lazygal-0.9.1/0000755000175000017500000000000013012772633013114 5ustar niolniol00000000000000lazygal-0.9.1/setup.py0000755000175000017500000002334113012770762014635 0ustar niolniol00000000000000#!/usr/bin/env python3 # -*- coding: UTF-8 -*- # Lazygal, a lazy static web gallery generator. # Copyright (C) 2007-2012 Michal Čihař, Mickaël Royer, Alexandre Rossi # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. from distutils.core import setup, Command import distutils.sysconfig import distutils.command.build_scripts import distutils.command.build from distutils.dep_util import newer from distutils.spawn import find_executable import re import os import sys import glob import lazygal from stat import ST_MODE class test_lazygal(Command): user_options = [] def initialize_options(self): pass def finalize_options(self): pass def run(self): import lazygaltest lazygaltest.run() class build_manpages(Command): user_options = [] manpages = None db2mans = [ # debian "/usr/share/sgml/docbook/stylesheet/xsl/nwalsh/manpages/docbook.xsl", # gentoo "/usr/share/sgml/docbook/xsl-stylesheets/manpages/docbook.xsl", ] mandir = "./" executable = find_executable('xsltproc') def initialize_options(self): pass def finalize_options(self): self.manpages = glob.glob(os.path.join(self.mandir, "*.xml")) def __get_man_section(self, filename): # filename should be file.mansection.xml return filename.split('.')[-2] def run(self): data_files = self.distribution.data_files db2man = None for path in self.__class__.db2mans: if os.path.exists(path): db2man = path continue for xmlmanpage in self.manpages: manpage = xmlmanpage[:-4] # remove '.xml' at the end section = manpage[-1:] if newer(xmlmanpage, manpage): cmd = (self.executable, "--nonet", "-o", self.mandir, db2man, xmlmanpage) self.spawn(cmd) targetpath = os.path.join("share", "man", 'man%s' % section) data_files.append((targetpath, (manpage, ), )) class build_i18n_lazygal(Command): user_options = [] po_package = None po_directory = None po_files = None def initialize_options(self): pass def finalize_options(self): self.po_directory = "locale" self.po_package = "lazygal" self.po_files = glob.glob(os.path.join(self.po_directory, "*.po")) def run(self): data_files = self.distribution.data_files for po_file in self.po_files: lang = os.path.basename(po_file[:-3]) mo_dir = os.path.join("build", "mo", lang, "LC_MESSAGES") mo_file = os.path.join(mo_dir, "%s.mo" % self.po_package) if not os.path.exists(mo_dir): os.makedirs(mo_dir) cmd = ["msgfmt", po_file, "-o", mo_file] self.spawn(cmd) targetpath = os.path.join("share/locale", lang, "LC_MESSAGES") data_files.append((targetpath, (mo_file,))) class build_lazygal(distutils.command.build.build): def __has_manpages(self, command): has_db2man = False for path in build_manpages.db2mans: if os.path.exists(path): has_db2man = True return 'build_manpages' in self.distribution.cmdclass\ and has_db2man and build_manpages.executable is not None def __has_i18n(self, command): return 'build_i18n' in self.distribution.cmdclass def finalize_options(self): distutils.command.build.build.finalize_options(self) self.sub_commands.append(("build_i18n", self.__has_i18n)) self.sub_commands.append(("build_manpages", self.__has_manpages)) # check if Python is called on the first line with this expression first_line_re = re.compile('^#!.*python[0-9.]*([ \t].*)?$') class build_scripts_lazygal(distutils.command.build_scripts.build_scripts, object): """ This is mostly distutils copy, it just renames script according to platform (.py for Windows, without extension for others) """ def copy_scripts(self): """Copy each script listed in 'self.scripts'; if it's marked as a Python script in the Unix way (first line matches 'first_line_re', ie. starts with "\#!" and contains "python"), then adjust the first line to refer to the current Python interpreter as we copy. """ self.mkpath(self.build_dir) outfiles = [] for script in self.scripts: adjust = 0 script = distutils.util.convert_path(script) outfile = os.path.join(self.build_dir, os.path.splitext(os.path.basename(script))[0]) if sys.platform == 'win32': outfile += os.extsep + 'py' outfiles.append(outfile) if not self.force and not distutils.dep_util.newer(script, outfile): distutils.log.debug("not copying %s (up-to-date)", script) continue # Always open the file, but ignore failures in dry-run mode -- # that way, we'll get accurate feedback if we can read the # script. try: f = open(script, "r") except IOError: if not self.dry_run: raise f = None else: first_line = f.readline() if not first_line: self.warn("%s is an empty file (skipping)" % script) continue match = first_line_re.match(first_line) if match: adjust = 1 post_interp = match.group(1) or '' if adjust: distutils.log.info("copying and adjusting %s -> %s", script, self.build_dir) if not self.dry_run: outf = open(outfile, "w") if not distutils.sysconfig.python_build: outf.write("#!%s%s\n" % (os.path.normpath(sys.executable), post_interp)) else: outf.write( "#!%s%s\n" % (os.path.join( distutils.sysconfig.get_config_var("BINDIR"), "python" + distutils.sysconfig.get_config_var("EXE")), post_interp)) outf.writelines(f.readlines()) outf.close() if f: f.close() else: f.close() self.copy_file(script, outfile) if os.name == 'posix': for file in outfiles: if self.dry_run: distutils.log.info("changing mode of %s", file) else: oldmode = os.stat(file)[ST_MODE] & 0o7777 newmode = (oldmode | 0o555) & 0o7777 if newmode != oldmode: distutils.log.info("changing mode of %s from %o to %o", file, oldmode, newmode) os.chmod(file, newmode) # copy_scripts () # list themes to install theme_data = [] themes = glob.glob(os.path.join('themes', '*')) for theme in themes: themename = os.path.basename(theme) theme_data.append( (os.path.join('share', 'lazygal', 'themes', themename), glob.glob(os.path.join('themes', themename, '*')))) setup( name = 'lazygal', version = lazygal.__version__, description = 'Static web gallery generator', long_description = '', author = 'Alexandre Rossi', author_email = 'alexandre.rossi@gmail.com', maintainer = 'Alexandre Rossi', maintainer_email = 'alexandre.rossi@gmail.com', platforms = ['Linux', 'Mac OSX', 'Windows XP/2000/NT', 'Windows 95/98/ME'], keywords = ['gallery', 'exif', 'photo', 'image'], url = 'http://sousmonlit.zincube.net/~niol/playa/oss/projects/lazygal', download_url = 'http://sousmonlit.zincube.net/~niol/playa/oss/projects/lazygal', license = 'GPL', classifiers = [ 'Development Status :: 5 - Production/Stable', 'Environment :: Win32 (MS Windows)', 'Environment :: X11 Applications :: GTK', 'Intended Audience :: End Users/Desktop', 'License :: OSI Approved :: GNU General Public License (GPL)', 'Operating System :: Microsoft :: Windows :: Windows 95/98/2000', 'Operating System :: Microsoft :: Windows :: Windows NT/2000', 'Operating System :: POSIX', 'Operating System :: Unix', 'Programming Language :: Python', 'Topic :: Utilities', 'Natural Language :: English', ], packages = ['lazygal'], package_data = {'lazygal': ['defaults.json'], }, scripts = ['lazygal.py'], # Override certain command classes with our own ones cmdclass = { 'build' : build_lazygal, 'build_scripts' : build_scripts_lazygal, 'build_i18n' : build_i18n_lazygal, 'build_manpages': build_manpages, 'test' : test_lazygal, }, data_files = theme_data ) # vim: ts=4 sw=4 expandtab lazygal-0.9.1/lazygal.1.xml0000644000175000017500000007477013012770762015460 0ustar niolniol00000000000000 %lazygalent; August 2011"> Debian"> GNU"> GPL"> ]> 2010 &dhdate; LAZYGAL &dhsection; &dhpackage; &dhsectiontitle; &dhtitle; static web gallery generator &dhpackage; albumdir DESCRIPTION This manual page explains the &dhpackage; program. This program is a static web gallery generator written in Python. &dhpackage; works so: you should have an original store of files - possibly containg subdirectories (their names serving as headings if not using the album metadata feature). This is the source file hierarchy. It will never be modified by &dhpackage;. Then, when launching: $ lazygal -o /var/www/MyAlbum /home/user/SourceDir &dhpackage; will analyze the contents of the source hierarchy and will (re)create the target hierarchy, with all the bells and whistles defined by the templates. Only missing parts or parts that are not up to date will be generated. There is a limitation to this mechanism though: although updates in the source directory, in the metadata or in the themes are detected, changes in command line options and configuration files since last generation are not and the user should manually delete files that need to be generated again. OPTIONS These programs follow the usual &gnu; command line syntax, with long options starting with two dashes (`-'). A summary of options is included below. For a complete description, see the switch. Show program's version number and exit. Show summary of options. Don't output anything except for errors. Output everything that &dhpackage; is doing. Directory where web pages, slides and thumbs will be written (default is current directory). Theme name (looked up in theme directory) or theme full path. Default style to apply to the theme. Common variables to load all templates with, e.g. . For longer variable contents, it is easier to use a configuration file (see &lazygal-conf;). Force rebuild of web pages, regardless of the modification times of their dependencies. This is handy when changing a configuration option affecting these (theme, directory flattening, etc.). Clean destination directory of files that should not be there. Specify a file pattern (or name) which should be ignored during cleanup of the destination. May be specified more than once. Values given here will be in addition to those specified in configuration files. Specify a file pattern (or name) which should be ignored during processing. May be specified more than once. Values given here will be in addition to those specified in configuration files. Exhaustively go through all directories regardless of source modification time. Size of images, define as name=xxy, ..., eg. small=800x600,medium=1024x768. The special dimensions 0x0 use original size. Refer to the IMAGE RESIZE DESCRIPTION section for more information on the available syntax. Size of thumbnails, eg. 150x113. Refer to the IMAGE RESIZE DESCRIPTION section for more information on the available syntax. Quality of generated JPEG images (default is 85). Include original photos in output. Do not copy original photos in output directory, instead link them using RELATIVE_PATH as base for those links (discarded without ). Do not copy original photos in output directory, instead create symlinks to their original locations. This is useful when you plan transferring the whole directory which &dhpackage; generated to some other location, perhaps with rsync, and you wish to avoid creating an extra copy of each photo. This option is not available on Windows; if you try to use it on that operating system, &dhpackage; will immediately exit with an exit status of 1. Publication URL (only useful for feed generation). Generate metadata description files where they don't exist in the source tree instead of generating the web gallery. This disables all other options. Maximum number of thumbs per index page. This enables index pagination (0 is unlimited). If set, lazygal will only export the pictures that have one of their (IPTC) tags matching TAG. It is also possible to use an equivalent of AND and OR boolean tests to filter tags. For more details, read below the section TAG FILTERING. Sort order for images in a subgallery, among 'mtime', 'filename', 'numeric', or 'exif'. (default is 'exif' which is by EXIF date if EXIF data is available, filename otherwise, sorting EXIF-less images before). 'numeric' does a numeric sort on the numeric part of the filename. Add ':reverse' to reverse the sort order (e.g. ). Sort order for subgalleries, among 'exif' (EXIF date of the latest picture in sub-gallery), 'mtime', 'dirname', or 'numeric' (default is 'dirname'). 'numeric' does a numeric sort on the numeric part of the dirname. Add ':reverse' to reverse the sort order (e.g. ). Level below which the directory tree is flattened. Default is no flattening ('No'). This option makes the program include the web gallery index of child galleries in their parent's gallery index, if their level is greater than the supplied LEVEL. The level of the album root is 0. Index pages with multiple galleries (which happens when this section is used) show the pictures links in gallery sections. The following examples show the produced indexes for a sample album (2 sub-galleries, 1 sub-sub-gallery, 1 picture in each one of those). --dir-flattening-depth=No (default) index.html <- sub-gallery links subgal1/index.html <- index with img1 subgal1/img1.html subgal1/subsubgal1/index.html <- index with img2 subgal1/subsubgal1/img2.html subgal2/index.html <- index with img3 subgal2/img3.html --dir-flattening-depth=0 index.html <- contains index for all pics subgal1/img1.html subgal1/subsubgal1/img2.html subgal2/img3.html --dir-flattening-depth=1 index.html <- contains index for all pics subgal1/index.html <- index with img1 and img2 subgal1/img1.html subgal1/subsubgal1/img2.html subgal2/index.html <- index with img3 subgal2/img3.html Make a zip archive of original pictures for each directory. Webalbum picture background color. Default is transparent, and implies the PNG format. Any other value, e.g. red, white, blue, uses JPEG. What type of web album thumbnails to generate. By default, lazygal generates the well-loved "messy" thumbnails with randomly selected pictures from the album each rotated by a random amount and pasted together. This default can also be forced by specifying 'messy' as WEBALBUMPIC_TYPE. On the other hand, specifying 'tidy' as the value of this option forces lazygal to skip the rotations, resulting in more regularly shaped thumbnails which can also be more densely packed. This can be an advantage if not all users of your albums have huge screens :-) Do not remove GPS data from EXIF tags. By default the location tags are removed for privacy reasons. However, there are situations when having the location data makes sense and is desired. This is mostly meant to be used with holiday photos. THEMES A theme maps to a directory that contains the following items: theme/SHARED_* Files to put in the web gallery shared directory, e.g. CSS, Javascript, images or other resources common to all galleries. theme/browse.thtml The XHTML template for the theme browse page (displaying one picture). theme/dirindex.thtml or theme/dynindex.thtml The XHTML template for the directory index page (pictures and sub-galleries links). Depending on which index file is present, the theme will be: dirindex.thtml: fully static one HTML page per picture, per size and one index per size, or dynindex.thtml: dynamic only one index per directory is to be generated. theme/*.thtml must be valid XML. See http://genshi.edgewall.org/wiki/Documentation/xml-templates.html for syntax. Dependencies for statically included templates (i.e. with filenames not computed from variables) are automatically computed: when an included template is modified, the software will automatically figure out which pages to re-generate. Missing template files will be searched for in the default theme. theme/SHARED_* files (common resources for the shared directory) are renamed to strip the SHARED_ prefix and: Processed using the Genshi text template engine (see http://genshi.edgewall.org/wiki/Documentation/text-templates.html for syntax.) if their file extension starts with t, Copied to the web album destination otherwise. Using the theme manifest theme/manifest.json file, it is possible to include files from other directories to be copied into the web album shared files. manifest.json { "shared": [ # copy as shared/lib.js { "path": "../lib-2.1.js", "dest": "lib.js" }, # copy as shared/js/lib-2.1.js { "path": "../lib-2.1.js", "dest": "js/" } ] } Please refer to the examples supplied in /usr/share/lazygal/themes. ALBUM METADATA If a directory from the source album contains a file named album_description, it is processed as a source of album metadata. The format is borrowed from another album generating tool - Matew. Each line is treated as one possible tag, unknown lines are simply ignored. Example content of this file follows: album_description Album name "My album" Album description "Description, which can be very long." Album image identifier relative/path/to/image.jpg Otherwise, the user can provide metadata in the following files. SOURCE_DIR/album-name The title to use for this album directory. SOURCE_DIR/album-description The description for this album directory. HTML tags are used verbatim from this file. SOURCE_DIR/album-picture The relative path to the image to use at the top of the album picture stack. SOURCE_DIR/PICTURE_FILENAME.comment The description to use for this particular image. Please note that HTML tags are taken as provided in this file for output in the templates. Lazygal also extracts information from many metadata tags in image files. Regarding image description, Lazygal searches for comments in this order: pic.jpeg.comment file Exif.Photo.UserComment Exif.Image.ImageDescription Iptc.Application2.ObjectName JPEG comment FILES ~/.lazygal User configuration directory. ~/.lazygal/themes User themes directory. CONFIGURATION FILES Multiple configuration files are processed by &dhpackage;. The configuration is initially set up with the defaults. The defaults can be found in the &dhpackage; source distribution in lazygal/defaults.json. Then, the configuration files are processed in the following order, each newly defined value overloading formerly defined values. Finally, any command-line-provided parameter takes precedence on any configuration file value. ~/.lazygal/config User configuration file. See &lazygal-conf; for format. SOURCE_DIR/.lazygal Album root configuration file. See &lazygal-conf; for format. SOURCE_DIR/gal/.lazygal Web gallery configuration file. Only the webgal and template-vars sections are red in these files. The configuration applies to the gallery representing the directory of the configuration file, and all of its sub-directories, unless another configuration file in a sub-directory overloads some of the defined configuration values. See &lazygal-conf; for format. SIZE DESCRIPTION The size string follows the same syntax as ImageMagick's. scale% Height and width both scaled by specified percentage. xscale%yscale% Height and width individually scaled by specified percentages. width Width given, height automatically selected to preserve aspect ratio. xheight Height given, width automatically selected to preserve aspect ratio. widthxheight Maximum values of height and width given, aspect ratio preserved. widthxheight^ Minimum values of width and height given, aspect ratio preserved. widthxheight! Width and height emphatically given, original aspect ratio ignored. widthxheight> Change as per the supplied dimensions but only if an image dimension exceeds a specified dimension. widthxheight< Change dimensions only if both image dimensions exceed specified dimensions. pixels@ Resize image to have specified area in pixels. Aspect ratio is preserved. TAG FILTERING Tag filtering supports regular expression matching thanks to the 're' module of Python. All the filter matchings can be indicated to lazygal by successive uses of the 'filter-by-tag' option, or by giving a coma-separated list of keywords. We illustrate here how more elaorated tag filtering can be done. We want to export only the images that have the tags 'lazygal' AND 'hiking'. $ lazygal --filter-by-tag=lazygal --filter-by-tag=hiking or: $ lazygal --filter-by-tag=lazygal,hiking We want to export the images that have the tags 'lazygal' OR 'hiking'. $ lazygal --filter-by-tag="(lazygal|hiking)" We want to export the images that have one of the tags 'hiking_2012', 'hiking_2013', 'hiking_France', etc. $ lazygal --filter-by-tag="hiking_.*" We want to export the images that have the tag 'lazygal', AND one of the tags 'hiking_2012', 'hiking_2013', 'hiking_France', etc. $ lazygal --filter-by-tag="lazygal,hiking_.*" SEE ALSO &lazygal-conf;. More information is available on the program website: http://sousmonlit.zincube.net/~niol/playa/oss/projects/lazygal. AUTHOR This manual page was written for the &debian; system (but may be used by others). Permission is granted to copy, distribute and/or modify this document under the terms of the &gnu; General Public License, Version 2 any later version published by the Free Software Foundation. On Debian systems, the complete text of the GNU General Public License can be found in /usr/share/common-licenses/GPL. lazygal-0.9.1/lazygal.py0000755000175000017500000003143513012770762015143 0ustar niolniol00000000000000#!/usr/bin/env python3 # # Lazygal, a lazy static web gallery generator. # Copyright (C) 2007-2012 Alexandre Rossi # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. from __future__ import print_function import gettext import locale import logging import os import sys from optparse import OptionParser # i18n from lazygal import py2compat from lazygal import INSTALL_MODE, INSTALL_PREFIX if INSTALL_MODE == 'source': LOCALES_PATH = os.path.normpath(os.path.join(os.path.dirname(__file__), 'build', 'mo')) elif INSTALL_MODE == 'installed': LOCALES_PATH = os.path.join(INSTALL_PREFIX, 'share', 'locale') gettext.install('lazygal', LOCALES_PATH) locale.setlocale(locale.LC_ALL, '') import lazygal from lazygal.generators import Album import lazygal.config import lazygal.eyecandy import lazygal.log usage = _("usage: %prog [options] albumdir") parser = OptionParser(usage=usage) # The help option must be changed to comply with i18n. parser.get_option('-h').help = _("Show this help message and exit.") parser.add_option("", "--quiet", action="store_true", dest="quiet", help=_("Don't output anything except for errors.")) parser.add_option("", "--debug", action="store_true", dest="debug", help=_("Output everything that lazygal is doing.")) parser.add_option("-o", "--output-directory", action="store", type="string", dest="dest_dir", help=_("Directory where web pages, slides and thumbs will be written (default is current directory).")) parser.add_option("-t", "--theme", action="store", type="string", dest="theme", help=_("Theme name (looked up in theme directory) or theme full path.")) parser.add_option("", "--default-style", action="store", type="string", dest="default_style", help=_("Default style to apply to the theme.")) parser.add_option("", "--template-vars", action="store", type="string", dest="tpl_vars", help=_("Common variables to load all templates with.")) parser.add_option("-f", "--force-gen-pages", action="store_true", dest="force_gen_pages", help=_("Force rebuild of all pages.")) parser.add_option("", "--clean-destination", action="store_true", dest="clean_destination", help=_("Clean destination directory of files that should not be there.")) parser.add_option("", "--preserve", type="string", action="append", metavar=_('PATTERN'), dest="preserve", help=_("Specifies pathname(s) which will be ignored during final cleanup")) parser.add_option("-v", "--version", action="store_true", dest="show_version", help=_("Display program version.")) parser.add_option("", "--check-all-dirs", action="store_true", dest="check_all_dirs", help=_("Exhaustively go through all directories regardless of source modification time.")) parser.add_option("", "--dir-flattening-depth", action="store", type="int", dest="dir_flattening_depth", help=_("Level below which the directory tree is flattened. Default is 'No' which disables this feature.")) parser.add_option("-s", "--image-size", action="store", type="string", dest="image_size", help=_("Size of images, define as =SIZE,..., eg. small=800x600,medium=1024x768. The special value 0x0 uses original size. See manual page for SIZE syntax.")) parser.add_option("-T", "--thumbnail-size", action="store", type="string", dest="thumbnail_size", help=_("Size of thumbnails, define as SIZE, eg. 150x113. See manual page for SIZE syntax.")) parser.add_option("-q", "--quality", action="store", type="int", dest="quality", help=_("Quality of generated JPEG images (default is 85).")) parser.add_option("-O", "--original", action="store_true", dest="original", help=_("Include original photos in output.")) parser.add_option("", "--orig-base", action="store", type="string", dest="orig_base", help=_("Do not copy original photos in output directory, instead link them using submitted relative path as base.")) parser.add_option("", "--orig-symlink", action="store_true", dest="orig_symlink", help=_("Do not copy original photos in output directory, instead create symlinks to their original locations.")) parser.add_option("", "--puburl", action="store", type="string", dest="puburl", help=_("Publication URL (only useful for feed generation).")) parser.add_option("-m", "--generate-metadata", action="store_true", dest="metadata", help=_("Generate metadata description files where they don't exist instead of generating the web gallery.")) parser.add_option("-n", "--thumbs-per-page", action="store", type="int", dest="thumbs_per_page", help=_("Maximum number of thumbs per index page. This enables index pagination (0 is unlimited).")) parser.add_option("-z", "--make-dir-zip", action="store_true", dest="dirzip", help=_("Make a zip archive of original pictures for each directory.")) parser.add_option("", "--webalbum-pic-bg", action="store", type="string", dest="webalbumpic_bg", help=_("Webalbum picture background color. Default is transparent, and implies the PNG format. Any other value, e.g. red, white, blue, uses JPEG.")) parser.add_option("", "--webalbum-pic-type", action="store", type="choice", choices=list(lazygal.eyecandy.WEBALBUMPIC_TYPES.keys()), dest="webalbumpic_type", help=_("Webalbum picture type. Default is messy.")) parser.add_option("", "--pic-sort-by", action="store", metavar=_('ORDER'), dest="pic_sort_by", help=_("Sort order for images in a folder: filename, numeric, mtime, or exif. Add ':reverse' to reverse the chosen order.")) parser.add_option("", "--subgal-sort-by", action="store", metavar=_('ORDER'), dest="subgal_sort_by", help=_("Sort order for sub galleries in a folder: dirname, numeric, exif or mtime. Add ':reverse' to reverse the chosen order.")) parser.add_option("", "--filter-by-tag", type="string", action="append", metavar=_('TAG'), dest="filter_by_tag", help=_("Only include in the gallery pics whose IPTC keywords match the supplied filter(s).")) parser.add_option("", "--exclude", type="string", action="append", metavar=_('PATTERN'), dest="exclude", help=_("Regular expression pattern(s) describing directories or filenames to exclude from consideration.")) parser.add_option("", "--keep-gps-data", action="store_true", dest="keep_gps", help=_("Do not remove GPS location tags from EXIF metadata. Mostly useful with holiday photos.")) (options, args) = parser.parse_args() if options.show_version: print(_('lazygal version %s') % lazygal.__version__) sys.exit(0) if len(args) != 1: parser.print_help() sys.exit(_("Bad command line: wrong number of arguments.")) source_dir = py2compat.u(args[0], sys.getfilesystemencoding()) if not os.path.isdir(source_dir): print(_("Directory %s does not exist.") % source_dir) sys.exit(1) cmdline_config = lazygal.config.LazygalConfig() for section in cmdline_config.valid_sections: cmdline_config.add_section(section) if options.quiet: cmdline_config.set('runtime', 'quiet', True) if options.debug: cmdline_config.set('runtime', 'debug', True) if options.check_all_dirs: cmdline_config.set('runtime', 'check-all-dirs', True) if options.dest_dir is not None: cmdline_config.set('global', 'output-directory', py2compat.u(options.dest_dir, sys.getfilesystemencoding())) if options.force_gen_pages: cmdline_config.set('global', 'force-gen-pages', True) if options.clean_destination: cmdline_config.set('global', 'clean-destination', True) if options.preserve is not None: cmdline_config.set('global', 'preserve_args', options.preserve) if options.dir_flattening_depth is not None: cmdline_config.set('global', 'dir-flattening-depth', options.dir_flattening_depth) if options.puburl is not None: cmdline_config.set('global', 'puburl', options.puburl) if options.theme is not None: cmdline_config.set('global', 'theme', options.theme) if options.exclude is not None: cmdline_config.set('global', 'exclude_args', options.exclude) if options.default_style is not None: cmdline_config.set('webgal', 'default-style', options.default_style) if options.webalbumpic_bg is not None: cmdline_config.set('webgal', 'webalbumpic-bg', options.webalbumpic_bg) if options.webalbumpic_type is not None: cmdline_config.set('webgal', 'webalbumpic-type', options.webalbumpic_type) if options.image_size is not None: cmdline_config.set('webgal', 'image-size', options.image_size) if options.thumbnail_size is not None: cmdline_config.set('webgal', 'thumbnail-size', options.thumbnail_size) if options.thumbs_per_page is not None: cmdline_config.set('webgal', 'thumbs-per-page', options.thumbs_per_page) if options.pic_sort_by is not None: cmdline_config.set('webgal', 'sort-medias', options.pic_sort_by) if options.subgal_sort_by is not None: cmdline_config.set('webgal', 'sort-subgals', options.subgal_sort_by) if options.filter_by_tag is not None: cmdline_config.set('webgal', 'filter-by-tag', options.filter_by_tag) if options.original: cmdline_config.set('webgal', 'original', 'Yes') if options.orig_base is not None: cmdline_config.set('webgal', 'original-baseurl', options.orig_base) if options.orig_symlink: try: os.symlink except AttributeError: print(_("Option --orig-symlink is not available on this platform.")) sys.exit(1) else: cmdline_config.set('webgal', 'original-symlink', True) if options.dirzip: cmdline_config.set('webgal', 'dirzip', True) if options.quality is not None: cmdline_config.set('webgal', 'jpeg-quality', options.quality) if options.keep_gps: cmdline_config.set('webgal', 'keep-gps', True) if options.tpl_vars is not None: cmdline_config.add_section('template-vars') tpl_vars_defs = options.tpl_vars.split(',') for single_def in tpl_vars_defs: name, value = single_def.split('=') cmdline_config.set('template-vars', name, py2compat.u(value, sys.stdin.encoding)) logger = logging.getLogger() logger.setLevel(logging.INFO) output_log = lazygal.log.ProgressConsoleHandler() output_log.setFormatter(logging.Formatter('%(message)s')) logger.addHandler(output_log) try: album = Album(source_dir, cmdline_config) except ValueError as e: print(py2compat.u(e)) sys.exit(1) else: if sys.stdout.isatty(): progress = lazygal.generators.AlbumGenProgress(\ len(album.stats()['bydir'].keys()), album.stats()['total']) def update_progress(): output_log.update_progress(py2compat._str(progress)) progress.updated = update_progress progress.updated() else: progress = None if options.metadata: album.generate_default_metadata() else: try: album.generate(progress=progress) except KeyboardInterrupt: print(_("Interrupted."), file=sys.stderr) sys.exit(1) except ValueError as e: print(py2compat.u(e)) sys.exit(1) # vim: ts=4 sw=4 expandtab lazygal-0.9.1/devscripts/0000755000175000017500000000000013012772633015302 5ustar niolniol00000000000000lazygal-0.9.1/devscripts/update-po0000755000175000017500000000467513012770762017143 0ustar niolniol00000000000000#!/usr/bin/env python # Lazygal, a static web gallery generator. # Copyright (C) 2007-2010 Mickael Royer # Alexandre Rossi # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. import glob,os from distutils.dep_util import newer from distutils.spawn import spawn def update_translation(po_dir, po_package, po): # Update runtime translations os.chdir(po_dir) spawn(["intltool-update", "--dist", "--gettext-package", po_package, os.path.basename(po[:-3])]) def update_template(po_dir, po_package): os.chdir(po_dir) # We force here the python language for gettext strings extraction because # xgettext (which is called by intltool-update) reverts to C for # templates, as they do not have a .py extension, and this does not work # and translatable strings are not extracted. os.environ['XGETTEXT_ARGS'] = "-L Python" spawn(["intltool-update", "--pot", "--gettext-package", po_package]) def update_po(): po_package = "lazygal" po_dir = os.path.abspath("locale") pot_file = os.path.join(po_dir, po_package + ".pot") po_files = glob.glob(os.path.join(po_dir, "*.po")) infilename = os.path.join(po_dir, "POTFILES.in") with open(infilename, 'r') as f: infiles = f.read().splitlines() oldpath = os.getcwd() need_tpl_update = False if newer(infilename, pot_file): need_tpl_update = True else: for filename in infiles: if newer(filename, pot_file): need_tpl_update = True if need_tpl_update: update_template(po_dir, po_package) for po in po_files: update_translation(po_dir, po_package, po) os.chdir(oldpath) if __name__ == "__main__": update_po() # vim: ts=4 sw=4 expandtab lazygal-0.9.1/devscripts/copy-metadata0000755000175000017500000000365413012770762017771 0ustar niolniol00000000000000#!/usr/bin/env python # Lazygal, a static web gallery generator. # Copyright (C) 2011 Alexandre Rossi # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. import sys import os sys.path.append(os.path.join(os.path.dirname(__file__), '..')) from gi.repository import GExiv2 def copy_metadata(src, dst): source_image = GExiv2.Metadata(src) dest_image = GExiv2.Metadata(dst) # Save dimensions if 'Exif.Photo.PixelXDimension' in dest_image \ and 'Exif.Photo.PixelYDimension' in dest_image: dst_width = dest_image["Exif.Photo.PixelXDimension"] dst_height = dest_image["Exif.Photo.PixelYDimension"] has_dims = True else: has_dims = False for tag in source_image.get_exif_tags(): dest_image[tag] = source_image[tag] for tag in source_image.get_iptc_tags(): dest_image[tag] = source_image[tag] for tag in source_image.get_xmp_tags(): dest_image[tag] = source_image[tag] if has_dims: # set EXIF image size info to resized size dest_image["Exif.Photo.PixelXDimension"] = dst_width dest_image["Exif.Photo.PixelYDimension"] = dst_height dest_image.save_file() if __name__ == "__main__": copy_metadata(sys.argv[1], sys.argv[2]) # vim: ts=4 sw=4 expandtab lazygal-0.9.1/devscripts/update-changelog0000755000175000017500000000121513012770762020437 0ustar niolniol00000000000000#!/bin/bash # Small script to easily generate a ChangeLog from hg log. project=Lazygal HG=$(which hg) AWK=$(which awk) repo=$(dirname $0)/.. $HG log --template '{tags}|{date|shortdate}|{desc|firstline}\n' -R $repo |\ $AWK -F'|'\ '/^\|.*\|Added tag [0-9\_]+ for changeset / { next }\ /^\|/ { print " * " $3 }\ /^tip\|/ { print "\nLazygal ##DEVELOPMENT VERSION## (" $2 ")";\ print " * " $3\ } /^[0-9]/ { gsub(/\_/,".",$1);\ print "\nLazygal " $1 " (" $2 ")";\ print " * " $3\ }'\ > $repo/ChangeLog-full lazygal-0.9.1/themes/0000755000175000017500000000000013012772633014401 5ustar niolniol00000000000000lazygal-0.9.1/themes/nojs/0000755000175000017500000000000013012772633015352 5ustar niolniol00000000000000lazygal-0.9.1/themes/nojs/SHARED_sidebnw.css0000644000175000017500000000522213012770762020547 0ustar niolniol00000000000000@import url("basic.css"); body{ background: white; } a { color: black; } .title { display: none; } .title h1{ margin-top: .1em; } .inline_enum ul{ margin-left: 0; padding-left: 0; display: inline; } .inline_enum ul li { margin-left: 0; padding-left: 2px; border: none; list-style: none; display: inline; } #breadcrumbs { padding: 3px; margin-bottom: 25px; font-size: small; } #breadcrumbs ul li:after { content: "\0020 \0020 \0020 \00BB \0020"; } #breadcrumbs ul li.bc_current:after { content: " "; } #osize_links ul li:after { content: " |"; } #osize_links ul li:last-child:after { content: " "; } #onum_links ul li:after { content: " |"; } #onum_links ul li:last-child:after { content: " "; } #osize_links { font-size: small; text-align:center; margin: 1em; } #onum_links{ font-size: small; text-align:center; } div.subgal_link { float: left; padding: 1em; width: 50em; } div.subgal_image { float: left; margin-right: 2em; margin-left: 4em; width:180px; } div.subgal_image img { margin: 0; border: none; } div.subgal_description p{ text-align:justify; } .media_links{ padding: 2em; } img.media{ border: solid black 1px; margin: 1em; } .prevnext{ text-align: center; margin: 2em; font-size: x-small; } .prevnext a{ display: block; } #image{ margin-left: 5px; } #image_img { float: left; padding-right: 1em; max-width: 70%; padding-right: 1em; } #image img { height: auto; border: solid black 1px; max-width: 100%; } #image_caption { padding-left: 70%; font-size: x-small; } #image_caption .image_comment{ font-size: x-large; margin-bottom: 1em; } .image_caption_tech { display: none; } #lazygalfooter{ padding-top: 3em; clear: both; font-size: x-small; } @media only screen and (max-width: 700px){ body { margin: 0; padding: 0; } #osize_links { display: none; } #breadcrumbs { margin: 2px; padding: 0; } .prevnext { margin: 0.1em; } .prevnext img { vertical-align: middle; max-height: 10%; width: auto; } #image_caption .image_comment{ font-size: small; } #lazygalfooter{ padding: 1px; } } @media only screen and (max-width: 700px) and (orientation: portrait){ #image_caption { padding: 5px; } #image_img { float: none; max-width: 100%; } .prevnext img, .prevnext a { display: inline; } } /* * vim: ts=4 sw=4 expandtab */ lazygal-0.9.1/themes/nojs/image.thtml0000644000175000017500000000264113012770762017512 0ustar niolniol00000000000000
Image $image_name
$comment
${_('Taken')} ${image_datetime.strftime(_('on %d/%m/%Y at %H:%M'))}
${_('Author')} : $authorship
${_('Keywords')} : $keywords
  • $image_name
  • ${_('Camera:')} $camera_name ${_('with')} $lens_name
  • ${_('Exposure')} $exposure
  • ${_('Sensitivity ISO')} $iso
  • ${_('Aperture')} $fnumber
  • ${_('Flash')} $flash
  • ${_('Focal length')} $focal_length
lazygal-0.9.1/themes/nojs/video.thtml0000644000175000017500000000054113012770762017533 0ustar niolniol00000000000000

${_('Original video')}

lazygal-0.9.1/themes/nojs/SHARED_default.tcss0000644000175000017500000000355413012770762020732 0ustar niolniol00000000000000@import url("basic.css"); {% if bgcolor %} body{ background-color:${bgcolor}; } {% end %} {% if txtcolor %} body{ color:${txtcolor}; } {% end %} p{ text-align:center; } a{ {% if lnkcolor %} color:${lnkcolor}; {% end %} {% if not lnkcolor %} color:blue; {% end %} {% if lnkdecoration %} text-decoration:${lnkdecoration}; {% end %} {% if not lnkdecoration %} text-decoration:none; {% end %} } .media_links{ clear: both; padding-left:7em; padding-right:7em; } .prevnext_text { display: none; } #prev_link{ position:absolute; top:50%; left:0.1em; } #next_link{ position:absolute; top:50%; right:0.1em; } .inline_enum ul{ margin-left: 0; padding-left: 0; display: inline; } .inline_enum ul li { margin-left: 0; padding-left: 2px; border: none; list-style: none; display: inline; } #breadcrumbs { padding: 3px; margin-bottom: 25px; font-size: small; } #breadcrumbs ul li:after { content: "\0020 \0020 \0020 \00BB \0020"; } #breadcrumbs ul li.bc_current:after { content: " "; } #osize_links ul li:after { content: " |"; } #osize_links ul li:last-child:after { content: " "; } #onum_links ul li:after { content: " |"; } #onum_links ul li:last-child:after { content: " "; } img { border:solid black 1px; margin:1em; } #image_img img{ display: block; margin-left: auto; margin-right: auto; } img.subgal { border: none; } div.subgal_link { float: left; padding: 1em; width: 40em; } div.subgal_image { float: left; width: 280px; /* This is based on thumbnail size */ } div.subgal_image img { margin: 0; border: none; } #subgal_links li { margin: 0.5em; } .media_links p{ text-align:justify; } .footer { clear: both; } .footer p { text-align:justify; } /* * vim: ts=4 sw=4 expandtab */ lazygal-0.9.1/themes/nojs/SHARED_scripts.js0000644000175000017500000000116213012770762020426 0ustar niolniol00000000000000/** * Load page where link in given element id points. */ function gotopage(divid) { var div = $('#' + divid); if (div) { var link = div.children('a')[0]; if (link) { document.location = link; } } } $(document).keypress(function(e) { switch(e.keyCode) { case 37: /* Left */ gotopage('prev_link'); break; case 38: /* Up */ gotopage('index_link'); break; case 39: /* Right */ case 13: /* Enter */ case 32: /* Space */ gotopage('next_link'); break; } }); lazygal-0.9.1/themes/nojs/browse.thtml0000644000175000017500000000420113012770762017723 0ustar niolniol00000000000000