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