magcms/prosopopee/prosopopee.py

716 lines
28 KiB
Python
Raw Normal View History

2015-12-03 06:09:29 +01:00
#!/usr/bin/env python
2017-05-05 16:52:12 +02:00
"""Prosopopee. Static site generator for your story.
Usage:
prosopopee.py
prosopopee.py test
2017-05-05 16:52:12 +02:00
prosopopee.py preview
prosopopee.py deploy
prosopopee.py (-h | --help)
prosopopee.py --version
Options:
-h --help Show this screen.
--version Show version.
"""
2015-12-03 06:09:29 +01:00
import os
2015-12-08 09:28:54 +01:00
import shutil
2017-07-03 13:37:38 +02:00
import socketserver
import subprocess
2017-07-03 13:37:38 +02:00
import http.server
2017-05-05 16:52:12 +02:00
2017-07-03 13:37:38 +02:00
import ruamel.yaml as yaml
from docopt import docopt
2015-12-08 07:04:07 +01:00
2016-11-01 10:47:29 +01:00
from path import Path
from jinja2 import Environment, FileSystemLoader
2016-02-18 06:43:28 +01:00
from .cache import CACHE
2017-10-04 00:44:47 +02:00
from .utils import error, warning, okgreen, makeform, encrypt
2016-02-18 06:43:28 +01:00
2016-05-12 02:24:26 +02:00
DEFAULTS = {
"rss": True,
"share": False,
"settings": {},
"show_date": True,
"test": False,
}
SETTINGS = {
"gm": {
"quality": 75,
"auto-orient": True,
"strip": True,
"resize": None,
"progressive": True
2016-04-29 12:40:34 +02:00
},
"ffmpeg": {
2016-05-03 09:41:08 +02:00
"binary": "ffmpeg",
"loglevel": "error",
2016-04-29 12:40:34 +02:00
"format": "webm",
"resolution": "1280x720",
2016-05-19 10:27:19 +02:00
"vbitrate": "3900k",
"abitrate": "100k",
"audio": "libvorbis",
"video": "libvpx",
2017-04-25 16:24:41 +02:00
"other": "-qmin 10 -qmax 42 -maxrate 500k -bufsize 1500k",
"extension": "webm"
2017-03-03 17:13:49 +01:00
},
"ffmpeg_audio": {
"binary": "ffmpeg",
"loglevel": "error",
2017-04-25 16:24:41 +02:00
"audio": "libmp3lame",
"extension": "mp3"
}
}
2016-04-29 12:40:34 +02:00
class Video(object):
2016-11-01 10:47:29 +01:00
base_dir = Path()
target_dir = Path()
2016-04-29 12:40:34 +02:00
def __init__(self, options):
2016-05-12 02:30:49 +02:00
error(SETTINGS["ffmpeg"] is not False, "I couldn't find a binary to convert video and I ask to do so, abort")
2016-04-29 12:40:34 +02:00
# assuming string
if not isinstance(options, dict):
2016-05-06 09:37:24 +02:00
options = {"name": options}
2016-04-29 15:55:14 +02:00
# used for caching, if it's modified -> regenerate
self.options = SETTINGS["ffmpeg"].copy()
2016-04-29 12:40:34 +02:00
self.options.update(options)
2016-04-29 15:55:14 +02:00
2016-04-29 12:40:34 +02:00
@property
def name(self):
return self.options["name"]
def ffmpeg(self, source, target, options):
2017-04-25 16:24:41 +02:00
if options.get("resize"):
target = target
else:
target = target + "." + options["extension"]
2016-05-04 09:39:35 +02:00
if not CACHE.needs_to_be_generated(source, target, options):
2016-04-29 12:40:34 +02:00
okgreen("Skipped", source + " is already generated")
2016-05-04 09:39:35 +02:00
return
ffmpeg_switches = {
2017-07-03 13:37:38 +02:00
"source": source,
"target": target,
"loglevel": "-loglevel %s" % options["loglevel"],
"resolution": "-s %s" % options["resolution"],
"resize": "-vf scale=-1:%s" % options.get("resize"),
"vbitrate": "-b:v %s" % options["vbitrate"],
"abitrate": "-b:v %s" % options["abitrate"],
"format": "-f %s" % options["format"],
"binary": "%s" % options["binary"],
"video": "-c:v %s" % options["video"],
"audio": "-c:a %s" % options["audio"],
"other": "%s" % options["other"]
2016-05-04 09:40:12 +02:00
}
2016-05-04 09:39:50 +02:00
2016-05-04 09:39:35 +02:00
warning("Generation", source)
2016-05-04 09:39:50 +02:00
2016-05-04 09:39:35 +02:00
if options.get("resize"):
command = "{binary} {loglevel} -i {source} {resize} -vframes 1 -y {target}".format(**ffmpeg_switches)
2016-05-20 08:47:02 +02:00
print(command)
2016-05-12 03:11:38 +02:00
error(os.system(command) == 0, "%s command failed" % ffmpeg_switches["binary"])
2016-05-04 09:39:35 +02:00
else:
2017-03-15 22:00:49 +01:00
command = "{binary} {loglevel} -i {source} {video} {vbitrate} {other} {audio} {abitrate} {resolution} {format} -y {target}".format(**ffmpeg_switches)
2016-05-04 09:41:22 +02:00
print(command)
2016-05-12 03:11:38 +02:00
error(os.system(command) == 0, "%s command failed" % ffmpeg_switches["binary"])
2016-05-04 09:39:50 +02:00
2016-05-04 09:39:35 +02:00
CACHE.cache_picture(source, target, options)
2016-04-29 15:55:14 +02:00
2016-04-29 12:40:34 +02:00
def copy(self):
if not DEFAULTS['test']:
source, target = self.base_dir.joinpath(self.name), self.target_dir.joinpath(self.name)
options = self.options.copy()
self.ffmpeg(source, target, options)
2016-04-29 12:40:34 +02:00
return ""
def generate_thumbnail(self, gm_geometry):
2016-11-02 10:07:05 +01:00
thumbnail_name = ".".join(self.name.split(".")[:-1]) + "-%s.jpg" % gm_geometry
if not DEFAULTS['test']:
source, target = self.base_dir.joinpath(self.name), self.target_dir.joinpath(thumbnail_name)
2016-05-04 09:42:42 +02:00
options = self.options.copy()
options.update({"resize": gm_geometry})
2016-05-04 09:42:42 +02:00
self.ffmpeg(source, target, options)
2016-05-04 09:42:42 +02:00
2016-04-29 12:40:34 +02:00
return thumbnail_name
2016-04-29 15:55:14 +02:00
@property
def ratio(self):
if self.options["binary"] == "ffmpeg":
binary = "ffprobe"
else:
binary = "avprobe"
command = binary + " -v error -select_streams v:0 -show_entries stream=width,height -of csv=p=0 " + self.base_dir.joinpath(self.name)
out = subprocess.check_output(command.split())
2019-09-25 19:36:21 +02:00
width,height = out.decode("utf-8").split(',')
return float(width) / int(height)
2016-04-29 12:40:34 +02:00
def __repr__(self):
return self.name
2017-03-15 21:57:13 +01:00
2017-03-03 17:13:49 +01:00
class Audio(object):
base_dir = Path()
target_dir = Path()
def __init__(self, options):
error(SETTINGS["ffmpeg"] is not False, "I couldn't find a binary to convert audio and I ask to do so, abort")
# assuming string
if not isinstance(options, dict):
options = {"name": options}
# used for caching, if it's modified -> regenerate
self.options = SETTINGS["ffmpeg_audio"].copy()
self.options.update(options)
@property
def name(self):
return self.options["name"]
def ffmpeg(self, source, target, options):
2017-04-25 16:24:41 +02:00
target = target + "." + options["extension"]
2017-03-03 17:13:49 +01:00
if not CACHE.needs_to_be_generated(source, target, options):
okgreen("Skipped", source + " is already generated")
return
ffmpeg_switches = {
2017-07-03 13:37:38 +02:00
"source": source,
"target": target,
"binary": "%s" % options["binary"],
"loglevel": "-loglevel %s" % options["loglevel"],
"audio": "-c:a %s" % options["audio"]
2017-03-03 17:13:49 +01:00
}
warning("Generation", source)
2017-04-25 16:24:41 +02:00
2017-04-23 16:04:56 +02:00
command = "{binary} {loglevel} -i {source} {audio} -y {target}".format(**ffmpeg_switches)
2017-03-03 17:13:49 +01:00
print(command)
error(os.system(command) == 0, "%s command failed" % ffmpeg_switches["binary"])
CACHE.cache_picture(source, target, options)
def copy(self):
if not DEFAULTS['test']:
source, target = self.base_dir.joinpath(self.name), self.target_dir.joinpath(self.name)
options = self.options.copy()
self.ffmpeg(source, target, options)
2017-03-03 17:13:49 +01:00
return ""
def __repr__(self):
return self.name
2016-04-29 12:40:34 +02:00
2017-03-15 21:57:13 +01:00
class Image(object):
base_dir = ""
target_dir = ""
2015-12-11 09:22:36 +01:00
def __init__(self, options):
# assuming string
if not isinstance(options, dict):
options = {"name": options}
2016-05-04 11:01:02 +02:00
self.options = SETTINGS["gm"].copy() # used for caching, if it's modified -> regenerate
self.options.update(options)
@property
def name(self):
2016-02-18 06:40:56 +01:00
return self.options["name"]
def gm(self, source, target, options):
2016-05-04 09:56:22 +02:00
if not CACHE.needs_to_be_generated(source, target, options):
okgreen("Skipped", source + " is already generated")
2016-05-04 10:12:18 +02:00
return
2016-05-04 09:56:22 +02:00
gm_switches = {
2017-07-03 13:37:38 +02:00
"source": source,
"target": target,
"auto-orient": "-auto-orient" if options["auto-orient"] else "",
"strip": "-strip" if options["strip"] else "",
"quality": "-quality %s" % options["quality"] if "quality" in options else "-define jpeg:preserve-settings",
"resize": "-resize %s" % options["resize"] if options.get("resize", None) is not None else "",
"progressive": "-interlace Line" if options.get("progressive", None) is True else ""
2016-05-04 09:56:38 +02:00
}
if not DEFAULTS['test']:
command = "gm convert '{source}' {auto-orient} {strip} {progressive} {quality} {resize} '{target}'".format(**gm_switches)
warning("Generation", source)
2016-05-04 09:56:49 +02:00
print(command)
error(os.system(command) == 0, "gm command failed")
2016-05-04 09:56:49 +02:00
CACHE.cache_picture(source, target, options)
2016-05-04 09:56:22 +02:00
def copy(self):
2016-11-01 10:47:29 +01:00
source, target = self.base_dir.joinpath(self.name), self.target_dir.joinpath(self.name)
2015-12-11 09:13:52 +01:00
# 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):
2016-04-29 15:55:14 +02:00
# print "Skipped %s since the file hasn't been modified based on file size" % source
# return ""
if not DEFAULTS['test']:
options = self.options.copy()
if not options["auto-orient"] and not options["strip"]:
shutil.copyfile(source, target)
print(("%s%s%s" % (source, "->", target)))
else:
# Do not consider quality settings here, since we aim to copy the input image
# better to preserve input encoding setting
del options["quality"]
self.gm(source, target, options)
2016-05-04 09:55:19 +02:00
return ""
def generate_thumbnail(self, gm_geometry):
2016-05-11 18:02:18 +02:00
thumbnail_name = ".".join(self.name.split(".")[:-1]) + "-" + gm_geometry + "." + self.name.split(".")[-1]
if not DEFAULTS['test']:
source, target = self.base_dir.joinpath(self.name), self.target_dir.joinpath(thumbnail_name)
2016-05-04 09:57:56 +02:00
options = self.options.copy()
options.update({"resize": gm_geometry})
2016-05-04 09:57:56 +02:00
self.gm(source, target, options)
2016-05-04 09:57:56 +02:00
return thumbnail_name
@property
def ratio(self):
command = "gm identify -format %w,%h " + self.base_dir.joinpath(self.name)
out = subprocess.check_output(command.split())
2019-09-25 19:36:21 +02:00
width,height = out.decode("utf-8").split(',')
return float(width) / int(height)
def __repr__(self):
return self.name
2017-07-18 13:43:27 +02:00
class TCPServerV4(socketserver.TCPServer):
allow_reuse_address = True
2017-03-15 21:57:13 +01:00
2016-11-01 09:50:34 +01:00
def get_settings():
2016-11-01 10:47:29 +01:00
error(Path("settings.yaml").exists(), "I can't find a "
2016-05-19 10:27:19 +02:00
"settings.yaml in the current working directory")
2016-05-19 19:19:09 +02:00
2017-06-04 20:03:37 +02:00
try:
# Deprecated:
# settings = yaml.safe_load(open("settings.yaml", "r"))
yamli = yaml.YAML(typ='safe', pure=True)
settings = yamli.load(open("settings.yaml", "r"))
2017-07-03 13:37:38 +02:00
except yaml.YAMLError as exc:
2017-06-04 20:03:37 +02:00
if hasattr(exc, 'problem_mark'):
mark = exc.problem_mark
2017-07-03 13:37:38 +02:00
error(False, "There are something wrong in settings.yaml line %s" % (mark.line))
2017-06-04 20:03:37 +02:00
else:
2017-07-03 13:37:38 +02:00
error(False, "There are omething wrong in settings.yaml")
2016-05-19 10:27:19 +02:00
error(isinstance(settings, dict), "Your settings.yaml should be a dict")
2017-07-03 13:37:38 +02:00
for key, value in list(DEFAULTS.items()):
2016-05-19 10:27:19 +02:00
if key not in settings:
settings[key] = value
2017-07-03 13:37:38 +02:00
for key, value in list(SETTINGS.items()):
2017-04-25 16:24:41 +02:00
if key not in settings:
settings[key] = value
2016-05-03 10:05:49 +02:00
if settings["settings"].get("ffmpeg"):
SETTINGS["ffmpeg"].update(settings["settings"]["ffmpeg"])
2016-05-03 10:05:49 +02:00
conv_video = settings["settings"]["ffmpeg"]["binary"]
else:
conv_video = "ffmpeg"
error(os.system("which gm > /dev/null") == 0, "I can't locate the gm binary, "
"please install the 'graphicsmagick' package.\n")
2016-05-21 10:19:43 +02:00
if os.system("which " + conv_video + " > /dev/null") != 0:
if conv_video == "ffmpeg" and os.system("which avconv > /dev/null") == 0:
SETTINGS["ffmpeg"]["binary"] = "avconv"
2016-05-21 10:19:43 +02:00
warning("Video", "I couldn't locate ffmpeg but I could find avconv, "
"switching to avconv for video conversion")
else:
warning("Video", "I can't locate the " + conv_video + " binary, "
"please install the '" + conv_video + "' package.\n")
2016-05-11 13:31:42 +02:00
warning("Video", "I won't be able to encode video and I will stop if I encounter a video to convert")
SETTINGS["ffmpeg"] = False
2015-12-09 06:57:53 +01:00
error(settings.get("title"), "You need to specify a title in your main settings.yaml")
2016-04-18 19:45:10 +02:00
if (settings["rss"] or settings["share"]) and not settings.get("url"):
warning("warning", "If you want the rss and/or the social network share to work, "
2016-04-29 12:40:34 +02:00
"you need to specify the website url in root settings")
settings["rss"] = False
settings["share"] = False
2016-02-18 06:39:49 +01:00
if settings["settings"].get("gm"):
SETTINGS["gm"].update(settings["settings"]["gm"])
2016-11-01 10:58:53 +01:00
2016-05-19 19:19:09 +02:00
return settings
2016-02-18 06:39:49 +01:00
2016-05-30 21:57:37 +02:00
def get_gallery_templates(theme, gallery_path="", parent_templates=None):
2016-11-01 10:58:05 +01:00
theme_path = Path(__file__).parent.joinpath("themes", theme).exists()
2016-11-01 10:47:29 +01:00
# available_themes = theme, "', '".join(Path(__file__).parent.joinpath("themes").listdir())
themesdir = "".join(Path(__file__).parent.joinpath("themes"))
available_themes = theme, "', '".join(os.listdir(themesdir))
2015-12-08 07:11:55 +01:00
2016-11-01 10:58:05 +01:00
error(theme_path, "'%s' is not an existing theme, available themes are '%s'" % available_themes)
2015-12-08 07:34:55 +01:00
2016-11-01 10:58:05 +01:00
templates_dir = [
Path(".").joinpath("templates").realpath(),
Path(__file__).parent.joinpath("themes", theme, "templates")
]
2015-12-08 09:28:54 +01:00
2016-11-01 10:58:05 +01:00
if theme != "exposure":
templates_dir.append(Path(__file__).parent.joinpath("themes", "exposure", "templates"))
2016-04-18 19:40:48 +02:00
2016-11-01 10:58:05 +01:00
subgallery_templates = Environment(loader=FileSystemLoader(templates_dir), trim_blocks=True)
2016-11-01 10:47:29 +01:00
Path(".").joinpath("build", gallery_path, "static").rmtree_p()
2016-11-01 10:47:29 +01:00
if Path(".").joinpath("static").exists():
shutil.copytree(Path(".").joinpath("static"), Path(".").joinpath("build", gallery_path, "static"))
2016-11-01 10:58:53 +01:00
2016-05-30 21:57:37 +02:00
else:
shutil.copytree(
2016-11-01 10:47:29 +01:00
Path(__file__).parent.joinpath("themes", theme, "static"),
2016-11-01 10:58:53 +01:00
Path(".").joinpath("build", gallery_path, "static")
)
2016-05-30 21:57:37 +02:00
return subgallery_templates
2016-05-31 14:55:55 +02:00
def process_directory(gallery_name, settings, parent_templates, parent_gallery_path=False):
if parent_gallery_path:
2016-11-01 10:47:29 +01:00
gallery_path = parent_gallery_path.joinpath(gallery_name)
else:
gallery_path = gallery_name
2016-05-27 11:57:03 +02:00
2017-06-04 16:15:37 +02:00
try:
# DEPRECATED:
# gallery_settings = yaml.safe_load(open(Path(".").joinpath(gallery_path, "settings.yaml").abspath(), "r"))
yamli = yaml.YAML(typ='safe', pure=True)
gallery_settings = yamli.load(open(os.path.abspath(Path(".").joinpath(gallery_path, "settings.yaml")), "r"))
2017-07-03 13:37:38 +02:00
except yaml.YAMLError as exc:
2017-06-04 16:15:37 +02:00
if hasattr(exc, 'problem_mark'):
mark = exc.problem_mark
2017-07-03 13:37:38 +02:00
error(False, "There are something wrong in %s/settings.yaml line %s" % (gallery_path, mark.line))
2017-06-04 16:15:37 +02:00
else:
2017-07-03 13:37:38 +02:00
error(False, "There are something wrong in %s/settings.yaml" % (gallery_path))
error(isinstance(gallery_settings, dict), "Your %s should be a dict" % os.path.join(gallery_name, "settings.yaml"))
error(gallery_settings.get("title"), "You should specify a title in %s" % os.path.join(gallery_name, "settings.yaml"))
2016-02-23 05:57:46 +01:00
gallery_cover = {}
2016-02-23 05:57:46 +01:00
sub_galleries = [x for x in os.listdir(os.path.join(Path("."), gallery_path)) if os.path.exists(os.path.join(x, "settings.yaml"))]
os.path.join(Path("build"), gallery_path).makedirs_p()
if not gallery_settings.get("public", True):
build_gallery(settings, gallery_settings, gallery_path, parent_templates)
2016-02-19 17:39:17 +01:00
else:
gallery_cover = create_cover(gallery_name, gallery_settings, gallery_path)
2015-12-08 09:28:54 +01:00
2016-11-01 11:16:16 +01:00
if not sub_galleries:
build_gallery(settings, gallery_settings, gallery_path, parent_templates)
else:
2016-07-21 14:36:23 +02:00
error(gallery_settings.get("sections") is not False,
"The gallery in %s can't have both sections and subgalleries" % os.path.join(gallery_name, "settings.yaml"))
2015-12-08 07:34:55 +01:00
2016-07-21 14:15:50 +02:00
# Sub galleries found, create index with them instead of a gallery
theme = gallery_settings.get("theme", settings.get("theme", "exposure"))
2016-02-16 08:41:53 +01:00
subgallery_templates = get_gallery_templates(theme, gallery_path, parent_templates)
2016-05-21 09:51:52 +02:00
sub_page_galleries_cover = []
2016-05-04 10:04:50 +02:00
2016-07-21 14:15:50 +02:00
for subgallery in sub_galleries:
sub_page_galleries_cover.append(
2016-11-01 10:47:29 +01:00
process_directory(subgallery.name, settings, subgallery_templates, gallery_path)
)
2016-05-04 10:04:50 +02:00
# Changed for (subgal_section)
if not gallery_settings.get("sections"):
# Simple old way of creating separate "index pages" for subgalleries (for compatibility)
build_index(settings, sub_page_galleries_cover, subgallery_templates, gallery_path, sub_index=True, gallery_settings=gallery_settings)
else:
# Galeries now can have both sections and subgalleries. The subgalleries show up in the "subgal" type section!
build_gallery(settings, gallery_settings, gallery_path, parent_templates, galleries_cover=sub_page_galleries_cover);
# This is needed for rss xml generation
2016-05-23 19:37:37 +02:00
gallery_cover['sub_gallery'] = sub_page_galleries_cover
return gallery_cover
2015-12-08 07:11:55 +01:00
2015-12-08 08:41:02 +01:00
def create_cover(gallery_name, gallery_settings, gallery_path):
error(gallery_settings.get("title"), "Your gallery describe in %s need to have a "
"title" % os.path.join(gallery_name, "settings.yaml"))
2016-05-04 10:09:45 +02:00
error(gallery_settings.get("cover"), "You should specify a path to a cover picture "
"in %s" % os.path.join(gallery_name, "settings.yaml"))
2016-02-16 08:41:53 +01:00
if isinstance(gallery_settings["cover"], dict):
cover_image_path = Path(gallery_path).joinpath(gallery_settings["cover"]["name"])
cover_image_url = Path(gallery_name).joinpath(gallery_settings["cover"]["name"])
cover_image_type = gallery_settings["cover"]["type"]
else:
cover_image_path = Path(gallery_path).joinpath(gallery_settings["cover"])
cover_image_url = Path(gallery_name).joinpath(gallery_settings["cover"])
cover_image_type = "image"
2016-11-01 10:47:29 +01:00
error(cover_image_path.exists(), "File for %s cover image doesn't exist at "
"%s" % (gallery_name, cover_image_path))
gallery_cover = {
"title": gallery_settings["title"],
"link": gallery_name,
"sub_title": gallery_settings.get("sub_title", ""),
"date": gallery_settings.get("date", ""),
"tags_as_list": gallery_settings.get("tags_as_list", ""),
"ord": gallery_settings.get("ord", ""),
"tags": gallery_settings.get("tags", ""),
"cover_type": cover_image_type,
"cover": cover_image_url,
}
return gallery_cover
def build_gallery(settings, gallery_settings, gallery_path, template, galleries_cover=False, sub_index=False):
gallery_index_template = template.get_template("gallery-index.html")
page_template = template.get_template("page.html")
2016-04-18 19:40:48 +02:00
# Added because of: (subgal_section)
if galleries_cover:
reverse = gallery_settings.get('reverse', settings["settings"].get('reverse', False))
# Rem.: Galleries are sorted by their "ord" setting if that exists in their settings.yaml,
# then the date if exists, then the first letter of the "link" alphabetically as that is
# actually the directory name and should always exist. Earlier it crashed without date, but
# to our use cases (company website, more generic cms, etc) a date is not always necessary.
# Also it seemed like a bug anyways, because there is usually:
# {% if settings.show_date and gallery.date %}
# in the html templates so the templates seem to be prepared to now having date just here
# it crashed the original lambda if there was none!
if reverse:
galleries_cover = sorted([x for x in galleries_cover if x != {}], key=lambda x: x["ord"] if x["ord"] else (x["date"] if x["date"] else x["link"][0]))
else:
galleries_cover = reversed(sorted([x for x in galleries_cover if x != {}], key=lambda x: x["ord"] if x["ord"] else (x["date"] if x["date"] else x["link"][0])))
# this should probably be a factory
2016-11-01 10:47:29 +01:00
Image.base_dir = Path(".").joinpath(gallery_path)
Image.target_dir = Path(".").joinpath("build", gallery_path)
2016-05-27 11:57:03 +02:00
2016-11-01 10:47:29 +01:00
Video.base_dir = Path(".").joinpath(gallery_path)
Video.target_dir = Path(".").joinpath("build", gallery_path)
2016-05-27 11:57:03 +02:00
2017-03-03 17:13:49 +01:00
Audio.base_dir = Path(".").joinpath(gallery_path)
Audio.target_dir = Path(".").joinpath("build", gallery_path)
has_gotto = False;
gottolist = []
if gallery_settings.get("sections"):
for x in gallery_settings['sections']:
if x['type'] not in gallery_settings:
gallery_settings[x['type'] + '_enabled'] = True
if x['type'] == 'header':
if x['menuid']:
has_gotto = True
gottolist.append(x)
template_to_render = page_template if gallery_settings.get("static") else gallery_index_template
2016-05-27 11:57:03 +02:00
html = template_to_render.render(
settings=settings,
gallery=gallery_settings,
galleries=galleries_cover, # Can be False if there were no subgal sections (subgal_section branch)
sub_index=sub_index, # TODO: Back button not generated (subgal_section)
has_goto=has_gotto, # Needed for the navmenu
gotolist=gottolist, # Needed for the navmenu
Image=Image,
Video=Video,
2017-03-03 17:13:49 +01:00
Audio=Audio,
2016-11-04 14:37:46 +01:00
link=gallery_path,
name=gallery_path.split('/', 1)[-1]
).encode("Utf-8")
2017-09-29 04:48:37 +02:00
2017-07-03 13:37:38 +02:00
open(Path("build").joinpath(gallery_path, "index.html"), "wb").write(html)
2016-05-27 11:57:03 +02:00
2017-10-02 11:14:50 +02:00
if gallery_settings.get("password") or settings.get("password"):
password = gallery_settings.get("password", settings.get("password"))
2017-10-04 00:44:47 +02:00
html = encrypt(password, template, gallery_path, settings, gallery_settings)
2017-09-29 04:48:37 +02:00
2017-09-27 13:48:21 +02:00
open(Path("build").joinpath(gallery_path, "index.html"), "wb").write(html)
2016-11-01 11:33:27 +01:00
# XXX shouldn't this be a call to build_gallery?
# Build light mode gallery - TODO: I think does not work in most cases anymore...
if gallery_settings.get("light_mode", False) or (
2017-07-18 13:43:27 +02:00
settings["settings"].get("light_mode", False) and
gallery_settings.get("light_mode") is None
):
2016-11-01 11:27:19 +01:00
# Prepare light mode
2016-11-01 10:47:29 +01:00
Path("build").joinpath(gallery_path, "light").makedirs_p()
gallery_light_path = Path(gallery_path).joinpath("light")
light_templates = get_gallery_templates("light", gallery_light_path)
2016-05-27 11:57:03 +02:00
2016-11-01 10:47:29 +01:00
Image.base_dir = Path(".").joinpath(gallery_path)
Image.target_dir = Path(".").joinpath("build", gallery_path)
2016-05-27 11:57:03 +02:00
2016-11-01 10:47:29 +01:00
Video.base_dir = Path(".").joinpath(gallery_path)
Video.target_dir = Path(".").joinpath("build", gallery_path)
2016-05-27 11:57:03 +02:00
2017-03-06 10:17:27 +01:00
Audio.base_dir = Path(".").joinpath(gallery_path)
Audio.target_dir = Path(".").joinpath("build", gallery_path)
light_template_to_render = light_templates.get_template("gallery-index.html")
2016-05-27 11:57:03 +02:00
html = light_template_to_render.render(
settings=settings,
gallery=gallery_settings,
Image=Image,
Video=Video,
2017-03-06 10:17:27 +01:00
Audio=Audio,
2016-11-04 14:44:40 +01:00
link=gallery_light_path,
2016-11-04 14:43:29 +01:00
name=gallery_path.split('/', 1)[-1]
).encode("Utf-8")
2015-12-08 08:07:24 +01:00
2017-07-03 13:37:38 +02:00
open(Path("build").joinpath(gallery_light_path, "index.html"), "wb").write(html)
2017-10-02 11:14:50 +02:00
if gallery_settings.get("password") or settings.get("password"):
from_template = light_templates.get_template("form.html")
2017-10-04 00:44:47 +02:00
html = encrypt(password, light_templates, gallery_light_path, settings, gallery_settings)
2019-09-25 19:36:21 +02:00
2017-09-29 04:48:37 +02:00
open(Path("build").joinpath(gallery_light_path, "index.html"), "wb").write(html)
2017-03-15 21:57:13 +01:00
2017-06-03 13:23:56 +02:00
def build_index(settings, galleries_cover, templates, gallery_path='', sub_index=False, gallery_settings={}):
2016-05-20 22:26:24 +02:00
index_template = templates.get_template("index.html")
2017-07-18 13:43:27 +02:00
reverse = gallery_settings.get('reverse', settings["settings"].get('reverse', False))
2017-06-03 13:23:56 +02:00
if reverse:
galleries_cover = sorted([x for x in galleries_cover if x != {}], key=lambda x: x["ord"] if x["ord"] else (x["date"] if x["date"] else x["link"][0]))
2017-07-18 13:43:27 +02:00
else:
galleries_cover = reversed(sorted([x for x in galleries_cover if x != {}], key=lambda x: x["ord"] if x["ord"] else (x["date"] if x["date"] else x["link"][0])))
2015-12-08 06:55:01 +01:00
2016-02-16 08:49:03 +01:00
# this should probably be a factory
2016-11-01 10:47:29 +01:00
Image.base_dir = Path(".").joinpath(gallery_path)
Image.target_dir = Path(".").joinpath("build", gallery_path)
2016-05-11 17:59:16 +02:00
2016-11-01 10:47:29 +01:00
Video.base_dir = Path(".").joinpath(gallery_path)
Video.target_dir = Path(".").joinpath("build", gallery_path)
html = index_template.render(
settings=settings,
2016-05-21 09:51:52 +02:00
galleries=galleries_cover,
2016-11-01 15:04:37 +01:00
sub_index=sub_index,
2016-05-04 15:38:11 +02:00
Image=Image,
Video=Video
).encode("Utf-8")
2017-07-03 13:37:38 +02:00
open(Path("build").joinpath(gallery_path, "index.html"), "wb").write(html)
2017-10-02 11:14:50 +02:00
if settings.get("password"):
password = settings.get("password")
2017-10-04 00:44:47 +02:00
html = encrypt(password, templates, gallery_path, settings, None)
2017-10-02 11:14:50 +02:00
open(Path("build").joinpath(gallery_path, "index.html"), "wb").write(html)
2015-12-08 10:42:00 +01:00
2016-05-19 19:19:09 +02:00
def main():
2018-03-27 10:58:33 +02:00
arguments = docopt(__doc__, version='0.8.1')
2016-11-01 09:50:34 +01:00
settings = get_settings()
# In order to let the front page render as a gallery itself, we needed "gallery_settings", which will be
# the same YAML file as the settings yaml file for the first page! (subgal_section)
gallery_settings = settings #yaml.safe_load(open(Path(".").joinpath(gallery_path, "settings.yaml").abspath(), "r"))
2016-02-18 06:39:49 +01:00
2015-12-08 07:34:55 +01:00
front_page_galleries_cover = []
galleries_dirs = [x for x in os.listdir(Path(".")) if os.path.isfile(os.path.join(x, "settings.yaml"))]
2015-12-08 07:11:55 +01:00
2016-11-01 09:51:51 +01:00
error(galleries_dirs, "I can't find at least one directory with a settings.yaml in the current working "
2016-04-29 15:55:14 +02:00
"directory (NOT the settings.yaml in your current directory, but one INSIDE A "
"DIRECTORY in your current working directory), you don't have any gallery?")
if arguments['test']:
DEFAULTS['test'] = True
2015-12-08 07:34:55 +01:00
2017-05-05 16:52:12 +02:00
if arguments['preview']:
error(Path("build").exists(), "Please build the website before launch preview")
os.chdir('build')
2017-07-03 13:37:38 +02:00
handler = http.server.SimpleHTTPRequestHandler
2017-07-18 13:43:27 +02:00
httpd = TCPServerV4(("", 9000), handler)
2017-07-03 13:37:38 +02:00
print('Start server on http://localhost:9000')
2017-07-14 15:44:25 +02:00
try:
httpd.serve_forever()
except (KeyboardInterrupt, SystemExit):
2017-07-18 13:43:27 +02:00
print('\nShutdown server')
httpd.shutdown()
2017-07-14 15:44:25 +02:00
raise
2017-05-05 16:52:12 +02:00
if arguments['deploy']:
error(os.system("which rsync > /dev/null") == 0, "I can't locate the rsync, "
2017-07-18 13:43:27 +02:00
"please install the 'rsync' package.\n")
2017-05-05 16:52:12 +02:00
error(Path("build").exists(), "Please build the website before launch deployment")
2017-05-05 16:52:12 +02:00
r_dest = settings["settings"]["deploy"]["dest"]
if settings["settings"]["deploy"]["others"]:
r_others = settings["settings"]["deploy"]["others"]
else:
r_others = ''
2017-05-05 17:03:51 +02:00
if settings["settings"]["deploy"]["ssh"]:
r_username = settings["settings"]["deploy"]["username"]
r_hostname = settings["settings"]["deploy"]["hostname"]
r_cmd = "rsync -avz --progress %s build/* %s@%s:%s" % (r_others, r_username, r_hostname, r_dest)
else:
r_cmd = "rsync -avz --progress %s build/* %s" % (r_others, r_dest)
2017-05-05 16:52:12 +02:00
error(os.system(r_cmd) == 0, "deployment failed")
return
Path("build").makedirs_p()
theme = settings["settings"].get("theme", "exposure")
2016-05-30 21:57:37 +02:00
templates = get_gallery_templates(theme)
2016-05-23 19:37:37 +02:00
templates.add_extension('jinja2.ext.with_')
2016-02-23 05:57:46 +01:00
2017-07-03 13:37:38 +02:00
if Path("custom.js").exists():
shutil.copy(Path("custom.js"), Path(".").joinpath("build", "", "static", "js"))
settings["custom_js"] = True
if Path("custom.css").exists():
shutil.copy(Path("custom.css"), Path(".").joinpath("build", "", "static", "css"))
settings["custom_css"] = True
2016-11-01 09:51:51 +01:00
for gallery in galleries_dirs:
2016-05-31 14:55:55 +02:00
front_page_galleries_cover.append(process_directory(gallery, settings, templates))
2016-04-18 19:40:48 +02:00
if settings["rss"]:
feed_template = templates.get_template("feed.xml")
xml = feed_template.render(
settings=settings,
galleries=reversed(sorted([x for x in front_page_galleries_cover if x != {}], key=lambda x: x["ord"] if x["ord"] else (x["date"] if x["date"] else x["link"][0])))
2017-07-18 13:43:27 +02:00
).encode("Utf-8")
2017-07-03 13:37:38 +02:00
open(Path("build").joinpath("feed.xml"), "wb").write(xml)
# Changes for: (subgal_section)
#build_index(settings, front_page_galleries_cover, templates)
gallery_path='' # TODO: Is this sure? This is the main page now, I guess this value here for now!
build_gallery(settings, gallery_settings, gallery_path, templates, galleries_cover=front_page_galleries_cover)
2017-07-12 13:39:45 +02:00
CACHE.cache_dump()
2018-02-28 15:32:58 +01:00
if DEFAULTS['test'] == True:
2020-02-05 14:56:43 +01:00
okgreen("Success", "HTML file building without error")
2015-12-08 10:42:00 +01:00
2015-12-08 06:55:01 +01:00
if __name__ == '__main__':
main()
# vim: ts=8 et sw=4 sts=4