1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
|
import os
import pathlib
import random
import tomllib
from pathlib import Path
from typing import TypedDict
from xml.etree import ElementTree
from robyn import Request, Response, Robyn
from robyn.templating import JinjaTemplate
User = TypedDict("User", {"name": str, "url": str, "description": str, "feed": str})
def load_users(path: Path) -> list[User]:
with path.open("rb") as f:
return tomllib.load(f)["user"]
current_file_path = pathlib.Path(__file__).parent.resolve()
users = load_users(current_file_path / "config.toml")
app = Robyn(__file__)
app.serve_directory(
route="/static",
directory_path=os.path.join(current_file_path, "static"),
)
JINJA_TEMPLATE = JinjaTemplate(os.path.join(current_file_path, "templates"))
def index_of(request: Request) -> int:
name = request.query_params.get("from", "")
for i, user in enumerate(users):
if user["name"] == name:
return i
return 0
def redirect(url: str) -> Response:
return Response(status_code=302, headers={"Location": url}, description="")
@app.get("/")
async def index(_request: Request):
return JINJA_TEMPLATE.render_template("index.html", users=users)
@app.get("/next")
async def next_user(request: Request):
current = index_of(request)
next_index = (current + 1) % len(users)
return redirect(users[next_index]["url"])
@app.get("/prev")
async def prev_user(request: Request):
current = index_of(request)
prev_index = (current - 1) % len(users)
return redirect(users[prev_index]["url"])
@app.get("/random")
async def random_user(_request: Request):
return redirect(random.choice(users)["url"])
@app.get("/feed.opml")
async def opml(_request: Request) -> Response:
return Response(
status_code=200,
headers={"Content-Type": "text/x-opml"},
description=build_opml(),
)
def build_opml() -> str:
opml = ElementTree.Element("opml", version="2.0")
head = ElementTree.SubElement(opml, "head")
ElementTree.SubElement(head, "title").text = "Technical Renaissance Webring"
body = ElementTree.SubElement(opml, "body")
for user in users:
if user["feed"]:
ElementTree.SubElement(
body,
"outline",
text=user["name"],
type="rss",
xmlUrl=user["feed"],
htmlUrl=user["url"],
)
return ElementTree.tostring(opml, encoding="unicode", xml_declaration=True)
def main() -> None:
host = os.environ.get("HOST", "127.0.0.1")
port = int(os.environ.get("PORT", "8080"))
app.start(host=host, port=port)
if __name__ == "__main__":
main()
|