redirecter for ao3 that adds opengraph metadata
1import { getSeries, getUser, getWork } from "@fujocoded/ao3.js"
2import { Hono } from "hono"
3import PageSkeleton from "./pages/PageSkeleton.jsx"
4import Home from "./pages/Home.jsx"
5import Image from "./pages/Image.jsx"
6import Generator from "./pages/Generator.jsx"
7import { render } from 'hono/jsx/dom'
8
9const app = new Hono()
10
11app.get("/", (c) => {
12 return c.html(<Home />)
13})
14
15app.get("/generator", (c) => {
16 const appRoot = document.getElementById('app')
17 render(<Generator />)
18})
19
20app.get("/works/:workId", async (c) => {
21 const workId = c.req.param("workId")
22 const work = await getWork({
23 workId: c.req.param("workId"),
24 chapterId: c.req.param("chapterId"),
25 })
26 const authorsFormatted = work.authors.map((a) => {
27 if (a.anonymous) return "Anonymous"
28 if (a.pseud !== a.username) return `${a.pseud} (${a.username})`
29 return a.username
30 })
31 const authors = authorsFormatted.length > 1
32 ? authorsFormatted.slice(0, -1).join(", ") + " & " +
33 authorsFormatted.slice(-1)
34 : authorsFormatted[0]
35 const title = `${work.title} by ${authors} - ${work.fandoms.join(", ")}`
36 const desc = `Rating: ${work.rating} | ${work.category} | Updated ${
37 work.updatedAt ? work.updatedAt : work.publishedAt
38 } | Words: ${work.words} | ${
39 work.complete ? "Complete | " : ""
40 } ${work.summary}`
41 return c.html(
42 <PageSkeleton title={title} description={desc} addr={`works/${workId}`} />,
43 )
44})
45
46app.get("/works/:workId/chapters/:chapterId", async (c) => {
47 const workId = c.req.param("workId")
48 const chapterId = c.req.param("chapterId")
49 const work = await getWork({
50 workId: c.req.param("workId"),
51 chapterId: c.req.param("chapterId"),
52 })
53 const authorsFormatted = work.authors.map((a) => {
54 if (a.anonymous) return "Anonymous"
55 if (a.pseud !== a.username) return `${a.pseud} (${a.username})`
56 return a.username
57 })
58 const authors = authorsFormatted.length > 1
59 ? authorsFormatted.slice(0, -1).join(", ") + " & " +
60 authorsFormatted.slice(-1)
61 : authorsFormatted[0]
62 const title =
63 `${work.title} by ${authors}, Chapter ${work.chapterInfo.index}${
64 work.chapterInfo.name ? `: ${work.chapterInfo.name}` : ""
65 } - ${work.fandoms.join(", ")}`
66 const desc = `Rating: ${work.rating} | ${work.category} | Updated ${
67 work.updatedAt ? work.updatedAt : work.publishedAt
68 } | Words: ${work.words} | ${work.complete ? "Complete | " : ""} ${
69 work.chapterInfo.summary ? work.chapterInfo.summary : work.summary
70 }`
71 return c.html(
72 <PageSkeleton
73 title={title}
74 description={desc}
75 addr={`works/${workId}/chapters/${chapterId}`}
76 />,
77 )
78})
79
80app.get("/series/:seriesId", async (c) => {
81 const seriesId = c.req.param("seriesId")
82 const series = await getSeries({ seriesId: seriesId })
83 const authorsFormatted = series.authors.map((a) => {
84 if (a.anonymous) return "Anonymous"
85 if (a.pseud !== a.username) return `${a.pseud} (${a.username})`
86 return a.username
87 })
88 const authors = authorsFormatted.length > 1
89 ? authorsFormatted.slice(0, -1).join(", ") + " & " +
90 authorsFormatted.slice(-1)
91 : authorsFormatted[0]
92 const title = `${series.name} by ${authors}`
93 const desc = ` Updated ${
94 series.updatedAt ? series.updatedAt : series.publishedAt
95 } | Works: ${series.worksCount} | ${
96 series.complete ? "Complete | " : ""
97 } ${series.notes}`
98 return c.html(
99 <PageSkeleton
100 title={title}
101 description={desc}
102 addr={`series/${seriesId}`}
103 />,
104 )
105})
106
107app.get("/users/:username", async (c) => {
108 const username = c.req.param("username")
109 const user = await getUser({ username: username })
110 return c.html(
111 <PageSkeleton
112 title={`${username}`}
113 description={user.header}
114 addr={`users/${username}`}
115 />,
116 )
117})
118
119app.get("/users/:username/pseuds/:pseud", async (c) => {
120 const username = c.req.param("username")
121 const pseud = c.req.param("pseud")
122 const user = await getUser({ username: username })
123 return c.html(
124 <PageSkeleton
125 title={`${pseud} (${username})`}
126 description={user.header}
127 addr={`users/${username}`}
128 />,
129 )
130})
131
132app.get("/preview/works/:workId", async (c) => {
133 const workId = c.req.param("workId")
134 const work = await getWork({
135 workId: workId,
136 })
137 const addr = `works/${workId}`
138 return Image({ data: work, addr: addr })
139})
140
141app.get("/preview/works/:workId/chapters/:chapterId", async (c) => {
142 const workId = c.req.param("workId")
143 const chapterId = c.req.param("chapterId")
144 const work = await getWork({
145 workId: workId,
146 chapterId: chapterId,
147 })
148 const addr = `works/${workId}/chapters/${chapterId}`
149 return Image({ data: work, addr: addr })
150})
151
152export default app