move to json config. allow subfolders
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
__version__ = "20230929.0"
|
||||
__version__ = "20231013.0"
|
||||
|
||||
|
||||
def get_version():
|
||||
|
||||
205
mirva/mirva.py
205
mirva/mirva.py
@@ -1,10 +1,11 @@
|
||||
import configparser
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
import random
|
||||
import re
|
||||
import shutil
|
||||
import subprocess
|
||||
import random
|
||||
import sys
|
||||
import urllib.parse
|
||||
from argparse import ArgumentParser, HelpFormatter
|
||||
|
||||
@@ -14,16 +15,13 @@ from tqdm import tqdm
|
||||
|
||||
class Mirva:
|
||||
def __init__(self):
|
||||
self.resource_src = os.path.join(
|
||||
os.path.dirname(os.path.abspath(__file__)), "resources"
|
||||
)
|
||||
self.resource_src = os.path.join(os.path.dirname(os.path.abspath(__file__)), "resources")
|
||||
self.resource_dir = ".mirva"
|
||||
self.medium_dir = os.path.join(self.resource_dir, "med")
|
||||
self.config_file = os.path.join(self.resource_dir, "config.cfg")
|
||||
self.config_backup = os.path.join(self.resource_dir, "config.cfg.bkp")
|
||||
self.image_match = re.compile(
|
||||
".*\.jpg$|.*\.jpeg$|.*\.png$|.*\.gif$|.*\.tif$", re.I
|
||||
)
|
||||
self.config_file = os.path.join(self.resource_dir, "config.json")
|
||||
self.config_file_old = os.path.join(self.resource_dir, "config.cfg")
|
||||
self.config_backup = os.path.join(self.resource_dir, "config.bkp")
|
||||
self.image_match = re.compile(".*\.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"},
|
||||
@@ -49,28 +47,27 @@ class Mirva:
|
||||
self.get_options()
|
||||
os.chdir(self.options.folder)
|
||||
self.file_list = self.get_files()
|
||||
self.folder_list = self.get_folders()
|
||||
|
||||
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
|
||||
)
|
||||
)
|
||||
print("Config created or updated: Check config contents: {}".format(self.config_file))
|
||||
|
||||
if self.run_commands["build"]:
|
||||
self.get_config()
|
||||
self.create_posts()
|
||||
self.create_folders()
|
||||
self.write_index()
|
||||
self.write_mediums()
|
||||
print("Gallery written.")
|
||||
|
||||
def create_config(self):
|
||||
self.config = configparser.RawConfigParser()
|
||||
self.config.read(self.config_file)
|
||||
self.get_config()
|
||||
config_changed = False
|
||||
|
||||
## SITE
|
||||
if not "SITE" in self.config:
|
||||
self.config["SITE"] = {}
|
||||
config_changed = True
|
||||
@@ -87,25 +84,55 @@ class Mirva:
|
||||
self.config["SITE"][key] = value
|
||||
config_changed = True
|
||||
|
||||
## FOLDERS
|
||||
if not "FOLDERS" in self.config:
|
||||
self.config["FOLDERS"] = []
|
||||
config_changed = True
|
||||
|
||||
path_list = [i["path"] for i in self.config["FOLDERS"]]
|
||||
if self.options.add_back:
|
||||
if not ".." in path_list:
|
||||
self.config["FOLDERS"].insert(0, {"path": "..", "title": "Back", "thumb": '[guess]'})
|
||||
config_changed = True
|
||||
|
||||
for d in self.folder_list:
|
||||
if not d in path_list:
|
||||
self.config["FOLDERS"].append({"path": d, "title": d, "thumb": '[guess]'})
|
||||
config_changed = True
|
||||
|
||||
## IMAGES
|
||||
if not "IMAGES" in self.config:
|
||||
self.config["IMAGES"] = []
|
||||
config_changed = True
|
||||
|
||||
path_list = [i["path"] for i in self.config["IMAGES"]]
|
||||
for f in self.file_list:
|
||||
if not f in self.config:
|
||||
if not f in path_list:
|
||||
title, _ = os.path.splitext(f)
|
||||
title = title.replace("_", " ")
|
||||
self.config[f] = {"title": title, "description": ""}
|
||||
self.config["IMAGES"].append({"path": 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"):
|
||||
unnecessary_files = []
|
||||
unnecessary_folders = []
|
||||
for i, f in enumerate(self.config["IMAGES"]):
|
||||
if f["path"] not in self.file_list:
|
||||
print("{} not found in files".format(f["path"]))
|
||||
unnecessary_files.append(i)
|
||||
for i, d in enumerate(self.config["FOLDERS"]):
|
||||
if d["path"] == "..":
|
||||
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]
|
||||
if d["path"] not in self.folder_list:
|
||||
unnecessary_folders.append(i)
|
||||
if len(unnecessary_files) > 0:
|
||||
config_changed = True
|
||||
if len(unnecessary_folders) > 0:
|
||||
config_changed = True
|
||||
|
||||
self.config["IMAGES"] = [d for i, d in enumerate(self.config["IMAGES"]) if i not in unnecessary_files]
|
||||
self.config["FOLDERS"] = [d for i, d in enumerate(self.config["FOLDERS"]) if i not in unnecessary_folders]
|
||||
|
||||
if self.options.exif:
|
||||
self.append_exif()
|
||||
@@ -117,41 +144,75 @@ class Mirva:
|
||||
|
||||
def create_posts(self):
|
||||
self.posts = []
|
||||
for c in self.config:
|
||||
if c in self.file_list:
|
||||
post = self.get_post(
|
||||
c, self.config[c]["title"], self.config[c]["description"]
|
||||
)
|
||||
for c in self.config["IMAGES"]:
|
||||
if c["path"] in self.file_list:
|
||||
post = self.get_post(c["path"], c["title"], c["description"])
|
||||
self.posts.append(post)
|
||||
|
||||
def create_folders(self):
|
||||
self.folders = []
|
||||
for c in self.config["FOLDERS"]:
|
||||
self.folders.append(self.get_folder(c["path"], c["title"], c["thumb"]))
|
||||
|
||||
def get_config(self):
|
||||
self.config = configparser.RawConfigParser()
|
||||
self.config.read(self.config_file)
|
||||
if os.path.exists(self.config_file_old):
|
||||
# Migration from old style config
|
||||
self.config_old = configparser.RawConfigParser()
|
||||
self.config_old.read(self.config_file_old)
|
||||
self.config = {}
|
||||
self.config["SITE"] = dict(self.config_old.items("SITE"))
|
||||
self.config["IMAGES"] = []
|
||||
|
||||
for f in self.config_old.sections():
|
||||
if f in ("IMAGES", "SITE"):
|
||||
continue
|
||||
self.config["IMAGES"].append(
|
||||
{
|
||||
"path": f,
|
||||
"title": self.config_old[f]["title"],
|
||||
"description": self.config_old[f]["description"],
|
||||
}
|
||||
)
|
||||
os.remove(self.config_file_old)
|
||||
return
|
||||
if os.path.exists(self.config_file):
|
||||
with open(self.config_file, "rt") as fp:
|
||||
self.config = json.load(fp)
|
||||
return
|
||||
self.config = {}
|
||||
|
||||
def write_config(self):
|
||||
print(
|
||||
"Modified config: {}".format(
|
||||
os.path.join(self.options.folder, self.config_file)
|
||||
)
|
||||
)
|
||||
print("Modified config: {}".format(os.path.join(self.options.folder, self.config_file)))
|
||||
if os.path.exists(self.config_file):
|
||||
with open(self.config_file, "rt") as reader:
|
||||
with open(self.config_backup, "wt") as writer:
|
||||
writer.write(reader.read())
|
||||
|
||||
with open(self.config_file, "wt") as fp:
|
||||
self.config.write(fp)
|
||||
json.dump(self.config, fp, indent=2)
|
||||
|
||||
def get_files(self):
|
||||
files = []
|
||||
for f in sorted(os.listdir(".")):
|
||||
if f.startswith("."):
|
||||
continue
|
||||
if not os.path.isfile(f):
|
||||
continue
|
||||
if not (self.image_match.match(f) or self.video_match.match(f)):
|
||||
continue
|
||||
files.append(f)
|
||||
return files
|
||||
|
||||
def get_folders(self):
|
||||
folders = []
|
||||
for f in sorted(os.listdir(".")):
|
||||
if f.startswith("."):
|
||||
continue
|
||||
if not os.path.isdir(f):
|
||||
continue
|
||||
folders.append(f)
|
||||
return folders
|
||||
|
||||
def get_options(self):
|
||||
parser = ArgumentParser(prog="mirva", formatter_class=SmartFormatter)
|
||||
parser.add_argument(
|
||||
@@ -165,7 +226,12 @@ class Mirva:
|
||||
default=".",
|
||||
help="Folder for gallery. Default current folder.",
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"--add-back",
|
||||
default=False,
|
||||
action="store_true",
|
||||
help="Add 'Back' link to parent folder.",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--purge",
|
||||
default=False,
|
||||
@@ -186,9 +252,7 @@ class Mirva:
|
||||
action="append",
|
||||
metavar=("key", "value"),
|
||||
help="smart|Configurable options: \n"
|
||||
+ "\n".join(
|
||||
["{}: {}".format(k, v["help"]) for k, v in self.site_defaults.items()]
|
||||
),
|
||||
+ "\n".join(["{}: {}".format(k, v["help"]) for k, v in self.site_defaults.items()]),
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
@@ -214,7 +278,7 @@ class Mirva:
|
||||
"build": self.options.command == "build" or self.options.command == "all",
|
||||
}
|
||||
|
||||
def get_index(self, posts):
|
||||
def get_index(self):
|
||||
return """<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||
<!--
|
||||
Design by TEMPLATED
|
||||
@@ -252,6 +316,11 @@ Released : 20110306
|
||||
<div id="page-bgtop">
|
||||
<div id="page-bgbtm">
|
||||
<div id="content">
|
||||
<div id="post_folders">
|
||||
<div class="entry folders">
|
||||
{folders}
|
||||
</div>
|
||||
</div>
|
||||
<div class="post" id="post_intro">
|
||||
<div class="entry intro">
|
||||
{intro}
|
||||
@@ -273,7 +342,8 @@ Released : 20110306
|
||||
sub_title=self.config["SITE"]["sub_title"],
|
||||
intro=self.config["SITE"]["intro"],
|
||||
scroll=self.config["SITE"]["scroll"],
|
||||
posts="\n".join(posts),
|
||||
folders="\n".join(self.folders),
|
||||
posts="\n".join(self.posts),
|
||||
resource=self.resource_dir,
|
||||
)
|
||||
|
||||
@@ -307,6 +377,32 @@ Released : 20110306
|
||||
</div>"""
|
||||
).format(image=image, title=title, content=content, med_dir=self.medium_dir)
|
||||
|
||||
def get_folder(self, path, title, thumb):
|
||||
|
||||
if thumb == '[guess]':
|
||||
try:
|
||||
img = (
|
||||
"style=\"background-image: url('"
|
||||
+ urllib.parse.quote(
|
||||
os.path.join(
|
||||
path,
|
||||
self.resource_dir,
|
||||
"med",
|
||||
sorted(
|
||||
[f for f in os.listdir(os.path.join(path, self.resource_dir, "med")) if f.endswith(".jpg")]
|
||||
)[0],
|
||||
)
|
||||
)
|
||||
+ "')\""
|
||||
)
|
||||
except Exception:
|
||||
img = ""
|
||||
else:
|
||||
img = "style=\"background-image: url('{}')\"".format(thumb)
|
||||
return '<div class=folder_wrapper><a href="{path}" title="{title}"><span class="folder_thumb" {img}></span>{title}</a></div>'.format(
|
||||
path=urllib.parse.quote(path), title=title, img=img
|
||||
)
|
||||
|
||||
def is_created_with_mirva(self):
|
||||
with open("index.html", "rt") as fp:
|
||||
for line in fp.readlines():
|
||||
@@ -317,13 +413,11 @@ Released : 20110306
|
||||
def write_index(self):
|
||||
if os.path.exists("index.html"):
|
||||
if not self.is_created_with_mirva():
|
||||
print(
|
||||
"index.html exists, and it's not written with Mirva. Not overwriting."
|
||||
)
|
||||
print("index.html exists, and it's not written with Mirva. Not overwriting.")
|
||||
sys.exit(1)
|
||||
|
||||
with open("index.html", "wt") as fp:
|
||||
fp.write(self.get_index(self.posts))
|
||||
fp.write(self.get_index())
|
||||
|
||||
def write_resources(self):
|
||||
try:
|
||||
@@ -427,22 +521,21 @@ Released : 20110306
|
||||
</ul>
|
||||
"""
|
||||
|
||||
for f in self.config:
|
||||
if f in self.file_list:
|
||||
for f in self.config["IMAGES"]:
|
||||
if f["path"] in self.file_list:
|
||||
sys.stdout.write(".")
|
||||
sys.stdout.flush()
|
||||
file_size = human_size(f)
|
||||
file_size = human_size(f["path"])
|
||||
p = subprocess.run(
|
||||
[
|
||||
"identify",
|
||||
"-format",
|
||||
exif_format.format(size=file_size),
|
||||
"{}[0]".format(f),
|
||||
"{}[0]".format(f["path"]),
|
||||
],
|
||||
capture_output=True,
|
||||
)
|
||||
|
||||
self.config[f]["description"] += p.stdout.decode("utf-8")
|
||||
f["description"] += p.stdout.decode("utf-8")
|
||||
sys.stdout.write("\n")
|
||||
|
||||
|
||||
|
||||
@@ -175,6 +175,21 @@ a:hover {}
|
||||
|
||||
.post-bgbtm {}
|
||||
|
||||
.folder_wrapper {
|
||||
margin-top: 3px;
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
.folders .folder_thumb {
|
||||
width: 150px;
|
||||
height: 40px;
|
||||
background-size: cover;
|
||||
vertical-align: middle;
|
||||
margin-right: 2em;
|
||||
display: inline-block;
|
||||
background-position: center;
|
||||
}
|
||||
|
||||
.post .title {
|
||||
height: 38px;
|
||||
margin-bottom: 10px;
|
||||
|
||||
Reference in New Issue
Block a user