235 lines
7.9 KiB
Python
235 lines
7.9 KiB
Python
from flask import Blueprint, render_template, make_response, request, jsonify
|
|
import datetime
|
|
import os
|
|
from functools import lru_cache
|
|
from tools import getHandshakeScript, error_response, isCLI
|
|
from curl import get_header, MAX_WIDTH
|
|
from bs4 import BeautifulSoup
|
|
import re
|
|
|
|
# Create blueprint
|
|
app = Blueprint("now", __name__, url_prefix="/")
|
|
|
|
|
|
@lru_cache(maxsize=16)
|
|
def list_page_files():
|
|
now_pages = os.listdir("templates/now")
|
|
now_pages = [
|
|
page for page in now_pages if page != "template.html" and page != "old.html"
|
|
]
|
|
now_pages.sort(reverse=True)
|
|
return now_pages
|
|
|
|
|
|
@lru_cache(maxsize=16)
|
|
def list_dates():
|
|
now_pages = list_page_files()
|
|
now_dates = [page.split(".")[0] for page in now_pages]
|
|
return now_dates
|
|
|
|
|
|
@lru_cache(maxsize=8)
|
|
def get_latest_date(formatted=False):
|
|
if formatted:
|
|
date = list_dates()[0]
|
|
date = datetime.datetime.strptime(date, "%y_%m_%d")
|
|
date = date.strftime("%A, %B %d, %Y")
|
|
return date
|
|
return list_dates()[0]
|
|
|
|
|
|
def render_latest(handshake_scripts=None):
|
|
now_page = list_dates()[0]
|
|
return render(now_page, handshake_scripts=handshake_scripts)
|
|
|
|
|
|
def render(date, handshake_scripts=None):
|
|
# If the date is not available, render the latest page
|
|
if date is None:
|
|
return render_latest(handshake_scripts=handshake_scripts)
|
|
# Remove .html
|
|
date = date.removesuffix(".html")
|
|
|
|
if date not in list_dates():
|
|
return error_response(request)
|
|
|
|
date_formatted = datetime.datetime.strptime(date, "%y_%m_%d")
|
|
date_formatted = date_formatted.strftime("%A, %B %d, %Y")
|
|
return render_template(
|
|
f"now/{date}.html", DATE=date_formatted, handshake_scripts=handshake_scripts
|
|
)
|
|
|
|
|
|
def render_curl(date=None):
|
|
# If the date is not available, render the latest page
|
|
if date is None:
|
|
date = get_latest_date()
|
|
|
|
# Remove .html if present
|
|
date = date.removesuffix(".html")
|
|
|
|
if date not in list_dates():
|
|
return error_response(request)
|
|
|
|
# Format the date nicely
|
|
date_formatted = datetime.datetime.strptime(date, "%y_%m_%d")
|
|
date_formatted = date_formatted.strftime("%A, %B %d, %Y")
|
|
|
|
# Load HTML
|
|
with open(f"templates/now/{date}.html", "r", encoding="utf-8") as f:
|
|
raw_html = f.read().replace("{{ date }}", date_formatted)
|
|
soup = BeautifulSoup(raw_html, "html.parser")
|
|
|
|
posts = []
|
|
|
|
# Find divs matching your pattern
|
|
divs = soup.find_all("div", style=re.compile(r"max-width:\s*700px", re.IGNORECASE))
|
|
if not divs:
|
|
return error_response(request, message="No content found for CLI rendering.")
|
|
|
|
for div in divs:
|
|
# header could be h1/h2/h3 inside the div
|
|
header_tag = div.find(["h1", "h2", "h3"]) # type: ignore
|
|
# content is usually one or more <p> tags inside the div
|
|
p_tags = div.find_all("p") # type: ignore
|
|
|
|
if header_tag and p_tags:
|
|
header_text = header_tag.get_text(strip=True) # type: ignore
|
|
content_lines = []
|
|
|
|
for p in p_tags:
|
|
# Extract text
|
|
text = p.get_text(strip=False)
|
|
|
|
# Extract any <a> links in the paragraph
|
|
links = [a.get("href") for a in p.find_all("a", href=True)] # type: ignore
|
|
# Set max width for text wrapping
|
|
|
|
# Wrap text manually
|
|
wrapped_lines = []
|
|
for line in text.splitlines():
|
|
while len(line) > MAX_WIDTH:
|
|
# Find last space within max_width
|
|
split_at = line.rfind(" ", 0, MAX_WIDTH)
|
|
if split_at == -1:
|
|
split_at = MAX_WIDTH
|
|
wrapped_lines.append(line[:split_at].rstrip())
|
|
line = line[split_at:].lstrip()
|
|
wrapped_lines.append(line)
|
|
text = "\n".join(wrapped_lines)
|
|
|
|
if links:
|
|
text += "\nLinks: " + ", ".join(links) # type: ignore
|
|
|
|
content_lines.append(text)
|
|
|
|
content_text = "\n\n".join(content_lines)
|
|
posts.append({"header": header_text, "content": content_text})
|
|
|
|
# Build final response
|
|
response = ""
|
|
for post in posts:
|
|
response += f"[1m{post['header']}[0m\n\n{post['content']}\n\n"
|
|
|
|
return render_template(
|
|
"now.ascii", date=date_formatted, content=response, header=get_header()
|
|
)
|
|
|
|
|
|
@app.route("/now", strict_slashes=False)
|
|
def index():
|
|
if isCLI(request):
|
|
return render_curl()
|
|
return render_latest(handshake_scripts=getHandshakeScript(request.host))
|
|
|
|
|
|
@app.route("/now/<path:path>")
|
|
def path(path):
|
|
if isCLI(request):
|
|
return render_curl(path)
|
|
|
|
return render(path, handshake_scripts=getHandshakeScript(request.host))
|
|
|
|
|
|
@app.route("/now/old", strict_slashes=False)
|
|
@app.route("/old", strict_slashes=False)
|
|
def old():
|
|
now_dates = list_dates()[1:]
|
|
if isCLI(request):
|
|
response = ""
|
|
for date in now_dates:
|
|
link = date
|
|
date_fmt = datetime.datetime.strptime(date, "%y_%m_%d")
|
|
date_fmt = date_fmt.strftime("%A, %B %d, %Y")
|
|
response += f"{date_fmt} - /now/{link}\n"
|
|
return render_template(
|
|
"now.ascii", date="Old Now Pages", content=response, header=get_header()
|
|
)
|
|
|
|
html = '<ul class="list-group">'
|
|
html += f'<a style="text-decoration:none;" href="/now"><li class="list-group-item" style="background-color:#000000;color:#ffffff;">{get_latest_date(True)}</li></a>'
|
|
|
|
for date in now_dates:
|
|
link = date
|
|
date = datetime.datetime.strptime(date, "%y_%m_%d")
|
|
date = date.strftime("%A, %B %d, %Y")
|
|
html += f'<a style="text-decoration:none;" href="/now/{link}"><li class="list-group-item" style="background-color:#000000;color:#ffffff;">{date}</li></a>'
|
|
|
|
html += "</ul>"
|
|
return render_template(
|
|
"now/old.html",
|
|
handshake_scripts=getHandshakeScript(request.host),
|
|
now_pages=html,
|
|
)
|
|
|
|
|
|
@app.route("/now.rss")
|
|
@app.route("/now.xml")
|
|
@app.route("/rss.xml")
|
|
def rss():
|
|
host = "https://" + request.host
|
|
path = request.path
|
|
if ":" in request.host:
|
|
host = "http://" + request.host
|
|
# Generate RSS feed
|
|
now_pages = list_page_files()
|
|
rss = f'<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Nathan.Woodburn/</title><link>{host}</link><description>See what I\'ve been up to</description><language>en-us</language><lastBuildDate>{datetime.datetime.now(tz=datetime.timezone.utc).strftime("%a, %d %b %Y %H:%M:%S %z")}</lastBuildDate><atom:link href="{host}{path}" rel="self" type="application/rss+xml" />'
|
|
for page in now_pages:
|
|
link = page.strip(".html")
|
|
date = datetime.datetime.strptime(link, "%y_%m_%d")
|
|
pubdate = date.strftime("%a, %d %b %Y 00:00:00 +0000")
|
|
date = date.strftime("%A, %B %d, %Y")
|
|
rss += f"""
|
|
<item>
|
|
<title>What's Happening {date}</title>
|
|
<link>{host}/now/{link}</link>
|
|
<description>Latest updates for {date}</description>
|
|
<pubDate>{pubdate}</pubDate>
|
|
<guid isPermaLink="true">{host}/now/{link}</guid>
|
|
</item>
|
|
"""
|
|
rss += "</channel></rss>"
|
|
return make_response(rss, 200, {"Content-Type": "application/rss+xml"})
|
|
|
|
|
|
@app.route("/now.json")
|
|
def json():
|
|
now_pages = list_page_files()
|
|
host = "https://" + request.host
|
|
if ":" in request.host:
|
|
host = "http://" + request.host
|
|
now_pages = [
|
|
{
|
|
"url": host + "/now/" + page.strip(".html"),
|
|
"date": datetime.datetime.strptime(
|
|
page.strip(".html"), "%y_%m_%d"
|
|
).strftime("%A, %B %d, %Y"),
|
|
"title": "What's Happening "
|
|
+ datetime.datetime.strptime(page.strip(".html"), "%y_%m_%d").strftime(
|
|
"%A, %B %d, %Y"
|
|
),
|
|
}
|
|
for page in now_pages
|
|
]
|
|
return jsonify(now_pages)
|