diff --git a/README.md b/README.md index e356b9a..e756f20 100644 --- a/README.md +++ b/README.md @@ -62,7 +62,7 @@ sub_title: it's a scary place, don't go there This settings.yaml will describe: * the title, subtitle and cover picture of your gallery that will be used on the homepage -* if your gallery is public +* if your gallery is public (if not, it will still be built but won't appear on the homepage) * the date of your gallery: this will be used on the homepage since **galleries are sorted anti chronologically** on it * the list of sections that will contains your gallery. A section will represent either one picture, a group of pictures or text. The different kind of sections will be explained in the next README section. diff --git a/example/build/first_gallery/index.html b/example/build/first_gallery/index.html index b52afd4..bbe7100 100644 --- a/example/build/first_gallery/index.html +++ b/example/build/first_gallery/index.html @@ -3,18 +3,20 @@ + - my first gallery | Example gallery + my first gallery · Example gallery +
@@ -28,6 +30,7 @@
+
@@ -43,15 +46,6 @@
- - -
- -
+
@@ -115,17 +124,19 @@
\ No newline at end of file diff --git a/example/build/index.html b/example/build/index.html index 691ec04..27a1605 100644 --- a/example/build/index.html +++ b/example/build/index.html @@ -2,6 +2,7 @@ + @@ -30,6 +31,8 @@ + + @@ -40,7 +43,7 @@

.

\ No newline at end of file diff --git a/example/build/static/css/style-page.css b/example/build/static/css/style-page.css index 11ff15e..fe019dc 100644 --- a/example/build/static/css/style-page.css +++ b/example/build/static/css/style-page.css @@ -12,7 +12,7 @@ body { } section { - margin-bottom: 64px; + margin-bottom: 80px; } a { @@ -51,7 +51,7 @@ a { text-transform: uppercase; font-size: 5.5vw; letter-spacing: 4px; - font-family: sans-serif; + font-family: 'montserrat', sans-serif; margin-left: 10%; margin-right: 10%; margin-bottom: 1px; @@ -61,30 +61,30 @@ a { font-weight: normal; font-style: italic; font-size: 2.2vw; - font-family: serif; + font-family: 'crimson', serif; margin-top: 1px; } .full-picture .datetime { text-transform: uppercase; - font-family: serif; + font-family: 'crimson', serif; letter-spacing: 2px; } .bordered-picture img { - height: 80%; - width: 80%; - margin-left: 10%; - margin-right: 10%; + height: 77%; + width: 77%; + margin-left: 11.5%; + margin-right: 11.5%; } .pictures-line { - min-width: 80%; - width: 80%; - margin-left: 10%; - margin-right: 10%; + min-width: 77%; + width: 77%; + margin-left: 11.5%; + margin-right: 11.5%; display: flex; - margin-bottom: 15px; + margin-bottom: 0.5em; } .pictures-line .picture img { @@ -93,22 +93,47 @@ a { } .pictures-line .separator { - min-width: 15px; + min-width: 0.5em; } .text { text-align: center; - font-size: 25px; - margin-left: 15%; - margin-right: 15%; + font-family: 'crimson', serif; + font-size: 1.6em; + line-height: 1.8em; + margin-left: 21%; + margin-right: 21%; + color: black; +} + +.paragraph { + text-align: left; + font-family: 'crimson', serif; + font-size: 1em; + margin-left: 21%; + margin-right: 21%; color: #333; } +.paragraph h2 { + font-family: 'montserrat', sans-serif; + font-weight: normal; + font-size: 2.5em; + text-transform: uppercase; + color: black; + line-height: 1.4em; +} + +.paragraph p { + line-height: 2em; + +} + footer { - margin-top: 7em; + margin-top: 6em; text-align: center; position: relative; - font-family: serif; + font-family: 'crimson', serif; font-size: 11px; color: #555; background-color: #EEE; @@ -154,7 +179,8 @@ footer { justify-content: center; text-align: center; text-transform: uppercase; - font-family: sans-serif; + font-family: 'montserrat', sans-serif; + font-weight: bold; } footer p { @@ -164,6 +190,6 @@ footer p { footer a { text-decoration: none; font-weight: 600; - font-family: sans-serif; + font-family: 'montserrat', sans-serif; color: #111; } diff --git a/example/build/static/css/style.css b/example/build/static/css/style.css index ff1b104..e08e151 100644 --- a/example/build/static/css/style.css +++ b/example/build/static/css/style.css @@ -1,6 +1,6 @@ body { color: #222; - font-family: sans-serif; + font-family: 'montserrat', sans-serif; background-color: #FBFBFB; margin: 0; } @@ -17,10 +17,11 @@ body { .galleries-line { width: 100%; height: 100%; + margin-bottom: -4px; /* YOLO */ } .covers-1 .gallery-square { - width: 47%; + width: 100%; height: 100%; margin: auto; padding-bottom: 47%; @@ -28,12 +29,12 @@ body { } .covers-2 .gallery-square { - width: 47%; + width: 50%; height: 100%; - float: left; - margin: 0 1.5% 3%; + margin: 0 0 0; padding-bottom: 47%; position: relative; + display: inline-block; } .covers-3 .gallery-square { @@ -110,7 +111,7 @@ body { color: #444; font-style: italic; font-weight: normal; - font-family: serif; + font-family: 'crimson', serif; margin-top: .5em; } @@ -131,13 +132,13 @@ body { font-style: italic; margin-top: 0; margin-bottom: .7em; - font-family: serif; + font-family: 'crimson', serif; font-weight: normal; } .gallery-datetime { margin-bottom: 1em; - font-family: serif; + font-family: 'crimson', serif; text-transform: uppercase; letter-spacing: 2px; font-size: 11px; @@ -147,7 +148,7 @@ footer { margin-top: 7em; text-align: center; position: relative; - font-family: serif; + font-family: 'crimson', serif; font-size: 11px; color: #555; background-color: #EEE; @@ -163,6 +164,6 @@ footer p { footer a { text-decoration: none; font-weight: 600; - font-family: sans-serif; + font-family: 'montserrat', sans-serif; color: #111; } diff --git a/prosopopee/prosopopee.py b/prosopopee/prosopopee.py index e9e9f93..d06889c 100644 --- a/prosopopee/prosopopee.py +++ b/prosopopee/prosopopee.py @@ -13,71 +13,100 @@ index_template = templates.get_template("index.html") gallery_index_template = templates.get_template("gallery-index.html") page_template = templates.get_template("page.html") +DEFAULT_GM_QUALITY = 75 + +CACHE_VERSION = 1 + + class Cache(object): cache_file_path = os.path.join(os.getcwd(), ".prosopopee_cache") - def __init__(self): + def __init__(self, json): + # fix: I need to keep a reference to json because for whatever reason + # modules are set to None during python shutdown thus totally breaking + # the __del__ call to save the cache + # This wonderfully stupid behavior has been fixed in 3.4 (which nobody uses) + self.json = json if os.path.exists(os.path.join(os.getcwd(), ".prosopopee_cache")): self.cache = json.load(open(self.cache_file_path, "r")) else: - self.cache = {} + self.cache = {"version": CACHE_VERSION} - def thumbnail_needs_to_be_generated(self, source, target): + if "version" not in self.cache or self.cache["version"] != CACHE_VERSION: + print "info: cache format as changed, prune cache" + self.cache = {"version": CACHE_VERSION} + + def thumbnail_needs_to_be_generated(self, source, target, image): if not os.path.exists(target): return True if target not in self.cache: return True - if self.cache[target] != os.path.getsize(source): + cached_thumbnail = self.cache[target] + + if cached_thumbnail["size"] != os.path.getsize(source) or cached_thumbnail["options"] != image.options: return True return False - def cache_thumbnail(self, source, target): - self.cache[target] = os.path.getsize(source) + def cache_thumbnail(self, source, target, image): + self.cache[target] = {"size": os.path.getsize(source), "options": image.options} def __del__(self): - json.dump(self.cache, open(self.cache_file_path, "w")) + self.json.dump(self.cache, open(self.cache_file_path, "w")) -CACHE = Cache() +CACHE = Cache(json=json) -class TemplateFunctions(): - def __init__(self, base_dir, target_dir, has_gm): - self.base_dir = base_dir - self.target_dir = target_dir - def copy_image(self, image): - source, target = os.path.join(self.base_dir, image), os.path.join(self.target_dir, image) +class Image(object): + base_dir = "" + target_dir = "" + + def __init__(self, options): + # assuming string + if not isinstance(options, dict): + name = options + options = {"name": options} + + self.name = name + self.quality = options.get("quality", DEFAULT_GM_QUALITY) + self.options = options.copy() # used for caching, if it's modified -> regenerate + del self.options["name"] + + def copy(self): + source, target = os.path.join(self.base_dir, self.name), os.path.join(self.target_dir, self.name) # XXX doing this DOESN'T improve perf at all (or something like 0.1%) # if os.path.exists(target) and os.path.getsize(source) == os.path.getsize(target): # print "Skiped %s since the file hasn't been modified based on file size" % source # return "" - shutil.copyfile(source, target) + print source, "->", target return "" - def generate_thumbnail(self, image, gm_geometry): - thumbnail_name = image.split(".") + def generate_thumbnail(self, gm_geometry): + thumbnail_name = self.name.split(".") thumbnail_name[-2] += "-small" thumbnail_name = ".".join(thumbnail_name) - source, target = os.path.join(self.base_dir, image), os.path.join(self.target_dir, thumbnail_name) + source, target = os.path.join(self.base_dir, self.name), os.path.join(self.target_dir, thumbnail_name) - if CACHE.thumbnail_needs_to_be_generated(source, target): - command = "gm convert %s -resize %s %s" % (source, gm_geometry, target) + if CACHE.thumbnail_needs_to_be_generated(source, target, self): + command = "gm convert %s -resize %s -quality %s %s" % (source, gm_geometry, self.quality, target) print command os.system(command) - - CACHE.cache_thumbnail(source, target) + CACHE.cache_thumbnail(source, target, self) else: - print "skiped %s since it's already generated (based on source unchanged size)" % target + print "skiped %s since it's already generated (based on source unchanged size and images options set in your gallery's settings.yaml)" % target return thumbnail_name + def __repr__(self): + return self.name + def error(test, error_message): if test: @@ -90,10 +119,9 @@ def error(test, error_message): def main(): - has_gm = True if os.system("which gm > /dev/null") != 0: - has_gm = False - sys.stderr.write("WARNING: I can't locate the 'gm' binary, I won't be able to resize images.\n") + sys.stderr.write("ERROR: I can't locate the 'gm' binary, I won't be able to resize images, please install the 'graphicsmagick' package.\n") + sys.exit(1) error(os.path.exists(os.path.join(os.getcwd(), "settings.yaml")), "I can't find a settings.yaml in the current working directory") @@ -143,7 +171,11 @@ def main(): if not os.path.exists(os.path.join("build", gallery)): os.makedirs(os.path.join("build", gallery)) - open(os.path.join("build", gallery, "index.html"), "w").write(gallery_index_template.render(settings=settings, gallery=gallery_settings, helpers=TemplateFunctions(os.path.join(os.getcwd(), gallery), os.path.join(os.getcwd(), "build", gallery), has_gm=has_gm)).encode("Utf-8")) + # this should probably be a factory + Image.base_dir = os.path.join(os.getcwd(), gallery) + Image.target_dir = os.path.join(os.getcwd(), "build", gallery) + + open(os.path.join("build", gallery, "index.html"), "w").write(gallery_index_template.render(settings=settings, gallery=gallery_settings, Image=Image).encode("Utf-8")) front_page_galleries_cover = reversed(sorted(front_page_galleries_cover, key=lambda x: x["date"])) @@ -154,7 +186,11 @@ def main(): error(os.path.exists(os.path.join(os.getcwd(), item_file+".yaml")), "I can't find a "+item_file+".yaml in the current working directory") open(os.path.join("build", item_file+".html"), "w").write(page_template.render(settings=settings, pages=yaml.safe_load(open(item_file+".yaml", "r")), galleries=front_page_galleries_cover, helpers=TemplateFunctions(os.getcwd(), os.path.join(os.getcwd(), "build"), has_gm=has_gm)).encode("Utf-8")) - open(os.path.join("build", "index.html"), "w").write(index_template.render(settings=settings, galleries=front_page_galleries_cover, helpers=TemplateFunctions(os.getcwd(), os.path.join(os.getcwd(), "build"), has_gm=has_gm)).encode("Utf-8")) + Image.base_dir = os.getcwd() + Image.target_dir = os.path.join(os.getcwd(), "build") + + open(os.path.join("build", "index.html"), "w").write(index_template.render(settings=settings, galleries=front_page_galleries_cover, Image=Image).encode("Utf-8")) + if __name__ == '__main__': diff --git a/prosopopee/templates/gallery-index.html b/prosopopee/templates/gallery-index.html index 902ffc9..1902c60 100644 --- a/prosopopee/templates/gallery-index.html +++ b/prosopopee/templates/gallery-index.html @@ -43,7 +43,7 @@ }); diff --git a/prosopopee/templates/index.html b/prosopopee/templates/index.html index ef7d3ee..5d13d7f 100644 --- a/prosopopee/templates/index.html +++ b/prosopopee/templates/index.html @@ -35,7 +35,9 @@ {% if gallery.date %}{% endif %} - + {% set cover = Image(gallery.cover) %} + {{ cover.copy() }} + {% endfor %} diff --git a/prosopopee/templates/sections/bordered-picture.html b/prosopopee/templates/sections/bordered-picture.html index 65eb4ec..294c454 100644 --- a/prosopopee/templates/sections/bordered-picture.html +++ b/prosopopee/templates/sections/bordered-picture.html @@ -1,6 +1,7 @@ -{{ helpers.copy_image(section.image) }} +{% set image = Image(section.image) %} +{{ image.copy()}}
- - + +
diff --git a/prosopopee/templates/sections/full-picture.html b/prosopopee/templates/sections/full-picture.html index 527512e..48eb774 100644 --- a/prosopopee/templates/sections/full-picture.html +++ b/prosopopee/templates/sections/full-picture.html @@ -1,5 +1,6 @@ -{{ helpers.copy_image(section.image) }} -
+{% set image = Image(section.image) %} +{{ image.copy() }} +
{% if section.text %}
diff --git a/prosopopee/templates/sections/panorama.html b/prosopopee/templates/sections/panorama.html index 3d260a3..a9e2767 100644 --- a/prosopopee/templates/sections/panorama.html +++ b/prosopopee/templates/sections/panorama.html @@ -1,4 +1,5 @@ -{{ helpers.copy_image(section.image) }} +{% set image = Image(section.image) %} +{{ image.copy() }}
- +
diff --git a/prosopopee/templates/sections/pictures-group.html b/prosopopee/templates/sections/pictures-group.html index 02c8f85..bc9a282 100644 --- a/prosopopee/templates/sections/pictures-group.html +++ b/prosopopee/templates/sections/pictures-group.html @@ -2,10 +2,11 @@ {% for line in section.images %}
{% for image in line %} - {{ helpers.copy_image(image) }} + {% set image = Image(image) %} + {{ image.copy() }} {% if not loop.last %}