personal garden & website
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

208 lines
8.0 KiB

import os
import markdown
import re
from jinja2 import Environment, FileSystemLoader
import yaml
import time
import json
class Website:
def __init__(self, template_dir, public_dir):
self.template_dir_root = template_dir
self.public_dir = public_dir
self.output_dir_root = 'public/articles'
self.env = Environment(loader=FileSystemLoader(self.template_dir_root))
self.pages = []
self.tags = []
self.all_images = []
self.about_meta, self.about_content, self.about_modified_time = self.fetch_page('content', 'about.md')
def build(self):
self.fetch_pages()
self.process_page()
self.fetch_tags()
self.create_list()
self.build_about()
self.fetch_all_images()
self.create_json('public/json/articles.json')
def fetch_pages(self):
for page in os.listdir('content/posts'):
if page.endswith('.md'):
with open(os.path.join('content/posts', page), 'r', encoding="utf8") as f:
content = f.read()
file_desc = f.fileno()
file_status = os.fstat(file_desc)
parts = content.split('---')
metadata = yaml.safe_load(parts[1])
md_content = ''.join(parts[2:])
md_content = re.sub(r'\(([^)]+)\)\[([^\]]+)\]', r'<a href="\2">\1</a>', md_content)
md_content = self.format_content(md_content)
html_content = markdown.markdown(md_content)
output_filename = os.path.splitext(page)[0] + '.html'
new_page = Page(metadata, html_content, output_filename, file_status)
self.pages.append(new_page)
def process_page(self):
template = self.env.get_template('article.html')
self.check_output_dir()
for page in self.pages:
metadata = page.get_metadata()
filename = page.get_filename()
html_content = page.get_content()
html_output = template.render(
title=metadata.get('title', ''),
year=metadata.get('year', ''), # Assuming year is a string
date=metadata.get('date', ''), # Assuming date is a string
tags=metadata.get('tags', []),
image=metadata.get('image', ''), # Assuming image is a string
showcase=metadata.get('showcase', []),
credits=metadata.get('credits', []), # Assuming credits is a string
modified_time=page.get_modified_time_readable(),
content=html_content)
with open(os.path.join(self.output_dir_root, filename), 'w', encoding='utf8') as output_file:
output_file.write(html_output)
def check_output_dir(self):
if not os.path.exists(self.output_dir_root):
os.makedirs(self.output_dir_root)
def fetch_page(self, dir, page):
for about in os.listdir(dir):
if about == page:
with open(os.path.join(dir, about), 'r', encoding='utf8') as f:
content = f.read()
parts = content.split('---')
metadata = yaml.safe_load(parts[1])
md_content = ''.join(parts[2:])
md_content = re.sub(r'\(([^)]+)\)\[([^\]]+)\]', r'<a href="\2" target="_blank">\1</a>', md_content)
html_content = markdown.markdown(md_content)
about_modified_time = time.ctime(os.fstat(f.fileno()).st_mtime)
return metadata, html_content, about_modified_time
def create_list(self):
template = self.env.get_template('list.html')
self.check_output_dir()
html_output = template.render(
tags=self.tags,
pages=self.pages
)
with open(os.path.join('public', 'list.html'), 'w', encoding='utf8') as output_file:
output_file.write(html_output)
def fetch_tags(self):
for page in self.pages:
page_tags = page.get_tags()
for tag in page_tags:
if tag not in self.tags:
self.tags.append(tag)
def build_about(self):
template = self.env.get_template('about.html')
html_output = template.render(
content=self.about_content,
socials=self.about_meta,
modified_time = self.about_modified_time
)
with open(os.path.join('public', 'about.html'), 'w', encoding='utf8') as output_file:
output_file.write(html_output)
def format_content(self, content):
# convert all (link)(src) to <a> tags
content = re.sub(r'\(([^)]+)\)\[([^\]]+)\]', r'<a href="\2" target="_blank">\1</a>', content)
# convert all video links to embedded code
return content
def fetch_all_images(self):
dir = 'public/images'
template = self.env.get_template('gallery.html')
image_extensions = ('.png', '.jpg', '.jpeg', '.gif', '.webp')
for dirpath, _, filename in os.walk(dir):
for filename in filename:
if filename.lower().endswith(image_extensions):
relative_path = os.path.relpath(dirpath, dir).replace("\\", "/")
image_path = os.path.join('/images', relative_path, filename).replace("\\", "/")
if image_path.startswith("/images/."):
image_path = image_path.replace("/images/.", "/images")
self.all_images.append(image_path)
html_output = template.render(
images=self.all_images
)
with open(os.path.join('public', 'gallery.html'), 'w', encoding='utf8') as output_file:
output_file.write(html_output)
def create_json(self, json_file):
page_info_list = []
for page in self.pages:
page_info = {
'name': page.get_title(),
'filename': '/articles/' + page.get_filename(),
'image': page.get_image()
}
page_info_list.append(page_info)
with open(json_file, 'w', encoding='utf8') as f:
json.dump(page_info_list, f, ensure_ascii=False, indent=4)
class Page:
def __init__(self, metadata, md_content, filename, last_updated):
self.metadata = metadata
self.content = md_content
self.filename = filename
self.last_updated = last_updated
self.title = self.metadata['title']
self.type = self.metadata['type']
self.year = self.metadata['year']
self.image_src = self.metadata['image']
self.tags = self.metadata['tags']
self.date = self.metadata['date']
self.showcase = self.metadata.get('showcase', [])
self.credits = self.metadata.get('credits', {})
self.references = self.metadata.get('references', [])
self.isDraft = self.metadata['draft']
def get_metadata(self):
return self.metadata
def get_content(self):
return self.content
def get_filename(self):
return self.filename
def get_title(self):
return self.title
def get_tags(self):
return self.tags
def get_year(self):
return self.year
def get_image(self):
return self.image_src
def get_references(self):
return self.references
def get_src(self):
return os.path.splitext(self.filename)[0]
def display_metadata(self):
output = f"Title: {self.title}\nYear: {self.year}\nDate: {self.date}\nTags: {self.tags}\nType: {self.type}"
print(output)
def get_modified_time_readable(self):
if self.last_updated is not None:
last_modified_time = self.last_updated.st_mtime
last_modified_time_readable = time.ctime(last_modified_time)
return last_modified_time_readable
return None
def main():
inst = Website('templates', 'public')
inst.build()
if __name__ == "__main__":
main()