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}