import os
import shutil
import datetime
import re
import argparse
import html
import sys
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
DOMAIN_URL = "https://patate.dev"
PATHS = {
"images_src": SCRIPT_DIR,
"images_dest": os.path.abspath(os.path.join(SCRIPT_DIR, "../images")),
"pages": os.path.abspath(os.path.join(SCRIPT_DIR, "../pages")),
"rss": os.path.abspath(os.path.join(SCRIPT_DIR, "../rss")),
"sitemap": os.path.abspath(os.path.join(SCRIPT_DIR, "../sitemap.xml")),
"blog_index": os.path.abspath(os.path.join(SCRIPT_DIR, "../pages/blog.html")),
"header": os.path.abspath(os.path.join(SCRIPT_DIR, "../pages/header.html")),
"footer": os.path.abspath(os.path.join(SCRIPT_DIR, "../pages/footer.html"))
}
class BlogGenerator:
def __init__(self, filepath):
self.filepath = filepath
self.filename = os.path.basename(filepath)
self.content_lines = []
self.metadata = {
"foldername": "",
"title": "",
"description": "",
"date_str": "",
"date_obj": None,
"filename_html": ""
}
def run(self):
print(f"Processing {self.filename}...")
if not os.path.exists(PATHS["header"]):
print(f"CRITICAL ERROR: header.html not found at {PATHS['header']}")
return
self.parse_file()
missing_fields = []
if not self.metadata["foldername"]: missing_fields.append("[foldername]")
if not self.metadata["title"]: missing_fields.append("[title]")
if not self.metadata["description"]: missing_fields.append("[description]")
if not self.metadata["date_str"]: missing_fields.append("[date]")
if missing_fields:
print("Error: The following mandatory fields are missing from your text file:")
for field in missing_fields:
print(f" - {field}")
print("Aborting generation.")
return
self.write_html_output()
self.handle_images()
self.update_blog_index()
self.update_rss()
self.update_sitemap()
print("Done!")
def parse_date(self, date_str):
clean_date = date_str.strip()
try:
return datetime.datetime.strptime(clean_date, "%b %d, %Y")
except ValueError:
print(f"Warning: Could not parse date '{clean_date}'. Defaulting to NOW.")
return datetime.datetime.now()
def highlight_code(self, code):
"""Simple regex-based syntax highlighter for C/C++/Python/Rust."""
code = html.escape(code)
code = re.sub(r'(".*?")', r'\1', code)
code = re.sub(r"('.*?')", r'\1', code)
code = re.sub(r'(//.*)', r'\1', code)
code = re.sub(r'(#.*)', r'\1', code)
keywords = [
"int", "void", "char", "float", "double", "struct", "class",
"if", "else", "while", "for", "return", "switch", "case", "break",
"def", "import", "from", "fn", "let", "mut", "pub", "impl", "use",
"const", "static", "unsigned", "long", "true", "false", "NULL", "nullptr"
]
for kw in keywords:
pattern = r'\b(' + kw + r')\b(?![^<]*>)'
code = re.sub(pattern, r'\1', code)
code = re.sub(r'\b(0x[0-9a-fA-F]+|\d+)\b(?![^<]*>)', r'\1', code)
return code
def process_inline_tags(self, text):
text = re.sub(r'\[data\](.*?)\[data\]',
r'\1', text)
def replace_link(match):
url = match.group(1)
label = match.group(2)
return f'{label}'
text = re.sub(r'\[link\]\[(.*?)\](.*?)\[link\]', replace_link, text)
return text
def get_template_content(self, path):
if os.path.exists(path):
with open(path, "r", encoding="utf-8") as f:
return f.read()
else:
print(f"Warning: Template file not found at {path}")
return f""
def parse_file(self):
with open(self.filepath, "r", encoding="utf-8") as f:
lines = f.readlines()
is_list = False
in_code_block = False
code_buffer = []
html_buffer = []
header_content = self.get_template_content(PATHS["header"])
html_buffer.append(header_content)
html_buffer.append('')
for line in lines:
if line.strip().startswith("[code]"):
if in_code_block:
raw_code = "".join(code_buffer).strip()
highlighted_code = self.highlight_code(raw_code)
html_buffer.append(f'
{highlighted_code}
')
code_buffer = []
in_code_block = False
else:
in_code_block = True
continue
if in_code_block:
code_buffer.append(line)
continue
line = line.strip()
if not line: continue
if line.startswith("[foldername]"):
val = line.replace("[foldername]", "").strip()
self.metadata["foldername"] = val
self.metadata["filename_html"] = val + ".html"
elif line.startswith("[title]"):
val = line.replace("[title]", "").strip()
self.metadata["title"] = val
html_buffer.append(f'
{val}
')
elif line.startswith("[description]"):
val = line.replace("[description]", "").strip()
self.metadata["description"] = val
elif line.startswith("[date]"):
val = line.replace("[date]", "").strip()
self.metadata["date_str"] = val
self.metadata["date_obj"] = self.parse_date(val)
html_buffer.append(f'')
html_buffer.append('')
elif line.startswith("[section]"):
val = line.replace("[section]", "").strip()
anchor = val.replace(" ", "-")
html_buffer.append(f'