11 Commits

Author SHA1 Message Date
SG
808aab3609 updates 2025-06-30 20:57:01 +03:00
sg
162b45809b hopefully fixed bad images in content_item
template
2025-06-30 20:21:03 +03:00
SG
664a6adb77 updates 2025-06-22 14:08:45 +03:00
sg
b633c21ef2 updates 2025-06-22 14:06:52 +03:00
SG
802f8022d0 audio player added 2025-06-22 12:12:36 +03:00
SG
d58d9464a9 updates 2025-06-20 15:18:28 +03:00
SG
dca4aa7a7e updates 2025-06-19 11:17:01 +03:00
SG
8813d91493 updates 2025-06-19 08:56:37 +03:00
SG
9fa58d4700 updates 2025-06-18 15:55:52 +03:00
SG
15879e66b7 updates 2025-06-18 15:26:11 +03:00
SG
3abe3f2fac updates 2025-06-18 14:59:23 +03:00
6 changed files with 89 additions and 67 deletions

View File

@@ -8,33 +8,6 @@ import frontmatter
from pathlib import Path from pathlib import Path
from logger import logger from logger import logger
from config import config from config import config
#from jinja_env import env, content_item_template, index_template
from jinja2 import Environment, FileSystemLoader
# Get the script base_dir and check for templates dir
if Path(f'themes/{config.theme}/templates').exists():
base_dir = "."
elif getattr(sys, 'frozen', False):
# Running fron Pyinstaller-packed binary
base_dir = Path(sys._MEIPASS)
else:
# Running as a plain Python app
base_dir = Path(__file__).resolve().parent
# Prepare template rendering engine
if Path(f"themes/{config.theme}/templates").exists():
# Use the templates from the initialized site instance and the installed theme
jinja_env_dir = f"themes/{config.theme}/templates"
logger.debug(f"Using locally initialized templates from {jinja_env_dir}")
else:
# Use default templates from the default theme shipped with the app
# i.e. PyInstaller-packed single executable
logger.debug("Using shipped default temlpates.")
jinja_env_dir = f"{base_dir}/themes/default/templates"
env = Environment(loader=FileSystemLoader(f"{jinja_env_dir}"))
env.globals['header_image'] = f"{base_dir}/themes/{config.theme}/static/images/header.jpg"
index_template = env.get_template("index.html")
content_item_template = env.get_template("content_item.html")
class ContentItem: class ContentItem:
def render_content(self, categories, target_file = False): def render_content(self, categories, target_file = False):
@@ -46,23 +19,46 @@ class ContentItem:
else: else:
footer_data = '' footer_data = ''
try: try:
if self.image_file and self.image_file.exists(): if self.image_file and Path(self.image_file).exists():
image_targetfile = Path(f"{config.output_dir}/{config.static_dir}/images/{self.image_file.name}") self.image_file = Path(self.image_file)
image_targetfile = Path(f"{config.output_dir}/{config.static_dir}/images/{self.source_file.stem}.jpg")
logger.debug(f"Copying {self.image_file} to {image_targetfile}") logger.debug(f"Copying {self.image_file} to {image_targetfile}")
shutil.copyfile(self.image_file, image_targetfile) shutil.copyfile(self.image_file, image_targetfile)
self.image_file = f"{self.image_file.stem}.jpg" self.image_file = f"{self.image_file.stem}.jpg"
if self.css_file and self.css_file.exists(): else:
self.image_file = False
except Exception as e:
logger.error(f"Couldn't render image file {self.image_file}: {e}")
try:
if self.audio_file and Path(self.audio_file).exists():
self.audio_file = Path(self.audio_file)
audio_targetfile = Path(f"{config.output_dir}/{config.static_dir}/audio/{self.audio_file.name}")
logger.debug(f"Copying {self.audio_file} to {audio_targetfile}")
shutil.copyfile(self.audio_file, audio_targetfile)
self.audio_file = f"{self.audio_file.stem}.mp3"
except Exception as e:
logger.error(f"Couldn't render audio file {self.audio_file}: {e}")
try:
if self.css_file and Path(self.css_file).exists():
self.css_file = Path(self.css_file)
css_targetfile = Path(f"{config.output_dir}/{config.static_dir}/css/{self.css_file.name}") css_targetfile = Path(f"{config.output_dir}/{config.static_dir}/css/{self.css_file.name}")
logger.debug(f"Copying {self.css_file} to {css_targetfile}") logger.debug(f"Copying {self.css_file} to {css_targetfile}")
shutil.copyfile(self.css_file, css_targetfile) shutil.copyfile(self.css_file, css_targetfile)
if self.js_file and self.js_file.exists(): except Exception as e:
logger.error(f"Couldn't render CSS file {self.css_file}: {e}")
try:
if self.js_file and Path(self.js_file).exists():
self.js_file = Path(self.js_file)
js_targetfile = Path(f"{config.output_dir}/{config.static_dir}/js/{self.js_file.name}") js_targetfile = Path(f"{config.output_dir}/{config.static_dir}/js/{self.js_file.name}")
logger.debug(f"Copying {self.js_file} to {js_targetfile}") logger.debug(f"Copying {self.js_file} to {js_targetfile}")
shutil.copyfile(self.js_file, js_targetfile) shutil.copyfile(self.js_file, js_targetfile)
with self.target_file.open("w", encoding="utf-8") as f:
f.write(content_item_template.render(content_item = self, page_title = f"{config.site_name}: {self.title}", parent_path = '../', categories = categories, footer_data = footer_data))
except Exception as e: except Exception as e:
logger.error(f"Renderer: {e}") logger.error(f"Couldn't render JS file {self.js_file}: {e}")
try:
with self.target_file.open("w", encoding="utf-8") as f:
f.write(config.content_item_template.render(content_item = self, page_title = f"{config.site_name}: {self.title}", parent_path = '../', categories = categories, footer_data = footer_data))
except Exception as e:
logger.error(f"Couldn't render content file: {e}")
def parse_content(self): def parse_content(self):
logger.debug(f"Parsing file {self.source_file}") logger.debug(f"Parsing file {self.source_file}")
@@ -80,13 +76,14 @@ class ContentItem:
self.hidden = self.data.get("hidden", str(False)) self.hidden = self.data.get("hidden", str(False))
self.data.content = self.data.content.replace('\n', ' \n') # For markdown newline rendering self.data.content = self.data.content.replace('\n', ' \n') # For markdown newline rendering
self.html = markdown.markdown(self.data.content) self.html = markdown.markdown(self.data.content)
cover_image_path = Path(f"{self.source_file.parent}/{self.source_file.stem}.jpg") cover_image_path = f"{self.source_file.parent}/{self.source_file.stem}.jpg"
self.image_file = cover_image_path if cover_image_path.exists() else "" self.image_file = cover_image_path if Path(cover_image_path).exists() else ""
css_filepath = Path(f"{self.source_file.parent}/{self.source_file.stem}.css") audio_filepath = f"{self.source_file.parent}/{self.source_file.stem}.mp3"
self.css_file = css_filepath if css_filepath.exists() else "" self.audio_file = audio_filepath if Path(audio_filepath).exists() else ""
js_filepath = Path(f"{self.source_file.parent}/{self.source_file.stem}.js") css_filepath = f"{self.source_file.parent}/{self.source_file.stem}.css"
self.js_file = js_filepath if js_filepath.exists() else "" self.css_file = css_filepath if Path(css_filepath).exists() else ""
logger.debug(f"CCC {self.source_file.parts} : {self.source_file.parent} / {self.source_file.stem}.jpg") js_filepath = f"{self.source_file.parent}/{self.source_file.stem}.js"
self.js_file = js_filepath if Path(js_filepath).exists() else ""
except Exception as e: except Exception as e:
logger.error(f"Parser error, {e}") logger.error(f"Parser error, {e}")
@@ -133,7 +130,7 @@ class Site:
os.makedirs(subdir, exist_ok=True) os.makedirs(subdir, exist_ok=True)
# Copy default theme # Copy default theme
shutil.copytree(f"{base_dir}/themes/default", "themes/default", dirs_exist_ok=True) shutil.copytree(f"{config.base_dir}/themes/default", "themes/default", dirs_exist_ok=True)
def get_content_items(self): def get_content_items(self):
logger.debug("Getting content items") logger.debug("Getting content items")
@@ -164,7 +161,7 @@ class Site:
subdir.mkdir(parents=True, exist_ok=True) subdir.mkdir(parents=True, exist_ok=True)
# Copy theme's static dir to 'public/static # Copy theme's static dir to 'public/static
shutil.copytree(f"{base_dir}/themes/{config.theme}/static", f"{self.output_dir}/static", dirs_exist_ok=True) shutil.copytree(f"{config.base_dir}/themes/{config.theme}/static", f"{self.output_dir}/static", dirs_exist_ok=True)
# Get content items # Get content items
self.get_content_items() self.get_content_items()
@@ -188,7 +185,7 @@ class Site:
footer_data = '' footer_data = ''
visible_content_items = [c for c in self.content_items if c.data.get("hidden") != True] visible_content_items = [c for c in self.content_items if c.data.get("hidden") != True]
with (self.output_dir / "index.html").open("w", encoding="utf-8") as f: with (self.output_dir / "index.html").open("w", encoding="utf-8") as f:
f.write(index_template.render(page_title = config.site_name, content_items=visible_content_items, categories = self.categories, footer_data = footer_data)) f.write(config.index_template.render(page_title = config.site_name, content_items=visible_content_items, categories = self.categories, footer_data = footer_data))
# Render the categories indices # Render the categories indices
if hasattr(config, "footer"): if hasattr(config, "footer"):
@@ -198,9 +195,9 @@ class Site:
visible_content_items = [c for c in self.content_items if c.data.get("hidden") != True] visible_content_items = [c for c in self.content_items if c.data.get("hidden") != True]
for category in self.categories: for category in self.categories:
category_index = Path(f"{self.output_dir}/categories/{category}.html") category_index = Path(f"{self.output_dir}/categories/{category}.html")
category_items = [i for i in visible_content_items if category in i.data.get("categories")] category_items = [i for i in visible_content_items if category in i.data.get("categories", "default")]
with (category_index).open(mode="w", encoding="utf-8") as f: with (category_index).open(mode="w", encoding="utf-8") as f:
f.write(index_template.render(page_title=f"{config.site_name}: {category}", content_items=category_items, categories = self.categories, parent_path = '../', footer_data = footer_data)) f.write(config.index_template.render(page_title=f"{config.site_name}: [ {category} ]", content_items=category_items, categories = self.categories, parent_path = '../', footer_data = footer_data))
logger.info(f"Created {len(self.content_items)} content items.") logger.info(f"Created {len(self.content_items)} content items.")

View File

@@ -1,17 +1,6 @@
import os, yaml import os, sys, yaml
from jinja2 import Environment, FileSystemLoader
# Main config section from pathlib import Path
#class Config:
# MAIN_PAGE_TITLE = "microgen library"
# APP_NAME = "hydrogen"
# APP_DESCRIPTION = "Simplistic static site generator"
# APP_SRC_URL = f"https://git.exocortex.ru/Exocortex/{APP_NAME}"
# OUTPUT_DIR = 'public'
# TEMPLATES_DIR = 'templates'
# CONTENT_DIR = 'content'
# STATIC_DIR = 'static'
# HEADER_IMAGE = 'static/header.jpg'
# THEME = "default"
class Config: class Config:
def __init__(self): def __init__(self):
@@ -33,6 +22,33 @@ class Config:
if config: if config:
self.update_from_dict(config) self.update_from_dict(config)
# Get the script base_dir and check for templates dir
if Path(f'themes/{self.theme}/templates').exists():
self.base_dir = "."
elif getattr(sys, 'frozen', False):
# Running fron Pyinstaller-packed binary
self.base_dir = Path(sys._MEIPASS)
else:
# Running as a plain Python app
self.base_dir = Path(__file__).resolve().parent
# Prepare template rendering engine
if Path(f"themes/{self.theme}/templates").exists():
# Use the templates from the initialized site instance and the installed theme
jinja_env_dir = f"themes/{self.theme}/templates"
#logger.debug(f"Using locally initialized templates from {jinja_env_dir}")
else:
# Use default templates from the default theme shipped with the app
# i.e. PyInstaller-packed single executable
#logger.debug("Using shipped default temlpates.")
jinja_env_dir = f"{self.base_dir}/themes/default/templates"
self.env = Environment(loader=FileSystemLoader(f"{jinja_env_dir}"))
self.env.globals['header_image'] = f"{self.base_dir}/themes/{self.theme}/static/images/header.jpg"
self.index_template = self.env.get_template("index.html")
self.content_item_template = self.env.get_template("content_item.html")
def update_from_dict(self, config_dict): def update_from_dict(self, config_dict):
for key, value in config_dict.items(): for key, value in config_dict.items():
setattr(self, key, value) setattr(self, key, value)

View File

@@ -1,4 +1,5 @@
argparse argparse
bs4
python-frontmatter python-frontmatter
jinja2 jinja2
markdown markdown

View File

@@ -9,11 +9,24 @@
{% block content %} {% block content %}
<div class="container mt-4 mb-5"> <div class="container mt-4 mb-5">
<img src="{{ parent_path }}static/images/{{ content_item.image_file }}" class="img-fluid mb-5 rounded w-100 h-auto"> {% if content_item.image_file %}
<img src="{{ parent_path }}static/images/{{ content_item.image_file }}" alt="{{ content_item.image_file }}" class="img-fluid mb-5 rounded w-100 h-auto dotr">
{% endif %}
{% if not content_item.omit_second_title %} {% if not content_item.omit_second_title %}
<h1>{{ content_item.title }}</h1> <h1>{{ content_item.title }}</h1>
{% endif %} {% endif %}
<article>{{ content_item.html | safe }}</article> <article>{{ content_item.html | safe }}</article>
{% if content_item.audio_file %}
<div id="audio" class="mb-4 mt-4">
<audio controls>
<source src="{{ parent_path }}static/audio/{{ content_item.audio_file }}" type="audio/mpeg">
Your browser does not support the audio element.
</audio>
</div>
{% endif %}
<div id="categories"> <div id="categories">
{% for category in content_item.categories %} {% for category in content_item.categories %}
<a href="{{ parent_path }}categories/{{ category }}.html" class="mx-1 text-decoration-none small text-muted">{{ category }} </a> <a href="{{ parent_path }}categories/{{ category }}.html" class="mx-1 text-decoration-none small text-muted">{{ category }} </a>

View File

@@ -18,7 +18,7 @@
<div id= "top_header" class="row top_header"> <div id= "top_header" class="row top_header">
<img id="top_header_image" src="{{ parent_path }}static/images/header.jpg" class="img-fluid"> <img id="top_header_image" src="{{ parent_path }}static/images/header.jpg" class="img-fluid">
<div id="top_title" class="row"> <div id="top_title" class="row">
<a class="top_header_text">{{ page_title }}</a> <a class="top_header_text ms-1 text-decoration-none">{{ page_title }}</a>
</div> </div>
</div> </div>
<div id="menu_container" class="row justify-content-end pe-2 py-2" > <div id="menu_container" class="row justify-content-end pe-2 py-2" >

View File

@@ -1,10 +1,5 @@
{% extends "default.html" %} {% extends "default.html" %}
{% block head_includes %}
{% endblock %}
{% block content %} {% block content %}
<div class="row justify-content-center g-4 mb-4 py-4"> <div class="row justify-content-center g-4 mb-4 py-4">
{% for content_item in content_items %} {% for content_item in content_items %}