|
|
|
import os
|
|
|
|
import random
|
|
|
|
import markdown
|
|
|
|
import re
|
|
|
|
from jinja2 import Environment, FileSystemLoader
|
|
|
|
import yaml
|
|
|
|
import time
|
|
|
|
import json
|
|
|
|
from datetime import datetime
|
|
|
|
|
|
|
|
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.sort_pages_by_date()
|
|
|
|
self.process_page()
|
|
|
|
self.fetch_tags()
|
|
|
|
self.create_list()
|
|
|
|
self.build_about()
|
|
|
|
self.build_campfire()
|
|
|
|
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 build_campfire(self):
|
|
|
|
template = self.env.get_template('campfire.html')
|
|
|
|
html_output = template.render(
|
|
|
|
content=None
|
|
|
|
)
|
|
|
|
|
|
|
|
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)
|
|
|
|
random.shuffle(self.all_images)
|
|
|
|
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)
|
|
|
|
|
|
|
|
def sort_pages_by_date(self):
|
|
|
|
# Sort pages by date in descending order (newest first)
|
|
|
|
self.pages.sort(key=lambda x: x.date, reverse=True)
|
|
|
|
|
|
|
|
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()
|