diff --git a/css/styles.css b/css/styles.css index c7c4e35..9714878 100644 --- a/css/styles.css +++ b/css/styles.css @@ -106,3 +106,33 @@ a { margin-left: auto; margin-right: auto; } + +pre { + background-color: #000000; + color: #cccccc; + border: 1px solid #686bff; + padding: 10px; + overflow: auto; + font-family: "Courier New", Courier, monospace; + font-size: 14px; + margin-bottom: 15px; +} + +pre code { + font-family: "Courier New", Courier, monospace; +} + +.highlighter-rouge { + background-color: #000000; + color: #cccccc; + font-family: "Courier New", Courier, monospace; + padding-left: 3px; + padding-right: 3px; + border: 1px solid #333333; +} + +.kwd { color: #ffff00; font-weight: bold; } /* Keywords: Yellow */ +.str { color: #00ff00; } /* Strings: Green */ +.com { color: #999999; font-style: italic; } /* Comments: Gray */ +.num { color: #ff00ff; } /* Numbers: Magenta */ +.typ { color: #00ffff; } /* Types/Classes: Cyan */ diff --git a/index.html b/index.html index bd6c663..d66ecaf 100644 --- a/index.html +++ b/index.html @@ -1,6 +1,9 @@

Hey you, thanks for passing by, let me introduce myself. I'm a French C/C++/Python/ASM coder who is interested in reverse engineering, Eurobeat music and 90's looking websites.

-

I don't know how you found this website but be free to check my blog where i post random stuff.

+

I don't know how you found this website but be free to + check my blog + where i post random stuff. A rss feed is also available.


I run Arch Linux, Sway and Emacs: my dotfiles.

diff --git a/python_script/generate_article.py b/python_script/generate_article.py index ed20911..b31287c 100644 --- a/python_script/generate_article.py +++ b/python_script/generate_article.py @@ -1,181 +1,361 @@ -""" -~foldername~template~foldername~ -~titre~Test article~titre~ -~date~ Jan 25, 2022~date~ -~section~Test~section~ -~data~data~data~ -~link~[https://www.google.com]link to google~link~ -~list~Test~list~ -~endlist~ -~image~serverlist.png~image~ -""" -#TODO : -# - add code snippet - - import os -from os import listdir -from os.path import isfile, join import shutil -from tkinter import Tk -from tkinter.filedialog import askopenfilename +import datetime +import re +import argparse +import html +import sys -def write_file(text) : - with open("out.html", "a") as o : - o.write(text) +SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__)) +DOMAIN_URL = "https://patate.dev" -def generate_base(title) : - base = """ - -
-

"""+title+"""

-""" - write_file(base) +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")) +} -def generate_date(date) : - base = """ - +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]") - write_file(base) + 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 -def generate_paragraph(p) : - base = "

"+p+"

" - write_file(base) + self.write_html_output() + self.handle_images() + self.update_blog_index() + self.update_rss() + self.update_sitemap() + print("Done!") -def generate_section(s) : - s_2 = s.replace(" ","-") - base = ''' -

- '''+s+''' -

-''' - write_file(base) + 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 generate_end_file() : - base = ''' -

- - - ''' - - write_file(base) + 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) -def generate_image(path) : - base = ''' -

- -

-''' - write_file(base) + 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) -def set_foldername(name) : - try : os.mkdir("../images/"+name) - except: pass - onlyfiles = [f for f in listdir(".") if isfile(join(".", f))] - for f in onlyfiles : - if f.endswith(".jpg") or f.endswith(".jpeg") or f.endswith(".png") or f.endswith(".ico") or f.endswith(".gif") : - shutil.copy(f, "../images/"+name+"/"+f) + code = re.sub(r'\b(0x[0-9a-fA-F]+|\d+)\b(?![^<]*>)', r'\1', code) + return code -def main() : - Tk().withdraw() # we don't want a full GUI, so keep the root window from appearing - filename = askopenfilename() # show an "Open" dialog box and return the path to the selected file + 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 - name = "" - titre = "" - date = "" - was_list = False - with open(filename, "r") as a : - for line in a.readlines() : - - if line.startswith("~foldername~") : - final_line = line.replace("~foldername~","").strip() - name = final_line - set_foldername(final_line) + 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"" - elif line.startswith("~titre~") : - final_line = line.replace("~titre~","").strip() - titre = final_line - generate_base(final_line) + def parse_file(self): + with open(self.filepath, "r", encoding="utf-8") as f: + lines = f.readlines() - elif line.startswith("~date~") : - final_line = line.replace("~date~","").strip() - date = " " + final_line - generate_date(final_line) + is_list = False + in_code_block = False + code_buffer = [] + html_buffer = [] - elif line.startswith("~section~") : - final_line = line.replace("~section~","").strip() - generate_section(final_line) - - elif line.startswith("~image~") : - final_line = line.replace("~image~","").strip() - final_line = "../images/"+name+"/" + final_line - generate_image(final_line) + header_content = self.get_template_content(PATHS["header"]) + html_buffer.append(header_content) + + html_buffer.append('
') - else : - if line.startswith("~endlist~"): - was_list = False - write_file("") - continue - - if line.startswith("~list~") : - l = line.split("~list~") - res = "" - - if not was_list : - res += "") + is_list = False + + processed_line = self.process_inline_tags(line) + html_buffer.append(f"

{processed_line}

") + + html_buffer.append('
') + + footer_content = self.get_template_content(PATHS["footer"]) + html_buffer.append(footer_content) + + if "" not in footer_content: + html_buffer.append('') + if "" not in footer_content: + html_buffer.append('') + + self.content_lines = html_buffer + + def write_html_output(self): + output_path = os.path.join(PATHS["pages"], self.metadata["filename_html"]) + with open(output_path, "w", encoding="utf-8") as f: + f.write("\n".join(self.content_lines)) + print(f"Generated page: {output_path}") + + def handle_images(self): + target_dir = os.path.join(PATHS["images_dest"], self.metadata["foldername"]) + if not os.path.exists(target_dir): + os.makedirs(target_dir) + + source_dir = os.path.dirname(os.path.abspath(self.filepath)) + + for f in os.listdir(source_dir): + if f.lower().endswith(('.png', '.jpg', '.jpeg', '.gif', '.ico')): + shutil.copy(os.path.join(source_dir, f), os.path.join(target_dir, f)) + + def update_blog_index(self): + marker = "" + entry = f'\t\t
  • {self.metadata["title"]}
  • ' + + print(f"Updating {PATHS['blog_index']}...") + + try: + with open(PATHS["blog_index"], "r", encoding="utf-8") as f: + content = f.read() + + if self.metadata["filename_html"] in content and self.metadata["title"] in content: + print("Link already exists in blog.html. Skipping index update.") + return + + marker_index = content.find(marker) + if marker_index == -1: + print(f"Warning: '{marker}' marker not found in blog.html") + return + + ul_start_index = content.find("