redirecter for ao3 that adds opengraph metadata
1import { getWork } from "@fujocoded/ao3.js"
2import DOM from "fauxdom"
3import { readFile } from 'node:fs/promises'
4import { join } from 'node:path'
5import themes from '@/lib/themes.js'
6import baseFonts from '@/lib/baseFonts.js'
7import titleFonts from '@/lib/titleFonts.js'
8
9export default async function sanitizeData ({ type, data, props}) {
10 const baseFont = props.has('baseFont') ? props.get('baseFont') : process.env.DEFAULT_BASE_FONT
11 const baseFontData = baseFonts[baseFont]
12 const titleFont = props.has('titleFont') ? props.get('titleFont') : process.env.DEFAULT_TITLE_FONT
13 const titleFontData = titleFonts[titleFont]
14 const themeData = props.has('theme') ? themes[props.get('theme')] : themes[process.env.DEFAULT_THEME]
15 const parentWork = type === 'work' && data.chapterInfo ? await getWork({workId: data.id}) : null
16 const bfs = await Promise.all(baseFontData.defs.map(async (bf) => {
17 return {
18 name: baseFontData.displayName,
19 data: await readFile(
20 join(process.cwd(), bf.path)
21 ),
22 style: bf.style,
23 weight: bf.weight
24 }
25 })).then(x => x)
26 const tfs = await Promise.all(titleFontData.defs.map(async (tf) => {
27 return {
28 name: titleFontData.displayName,
29 data: await readFile(
30 join(process.cwd(), tf.path)
31 ),
32 style: tf.style,
33 weight: tf.weight
34 }
35 })).then(x => x)
36 const authorsFormatted = data.authors
37 ? data.authors.map((a) => {
38 if (a.anonymous) return "Anonymous"
39 if (a.pseud !== a.username) return `${a.pseud} (${a.username})`
40 return a.username
41 })
42 : []
43 const authorString = authorsFormatted.length > 1
44 ? authorsFormatted.slice(0, -1).join(", ") + " & " +
45 authorsFormatted.slice(-1)[0]
46 : authorsFormatted[0]
47 const summaryContent = type === 'work'
48 ? (props.get('summaryType') === 'chapter' && data.chapterInfo && data.chapterInfo.summary ? data.chapterInfo.summary : (props.get('summaryType') === 'custom' && props.has('customSummary') ? props.get('customSummary') : (data.summary ? data.summary : (parentWork ? parentWork.summary : ''))))
49 : (props.get('summaryType') === 'custom' && props.has('customSummary') ? props.get('customSummary') : data.notes)
50 const summaryDOM = new DOM(summaryContent, {decodeEntities: true});
51 const summaryFormatted = summaryDOM.innerHTML.replace(/\<br(?: \/)?\>/g, "\n").replace(
52 /(<([^>]+)>)/ig,
53 "",
54 ).split("\n")
55 const titleString = type === 'work' ? data.title : data.name
56 const chapterString = data.chapterInfo ? (data.chapterInfo.name
57 ? data.chapterInfo.name
58 : "Chapter " + data.chapterInfo.index) : null
59 const chapterCountString = data.chapters
60 ? ' | <b>Chapters:</b> '+data.chapters.published+' / '+(
61 data.chapters.total
62 ? data.chapters.total
63 : '?'
64 )
65 : ''
66 const fandomString = type === 'work' ? (
67 data.fandoms.length > 1
68 ? (
69 data.fandoms.length <= 5
70 ? data.fandoms.slice(0, -1).join(", ")+" & "+data.fandoms.slice(-1)
71 : data.fandoms.join(", ")+" (+"+(data.fandoms.length - 4)+")"
72 )
73 : data.fandoms[0]
74 ) : (
75 data.works.map(w => w.fandoms).reduce((a, b) => { return a.concat(b) }).filter((w, i) => { return i === data.works.indexOf(w) })
76 )
77 return {
78 topLine: fandomString,
79 titleLine: titleString,
80 authorLine: authorString,
81 chapterLine: chapterString,
82 summary: summaryFormatted,
83 url: 'https://archiveofourown.org/',
84 theme: themeData,
85 baseFont: baseFont,
86 titleFont: titleFont,
87 opts: {
88 fonts: bfs.concat(tfs)
89 }
90 }
91}