From 8d13297cb0b7407ec854a5fdfab2b0b882688cab Mon Sep 17 00:00:00 2001 From: Nathan Woodburn Date: Wed, 25 Jun 2025 14:38:07 +1000 Subject: [PATCH] feat: Update blog rendering --- blog.py | 46 ++++++++++++++++++++++++++++++++++++++++-- data/resume.pdf | Bin 713148 -> 713145 bytes requirements.txt | 3 ++- server.py | 6 +++--- templates/resume.html | 2 +- 5 files changed, 50 insertions(+), 7 deletions(-) diff --git a/blog.py b/blog.py index 13ed6df..ea6302c 100644 --- a/blog.py +++ b/blog.py @@ -4,6 +4,8 @@ from datetime import datetime import markdown from markdown.extensions.codehilite import CodeHiliteExtension from markdown.extensions.fenced_code import FencedCodeExtension +from bs4 import BeautifulSoup +import re def list_blog_page_files(): @@ -22,12 +24,16 @@ def render_blog_page(date,handshake_scripts=None): with open(f"data/blog/{date}.md", "r") as f: content = f.read() # Get the title from the file name - title = date.removesuffix(".md").replace("_", " ").title() + title = date.removesuffix(".md").replace("_", " ") # Convert the md to html content = markdown.markdown(content, extensions=['sane_lists', 'codehilite', 'fenced_code']) # Add target="_blank" to all links content = content.replace(' tag containing numbered steps + paragraphs = soup.find_all('p') + for p in paragraphs: + content = p.decode_contents() + + # Check for likely numbered step structure + if re.search(r'1\.\s', content): + # Split into pre-list and numbered steps + # Match:
, optional whitespace, then a number and dot + parts = re.split(r'(?:)?\s*(\d+)\.\s', content) + + # Result: [pre-text, '1', step1, '2', step2, ..., '10', step10] + pre_text = parts[0].strip() + steps = parts[1:] + + # Assemble the ordered list + ol_items = [] + for i in range(0, len(steps), 2): + if i+1 < len(steps): + step_html = steps[i+1].strip() + ol_items.append(f"
  • {step_html}
  • ") + + # Build the final list HTML + ol_html = "
      \n" + "\n".join(ol_items) + "\n
    " + + # Rebuild paragraph with optional pre-text + new_html = f"{pre_text}
    \n{ol_html}" if pre_text else ol_html + + # Replace old

    with parsed version + new_fragment = BeautifulSoup(new_html, 'html.parser') + p.replace_with(new_fragment) + break # Only process the first matching

    + + return str(soup) def render_blog_home(handshake_scripts=None): diff --git a/data/resume.pdf b/data/resume.pdf index e6c02b6a968280a4fa04fb367e5943e29ce3b75c..438dd45449ffb0a8947f4cd1551eec931e3cc56c 100644 GIT binary patch delta 14561 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 aKo|hf5GZ)u%}H_`~+Z diff --git a/requirements.txt b/requirements.txt index a862d58..2dbd6c4 100644 --- a/requirements.txt +++ b/requirements.txt @@ -13,4 +13,5 @@ solana solders weasyprint markdown -pygments \ No newline at end of file +pygments +beautifulsoup4 \ No newline at end of file diff --git a/server.py b/server.py index 5427250..c315cea 100644 --- a/server.py +++ b/server.py @@ -589,9 +589,9 @@ def index(): print("Error getting git data") # Get only repo names for the newest updates - if projects == [] or projectsUpdated < datetime.datetime.now() - datetime.timedelta( + if projects == [] or projectsUpdated < (datetime.datetime.now() - datetime.timedelta( hours=2 - ): + )).timestamp(): projectsreq = requests.get( "https://git.woodburn.au/api/v1/users/nathanwoodburn/repos" ) @@ -625,7 +625,7 @@ def index(): projects.append(projectsList[projectNum]) projectNames.append(projectsList[projectNum]["name"]) projectNum += 1 - projectsUpdated = datetime.datetime.now() + projectsUpdated = datetime.datetime.now().timestamp() custom = "" # Check for downtime diff --git a/templates/resume.html b/templates/resume.html index 94a3178..0df2a45 100644 --- a/templates/resume.html +++ b/templates/resume.html @@ -130,9 +130,9 @@

    Home Educated

    Self-Directed Learning
      +
    • Cultivated time management, self-discipline, and critical thinking skills crucial for success in tech and cybersecurity.
    • Developed a strong passion for technology, programming, and system administration through independent exploration.
    • Built custom applications, managed servers, and solved technical challenges in a flexible learning environment.
    • -
    • Cultivated time management, self-discipline, and critical thinking skills crucial for success in tech and cybersecurity.