some reworking

This commit is contained in:
SG
2025-06-07 13:17:51 +03:00
parent fc1ee27146
commit 1854366a9d
7 changed files with 183 additions and 74 deletions

11
argparser.py Normal file
View File

@@ -0,0 +1,11 @@
import argparse
from config import Config
argparser = argparse.ArgumentParser(
prog = Config.APP_NAME,
description = Config.APP_DESCRIPTION,
epilog = f"See {Config.APP_SRC_URL} for more info.")
argparser.add_argument('--init', action='store_true', help = 'Initialize new site')
argparser.add_argument('--content', '--edit', type = str, help = 'Create new content')
argparser.add_argument('--build', action='store_true', help = 'Build the site')

58
classes.py Normal file
View File

@@ -0,0 +1,58 @@
from datetime import datetime
import shutil
import markdown
import frontmatter
from jinja2 import Environment, FileSystemLoader
from pathlib import Path
from logger import logger
from config import Config
# Prepare template rendering engine
env = Environment(loader=FileSystemLoader(Config.TEMPLATE_DIR))
env.globals['header_image'] = Config.HEADER_IMAGE
index_template = env.get_template("index.html")
content_item_template = env.get_template("content_item.html")
class DefaultFrontmatterHeader:
def __init__(self, title):
self.title = f"title: '{title}'\n"
self.date = f"date: '{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}'\n"
self.omit_second_title = f"omit_second_title: '{str(False)}'\n"
self.description = "description: \n"
self.author = "author: \n"
class ContentItemPrototype:
def render_content(self):
logger.debug(f"Rendering {self.source_filename} to {Config.OUTPUT_DIR}/{self.target_filename}")
if self.image_src_file.exists():
shutil.copyfile(self.image_src_file, Path(Config.OUTPUT_DIR) / self.image)
if self.custom_css_src_file.exists():
shutil.copyfile(self.custom_css_src_file,Path(Config.OUTPUT_DIR) / self.custom_css)
if self.custom_js_src_file.exists():
shutil.copyfile(self.custom_js_src_file, Path(Config.OUTPUT_DIR) / self.custom_js)
with self.content_output_path.open("w", encoding="utf-8") as f:
f.write(content_item_template.render(content_item = self, page_title = self.title))
def __init__(self, md_file):
logger.debug(f"Parsing {md_file}")
self.source_filename = md_file
self.slug = md_file.stem
self.target_filename = self.slug + ".html"
self.data = frontmatter.load(md_file)
self.html = markdown.markdown(self.data.content)
self.preview = self.html[:300] + "<a href=" + f"{self.slug}.html" + ">... read more</a>"
self.title = self.data.get("title", self.slug)
self.omit_second_title = self.data.get("omit_second_title", False)
self.date = self.data.get("data", "2000-01-01T00:00:00+03:00")
self.content_output_path = Path(Config.OUTPUT_DIR) / f"{self.slug}.html"
self.image_src_file = Path(f"{Config.CONTENT_DIR}/{md_file.stem}.jpg")
self.image = f"images/{md_file.stem}.jpg" if self.image_src_file.exists() else None
self.custom_css_src_file = Path(f"{Config.CONTENT_DIR}/{md_file.stem}.css")
self.custom_css = f"static/css/{md_file.stem}.css" if self.custom_css_src_file.exists() else None
logger.debug(f"Custom CSS: {self.slug}: {self.custom_css}")
self.custom_js_src_file = Path(f"{Config.CONTENT_DIR}/{md_file.stem}.js")
self.custom_js = f"static/js/{md_file.stem}.js" if self.custom_js_src_file.exists() else None
logger.debug(f"Custom JS: {self.slug}: {self.custom_js}")
# Special handling for the 'about' item
if self.slug == 'about':
self.image = 'static/about.jpg'

View File

@@ -1,7 +1,16 @@
import os import os
# Main config section # Main config section
class Config: class Config:
MAIN_PAGE_TITLE = "hydrogen site"
APP_NAME = "hydrogen" APP_NAME = "hydrogen"
MAIN_PAGE_TITLE = "Selected poems" APP_DESCRIPTION = "Simplistic static site generator"
OUTPUT_DIR = os.environ.get('OUTPUT_DIR') or 'public' APP_SRC_URL = f"https://git.exocortex.ru/Exocortex/{APP_NAME}"
OUTPUT_DIR = 'public'
OUTPUT_IMG_DIR = f"{OUTPUT_DIR}/images"
OUTPUT_CSS_DIR = f"{OUTPUT_DIR}/css"
OUTPUT_JS_DIR = f"{OUTPUT_DIR}/js"
TEMPLATE_DIR = 'templates'
CONTENT_DIR = 'content'
STATIC_DIR = 'static'
HEADER_IMAGE = 'static/header.jpg' HEADER_IMAGE = 'static/header.jpg'

42
functions.py Normal file
View File

@@ -0,0 +1,42 @@
import os, subprocess
import shutil
from pathlib import Path
from classes import DefaultFrontmatterHeader
from config import Config
from logger import logger
def create_content(filename):
filename += '.md'
filename = Path(f"{Config.CONTENT_DIR}/{filename}")
if not filename.exists():
fh = DefaultFrontmatterHeader(filename.stem)
logger.debug(f"Creating new content {filename}")
with filename.open("w", encoding="utf-8") as f:
f.writelines(['---\n', fh.title, fh.date, fh.description, fh.author, fh.omit_second_title, '---\n', '\n', '\n'])
def edit_content(filename):
logger.debug(f"Editing content {filename}")
editor = os.environ.get('EDITOR', 'vim')
subprocess.call([editor, filename])
def init_site():
logger.debug(f"Initializing new site")
# Recreate output directory if necessary
output_dir = Path(Config.OUTPUT_DIR)
if output_dir.exists():
shutil.rmtree(output_dir)
output_dir.mkdir()
# Create output directory subtree
for dir in [ Path(Config.CONTENT_DIR), Path(Config.STATIC_DIR), Path(Config.TEMPLATE_DIR),
Path(Config.OUTPUT_IMG_DIR), Path(Config.OUTPUT_CSS_DIR), Path(Config.OUTPUT_JS_DIR)]:
dir.mkdir(exist_ok=True)
# Create "About.md" content item
create_content("about")
def build_site():
logger.debug(f"Starting build")

View File

@@ -1,12 +1,13 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
from pathlib import Path from pathlib import Path
import frontmatter
import markdown
from jinja2 import Environment, FileSystemLoader
import shutil import shutil
from config import Config from config import Config
from logger import logger from logger import logger
from argparser import argparser
from classes import *
from functions import *
content_dir = Path('content') content_dir = Path('content')
template_dir = Path('templates') template_dir = Path('templates')
@@ -17,38 +18,14 @@ assets_js_dir = Path(output_dir / 'static/js')
static_dir = Path('static') static_dir = Path('static')
header_image = Config.HEADER_IMAGE or '/static/header.jpg' header_image = Config.HEADER_IMAGE or '/static/header.jpg'
class ContentItemPrototype:
def render_content(self):
if self.image_src_file.exists():
shutil.copyfile(self.image_src_file, output_dir / self.image)
if self.custom_css_src_file.exists():
shutil.copyfile(self.custom_css_src_file,output_dir / self.custom_css)
if self.custom_js_src_file.exists():
shutil.copyfile(self.custom_js_src_file, output_dir / self.custom_js)
with self.content_output_path.open("w", encoding="utf-8") as f:
f.write(content_item_template.render(content_item = self, page_title = self.title))
def __init__(self, md_file):
self.slug = md_file.stem
self.data = frontmatter.load(md_file)
self.html = markdown.markdown(self.data.content)
self.preview = self.html[:300] + "<a href=" + f"{self.slug}.html" + ">... read more</a>"
self.title = self.data.get("title", self.slug)
self.omit_second_title = self.data.get("omit_second_title", False)
self.date = self.data.get("data", "2000-01-01T00:00:00+03:00")
self.content_output_path = output_dir / f"{self.slug}.html"
self.image_src_file = Path(f"{content_dir}/{md_file.stem}.jpg")
self.image = f"images/{md_file.stem}.jpg" if self.image_src_file.exists() else None
self.custom_css_src_file = Path(f"{content_dir}/{md_file.stem}.css")
self.custom_css = f"static/css/{md_file.stem}.css" if self.custom_css_src_file.exists() else None
logger.debug(f"Custom CSS: {self.slug}: {self.custom_css}")
self.custom_js_src_file = Path(f"{content_dir}/{md_file.stem}.js")
self.custom_js = f"static/js/{md_file.stem}.js" if self.custom_js_src_file.exists() else None
logger.debug(f"Custom JS: {self.slug}: {self.custom_js}")
# Special handling for the 'about' item
if self.slug == 'about':
self.image = 'static/about.jpg'
def build_site():
logger.info(f"Building the '{Config.MAIN_PAGE_TITLE}' site.") logger.info(f"Building the '{Config.MAIN_PAGE_TITLE}' site.")
# Recreate the output dir if needed # Recreate the output dir if needed
@@ -65,12 +42,6 @@ for subdir in subdirs:
if static_dir.exists(): if static_dir.exists():
shutil.copytree(static_dir, output_dir / "static", dirs_exist_ok=True) shutil.copytree(static_dir, output_dir / "static", dirs_exist_ok=True)
# Prepare template rendering engine
env = Environment(loader=FileSystemLoader(str(template_dir)))
env.globals['header_image'] = header_image
index_template = env.get_template("index.html")
content_item_template = env.get_template("content_item.html")
# Parse the content files # Parse the content files
content_items = [] content_items = []
for md_file in content_dir.glob("*.md"): for md_file in content_dir.glob("*.md"):
@@ -80,7 +51,7 @@ for md_file in content_dir.glob("*.md"):
"slug": current_content_item.slug, "slug": current_content_item.slug,
"title": current_content_item.title, "title": current_content_item.title,
"date": current_content_item.date, "date": current_content_item.date,
"preview": markdown.markdown(current_content_item.preview), # "preview": markdown.markdown(current_content_item.preview),
"image": current_content_item.image, "image": current_content_item.image,
}) })
@@ -96,3 +67,20 @@ about_content.render_content()
shutil.copyfile(static_dir / 'robots.txt', output_dir / 'robots.txt') shutil.copyfile(static_dir / 'robots.txt', output_dir / 'robots.txt')
logger.info(f"Created {len(content_items)} content items.") logger.info(f"Created {len(content_items)} content items.")
def main():
args = argparser.parse_args()
if args.content:
content = args.content or args.edit
create_content(content)
edit_content(content)
if args.build:
build_site()
if args.init:
init_site()
if __name__ == '__main__':
main()

View File

@@ -4,7 +4,7 @@ from config import Config
# Logging config section # Logging config section
LOG_TO = sys.stdout LOG_TO = sys.stdout
LOG_LEVEL = logging.INFO LOG_LEVEL = logging.DEBUG
logger = logging.getLogger(Config.APP_NAME) logger = logging.getLogger(Config.APP_NAME)
logger.setLevel(LOG_LEVEL) logger.setLevel(LOG_LEVEL)

View File

@@ -1,3 +1,4 @@
argparse
python-frontmatter python-frontmatter
jinja2 jinja2
markdown markdown