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