111 lines
3.3 KiB
Python
111 lines
3.3 KiB
Python
from os import getenv
|
||
from urllib.parse import urljoin
|
||
from html import unescape
|
||
from textwrap import wrap as text_wrap
|
||
|
||
import pituophis
|
||
from pituophis import Item, Request
|
||
from requests import get
|
||
from parse import parse
|
||
from bs4 import BeautifulSoup
|
||
|
||
wordpress_url = getenv("URL")
|
||
|
||
handlers = {}
|
||
formatters = {}
|
||
|
||
def wrap(text):
|
||
return "\n".join(text_wrap(text, width=int(getenv("WIDTH", 80))))
|
||
|
||
def excise_special_characters(text):
|
||
# TODO: Actually use .encode("ascii", "excise_special_characters") and register a custom handler
|
||
for char, replacement in {
|
||
"“": '"',
|
||
"’": "'",
|
||
"”": '"',
|
||
"w": "w",
|
||
}.items():
|
||
text = text.replace(char, replacement)
|
||
return text
|
||
|
||
def register_handler(path: str):
|
||
def decorator_handler(func):
|
||
handlers[path] = func
|
||
return func
|
||
return decorator_handler
|
||
|
||
def register_formatter(func):
|
||
formatters[func.__name__] = func
|
||
return func
|
||
|
||
@register_formatter
|
||
def h1(tag):
|
||
return f"\n === {tag.get_text()} === \n"
|
||
|
||
@register_formatter
|
||
def h2(tag):
|
||
return f"\n == {tag.get_text()} == \n"
|
||
|
||
@register_formatter
|
||
def h3(tag):
|
||
return f"\n = {tag.get_text()} = \n"
|
||
|
||
@register_formatter
|
||
def p(tag):
|
||
return tag.get_text()
|
||
|
||
@register_formatter
|
||
def img(tag):
|
||
if "alt" in tag:
|
||
return f"<Image Omitted: {tag['alt']}>"
|
||
return "<Image Omitted (no alt text)>"
|
||
|
||
def format_post(post):
|
||
post = post[0]
|
||
header = f"""
|
||
** {post["title"]} **
|
||
{post["date"]} - {post["author"]}
|
||
"""
|
||
soup = BeautifulSoup(post["content"]["rendered"], features="html.parser")
|
||
tags = soup.find_all(formatters.keys())
|
||
return header + "\n".join(
|
||
wrap(formatters[tag.name](tag))
|
||
for tag in tags
|
||
)
|
||
|
||
@register_handler("/post/{slug}")
|
||
def post(request: Request, slug: str):
|
||
post = get(urljoin(wordpress_url, f"wp-json/wp/v2/posts?slug={slug}")).json()
|
||
return format_post(post)
|
||
|
||
@register_handler("/page/{slug}")
|
||
def post(request: Request, slug: str):
|
||
page = get(urljoin(wordpress_url, f"wp-json/wp/v2/pages?slug={slug}")).json()
|
||
return format_post(page)
|
||
|
||
def format_excerpt(post):
|
||
text = BeautifulSoup(post["excerpt"]["rendered"]).get_text()
|
||
cutoff = text.find("…")
|
||
fudge_factor = 100 # Deal with the weird [html] link generated by the penny toys article
|
||
return wrap(excise_special_characters(text[:cutoff - fudge_factor] + "..."))
|
||
|
||
def handle(request):
|
||
for path, handler in handlers.items():
|
||
parse_result = parse(path, request.path)
|
||
if parse_result is not None:
|
||
return handler(request, **parse_result.named)
|
||
menu = [getenv("HEADER_TEXT")]
|
||
posts = get(urljoin(wordpress_url, "wp-json/wp/v2/posts?filter[posts_per_page]=-1")).json()
|
||
pages = get(urljoin(wordpress_url, "wp-json/wp/v2/pages?filter[posts_per_page]=-1")).json()
|
||
for heading, items, url in (
|
||
("Pages", pages, "/page/"),
|
||
("Posts", posts, "/post/")
|
||
):
|
||
menu.append(f"<==={heading}===>")
|
||
for i, post in enumerate(items):
|
||
menu.append(Item(itype=0, path=f"{url}{post['slug']}", text=unescape(post['title']['rendered']), host=request.host, port=request.port))
|
||
menu.append(format_excerpt(post))
|
||
return menu
|
||
|
||
if __name__ == '__main__':
|
||
pituophis.serve("127.0.0.1", int(getenv("PORT")), handler=handle)
|