major rework of configration parameters.
This commit is contained in:
244
mirva/mirva.py
244
mirva/mirva.py
@@ -4,8 +4,11 @@ import sys
|
||||
import re
|
||||
import shutil
|
||||
import subprocess
|
||||
from argparse import ArgumentParser
|
||||
import random
|
||||
from argparse import ArgumentParser, HelpFormatter
|
||||
|
||||
from mirva import get_version
|
||||
from tqdm import tqdm
|
||||
|
||||
|
||||
class Mirva:
|
||||
@@ -22,23 +25,48 @@ class Mirva:
|
||||
".*\.jpg$|.*\.jpeg$|.*\.png$|.*\.gif$|.*\.tif$", re.I
|
||||
)
|
||||
self.video_match = re.compile(".*\.mp4$", re.I)
|
||||
self.site_defaults = {
|
||||
"title": {"default": "", "help": "Title of the site"},
|
||||
"sub_title": {
|
||||
"default": "",
|
||||
"help": "Subtitle of the site, shown under the title",
|
||||
},
|
||||
"intro": {
|
||||
"default": "",
|
||||
"help": "Intro text shown before first image",
|
||||
},
|
||||
"image_size": {
|
||||
"default": "1920",
|
||||
"help": "Resize images for faster loading. Use 'link' for symbolic links without resizing.",
|
||||
},
|
||||
"scroll": {
|
||||
"default": "smooth",
|
||||
"help": "Transition to next image with keyboard: smooth or auto",
|
||||
},
|
||||
}
|
||||
|
||||
## Init ##
|
||||
self.get_options()
|
||||
os.chdir(self.options.folder)
|
||||
self.write_resources()
|
||||
self.file_list = self.get_files()
|
||||
if self.options.config or not os.path.exists(self.config_file):
|
||||
self.create_config()
|
||||
print(
|
||||
"Config created: Exiting without gallery creation. Check config first."
|
||||
)
|
||||
return
|
||||
self.get_config()
|
||||
if self.options.exif:
|
||||
self.append_exif()
|
||||
self.create_posts()
|
||||
self.write_index()
|
||||
self.write_mediums()
|
||||
print("Gallery written.")
|
||||
|
||||
if self.run_commands["config"]:
|
||||
|
||||
self.write_resources()
|
||||
updated = self.create_config()
|
||||
if updated:
|
||||
print(
|
||||
"Config created or updated: Check config contents: {}".format(
|
||||
self.config_file
|
||||
)
|
||||
)
|
||||
|
||||
if self.run_commands["generator"]:
|
||||
self.get_config()
|
||||
self.create_posts()
|
||||
self.write_index()
|
||||
self.write_mediums()
|
||||
print("Gallery written.")
|
||||
|
||||
def create_config(self):
|
||||
|
||||
@@ -46,23 +74,48 @@ class Mirva:
|
||||
self.config.read(self.config_file)
|
||||
config_changed = False
|
||||
if not "SITE" in self.config:
|
||||
self.config["SITE"] = {
|
||||
"title": "",
|
||||
"sub_title": "",
|
||||
"intro": "",
|
||||
"image_size": 850,
|
||||
}
|
||||
self.config["SITE"] = {}
|
||||
config_changed = True
|
||||
|
||||
for key in self.site_defaults:
|
||||
if not key in self.config["SITE"]:
|
||||
config_changed = True
|
||||
self.config["SITE"][key] = self.site_defaults[key]["default"]
|
||||
|
||||
if self.options.set:
|
||||
for key, value in self.options.set:
|
||||
if key not in self.site_defaults:
|
||||
raise KeyError("Key '{}' is not a config keyword".format(key))
|
||||
self.config["SITE"][key] = value
|
||||
config_changed = True
|
||||
|
||||
for f in self.file_list:
|
||||
if not f in self.config:
|
||||
title, _ = os.path.splitext(f)
|
||||
title = title.replace("_", " ")
|
||||
self.config[f] = {"title": title, "description": ""}
|
||||
config_changed = True
|
||||
print("Added {}".format(f))
|
||||
|
||||
if self.options.purge:
|
||||
unnecessary = []
|
||||
for f in self.config:
|
||||
if f in ("SITE", "DEFAULT"):
|
||||
continue
|
||||
if f not in self.file_list:
|
||||
print("{} not found in files".format(f))
|
||||
unnecessary.append(f)
|
||||
for f in unnecessary:
|
||||
del self.config[f]
|
||||
config_changed = True
|
||||
|
||||
if self.options.exif:
|
||||
self.append_exif()
|
||||
config_changed = True
|
||||
|
||||
if config_changed:
|
||||
self.write_config()
|
||||
return config_changed
|
||||
|
||||
def create_posts(self):
|
||||
|
||||
@@ -93,7 +146,6 @@ class Mirva:
|
||||
self.config.write(fp)
|
||||
|
||||
def get_files(self):
|
||||
image_match = re.compile(".*\.jpg$|.*\.jpeg$|.*\.png$|.*\.gif$|.*\.tif$", re.I)
|
||||
files = []
|
||||
for f in sorted(os.listdir(".")):
|
||||
if f.startswith("."):
|
||||
@@ -104,24 +156,24 @@ class Mirva:
|
||||
return files
|
||||
|
||||
def get_options(self):
|
||||
parser = ArgumentParser(
|
||||
prog="mirva",
|
||||
epilog='Configuration note: item "image_size = [integer]" is the '
|
||||
+ "middle sized image max width/height in pixels. It also accepts a special "
|
||||
+ 'value "link" to make symbolic links.',
|
||||
)
|
||||
# parser.add_argument("-v", default=False, action="store_true")
|
||||
parser = ArgumentParser(prog="mirva", formatter_class=SmartFormatter)
|
||||
parser.add_argument(
|
||||
"--config",
|
||||
default=False,
|
||||
action="store_true",
|
||||
help="Write config and exit. Required if more images are added.",
|
||||
"--version",
|
||||
action="version",
|
||||
version="%(prog)s {version}".format(version=get_version()),
|
||||
)
|
||||
parser.add_argument(
|
||||
"--force",
|
||||
"--folder",
|
||||
type=str,
|
||||
default=".",
|
||||
help="Folder for gallery. Default current folder.",
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"--purge",
|
||||
default=False,
|
||||
action="store_true",
|
||||
help="Force regeneration of middle sized images",
|
||||
help="Remove non-existent files in image list. Required if images are removed.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--exif",
|
||||
@@ -130,20 +182,43 @@ class Mirva:
|
||||
help="Append EXIF information to image descriptions",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--version",
|
||||
action="version",
|
||||
version="%(prog)s {version}".format(version=get_version()),
|
||||
"--set",
|
||||
"-s",
|
||||
default=None,
|
||||
nargs=2,
|
||||
action="append",
|
||||
metavar=("key", "value"),
|
||||
help="smart|Configurable options: \n"
|
||||
+ "\n".join(
|
||||
["{}: {}".format(k, v["help"]) for k, v in self.site_defaults.items()]
|
||||
),
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"--force",
|
||||
default=False,
|
||||
action="store_true",
|
||||
help="Force regeneration of middle sized images",
|
||||
)
|
||||
parser.add_argument(
|
||||
"folder",
|
||||
type=str,
|
||||
default=".",
|
||||
nargs="?",
|
||||
help="Folder for gallery",
|
||||
"--command",
|
||||
"-c",
|
||||
default="all",
|
||||
action="store",
|
||||
choices=["all", "config", "generator"],
|
||||
help="Run only part of the process. Defaults to all. Config is run always if it doesn't exist.",
|
||||
)
|
||||
self.options = parser.parse_args()
|
||||
|
||||
def get_index(self, page_title, sub_title, intro, posts):
|
||||
self.options = parser.parse_args()
|
||||
self.run_commands = {
|
||||
"config": self.options.command == "config"
|
||||
or self.options.command == "all"
|
||||
or not os.path.exists(self.config_file),
|
||||
"generator": self.options.command == "generator"
|
||||
or self.options.command == "all",
|
||||
}
|
||||
|
||||
def get_index(self, posts):
|
||||
|
||||
return """<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<!--
|
||||
@@ -164,10 +239,10 @@ Released : 20110306
|
||||
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
|
||||
<link rel="shortcut icon" href="{resource}/mirva.ico"/>
|
||||
<title>{page_title}</title>
|
||||
<link href="{resource}/style.css" rel="stylesheet" type="text/css" media="screen" />
|
||||
<link href="{resource}/mirva.css" rel="stylesheet" type="text/css" media="screen" />
|
||||
<script src="{resource}/mirva.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<body data-scroll="{scroll}">
|
||||
<div id="wrapper">
|
||||
<div id="header">
|
||||
<div id="logo">
|
||||
@@ -183,7 +258,7 @@ Released : 20110306
|
||||
<div id="page-bgbtm">
|
||||
<div id="content">
|
||||
<div class="post">
|
||||
<div class="entry">
|
||||
<div class="entry intro">
|
||||
{intro}
|
||||
</div>
|
||||
</div>
|
||||
@@ -199,9 +274,10 @@ Released : 20110306
|
||||
</div>
|
||||
</body>
|
||||
</html>""".format(
|
||||
page_title=page_title,
|
||||
sub_title=sub_title,
|
||||
intro=intro,
|
||||
page_title=self.config["SITE"]["title"],
|
||||
sub_title=self.config["SITE"]["sub_title"],
|
||||
intro=self.config["SITE"]["intro"],
|
||||
scroll=self.config["SITE"]["scroll"],
|
||||
posts="\n".join(posts),
|
||||
resource=self.resource_dir,
|
||||
)
|
||||
@@ -212,7 +288,7 @@ Released : 20110306
|
||||
return """
|
||||
<div class="post">
|
||||
<div class="navigation"> </div>
|
||||
<div class=center><a href="{image}">
|
||||
<div class="image_wrapper center"><a href="{image}">
|
||||
<video class=post_image controls preload="metadata">
|
||||
<source src="{image}" type="video/mp4" >
|
||||
</video>
|
||||
@@ -227,7 +303,9 @@ Released : 20110306
|
||||
return """
|
||||
<div class="post">
|
||||
<div class="navigation"> </div>
|
||||
<div class=center><a href="{image}"><img loading=lazy class=post_image src="{med_dir}/{image}.jpg"></a></div>
|
||||
<div class="image_wrapper center"><a href="{image}">
|
||||
<img loading=lazy class=post_image src="{med_dir}/{image}.jpg">
|
||||
</a></div>
|
||||
<div class="meta"><div class="name">{title}</div></div>
|
||||
<div style="clear: both;"> </div>
|
||||
<div class="entry">{content}</div>
|
||||
@@ -253,14 +331,7 @@ Released : 20110306
|
||||
sys.exit(1)
|
||||
|
||||
with open("index.html", "wt") as fp:
|
||||
fp.write(
|
||||
self.get_index(
|
||||
self.config["SITE"]["title"],
|
||||
self.config["SITE"]["sub_title"],
|
||||
self.config["SITE"]["intro"],
|
||||
self.posts,
|
||||
)
|
||||
)
|
||||
fp.write(self.get_index(self.posts))
|
||||
|
||||
def write_resources(self):
|
||||
|
||||
@@ -270,19 +341,47 @@ Released : 20110306
|
||||
pass
|
||||
|
||||
for f in (
|
||||
"style.css",
|
||||
"mirva.css",
|
||||
"arrow_up.png",
|
||||
"arrow_down.png",
|
||||
"banner.jpg",
|
||||
"mirva.ico",
|
||||
"mirva.js",
|
||||
):
|
||||
if os.path.exists(os.path.join(self.resource_dir, f)):
|
||||
continue
|
||||
shutil.copy(
|
||||
os.path.join(self.resource_src, f), os.path.join(self.resource_dir, f)
|
||||
os.path.join(self.resource_src, f),
|
||||
os.path.join(self.resource_dir, f),
|
||||
)
|
||||
|
||||
if not os.path.exists(os.path.join(self.resource_dir, "banner.jpg")):
|
||||
try:
|
||||
f = random.choice(self.file_list)
|
||||
outfile = os.path.join(self.resource_dir, "banner.jpg")
|
||||
res = "1920x"
|
||||
convargs = [
|
||||
"convert",
|
||||
"{}[0]".format(f),
|
||||
"-background",
|
||||
"white",
|
||||
"-flatten",
|
||||
"-resize",
|
||||
res,
|
||||
"+contrast",
|
||||
"+contrast",
|
||||
"+contrast",
|
||||
"-quality",
|
||||
"85",
|
||||
outfile,
|
||||
]
|
||||
subprocess.run(convargs)
|
||||
print("Random banner written to {}".format(outfile))
|
||||
except Exception:
|
||||
shutil.copy(
|
||||
os.path.join(self.resource_src, "banner.jpg"),
|
||||
os.path.join(self.resource_dir, "banner.jpg"),
|
||||
)
|
||||
|
||||
def write_mediums(self):
|
||||
|
||||
try:
|
||||
@@ -290,14 +389,14 @@ Released : 20110306
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
r = self.config["SITE"].get("image_size", 850)
|
||||
r = self.config["SITE"].get("image_size", 1920)
|
||||
link = str(r).lower() == "link"
|
||||
if link:
|
||||
r = 0
|
||||
|
||||
res = "{:d}x{:d}>".format(int(r), int(r))
|
||||
force = self.options.force
|
||||
for f in self.file_list:
|
||||
for f in tqdm(self.file_list):
|
||||
if self.video_match.match(f):
|
||||
continue
|
||||
outfile = os.path.join(self.medium_dir, "{}.jpg".format(f))
|
||||
@@ -309,14 +408,11 @@ Released : 20110306
|
||||
|
||||
if not os.path.exists(outfile):
|
||||
if link:
|
||||
# TODO: Get absolute path to f?
|
||||
os.symlink("../../{}".format(f), outfile)
|
||||
continue
|
||||
|
||||
convargs = [
|
||||
"convert",
|
||||
"-define",
|
||||
"jpeg:size={}x{}".format(r, r),
|
||||
"{}[0]".format(f),
|
||||
"-background",
|
||||
"white",
|
||||
@@ -327,8 +423,6 @@ Released : 20110306
|
||||
"85",
|
||||
outfile,
|
||||
]
|
||||
sys.stdout.write(".")
|
||||
sys.stdout.flush()
|
||||
subprocess.run(convargs)
|
||||
sys.stdout.write("\n")
|
||||
|
||||
@@ -359,7 +453,6 @@ Released : 20110306
|
||||
|
||||
self.config[f]["description"] += p.stdout.decode("utf-8")
|
||||
sys.stdout.write("\n")
|
||||
self.write_config()
|
||||
|
||||
|
||||
def human_size(file_name, precision=1):
|
||||
@@ -379,3 +472,10 @@ def human_size(file_name, precision=1):
|
||||
size = size / 1024.0
|
||||
defPrecision = precision
|
||||
return "%s%.*f%s" % (sign, defPrecision, size, suffixes[suffixIndex])
|
||||
|
||||
|
||||
class SmartFormatter(HelpFormatter):
|
||||
def _split_lines(self, help, width):
|
||||
if help.startswith("smart|"):
|
||||
return help[6:].splitlines()
|
||||
return HelpFormatter._split_lines(self, help, width)
|
||||
Reference in New Issue
Block a user