+5
-1
src/app/api/series/[seriesId]/route.js
+5
-1
src/app/api/series/[seriesId]/route.js
···
1
1
import { getSeries } from "@fujocoded/ao3.js"
2
+
import { setArchiveBaseUrl, resetArchiveBaseUrl } from "@fujocoded/ao3.js/urls"
2
3
3
4
export const dynamic = 'force-static'
4
5
5
-
export async function GET(_req, ctx) {
6
+
export async function GET(req, ctx) {
6
7
const { seriesId } = await ctx.params
8
+
const { archive } = await req.nextUrl.searchParams
9
+
if (archive) setArchiveBaseUrl(`https://${archive}`)
7
10
const series = await getSeries({seriesId: seriesId})
11
+
if (archive) resetArchiveBaseUrl()
8
12
return Response.json(series)
9
13
}
+5
-1
src/app/api/works/[workId]/chapters/[chapterId]/route.js
+5
-1
src/app/api/works/[workId]/chapters/[chapterId]/route.js
···
1
1
import { getWork } from "@fujocoded/ao3.js"
2
+
import { setArchiveBaseUrl, resetArchiveBaseUrl } from "@fujocoded/ao3.js/urls"
2
3
3
4
export const dynamic = 'force-static'
4
5
5
-
export async function GET(_req, ctx) {
6
+
export async function GET(req, ctx) {
6
7
const { workId, chapterId } = await ctx.params
8
+
const { archive } = await req.nextUrl.searchParams
9
+
if (archive) setArchiveBaseUrl(`https://${archive}`)
7
10
const work = await getWork({workId: workId, chapterId: chapterId})
11
+
if (archive) resetArchiveBaseUrl()
8
12
return Response.json(work)
9
13
}
+5
-1
src/app/api/works/[workId]/route.js
+5
-1
src/app/api/works/[workId]/route.js
···
1
1
import { getWork } from "@fujocoded/ao3.js"
2
+
import { setArchiveBaseUrl, resetArchiveBaseUrl } from "@fujocoded/ao3.js/urls"
2
3
3
4
export const dynamic = 'force-static'
4
5
5
-
export async function GET(_req, ctx) {
6
+
export async function GET(req, ctx) {
6
7
const { workId } = await ctx.params
8
+
const { archive } = await req.nextUrl.searchParams
9
+
if (archive) setArchiveBaseUrl(`https://${archive}`)
7
10
const work = await getWork({workId: workId})
11
+
if (archive) resetArchiveBaseUrl()
8
12
return Response.json(work)
9
13
}
+11
-3
src/app/generator/page.js
+11
-3
src/app/generator/page.js
···
1
1
"use client"
2
2
3
3
import { useEffect, useState } from "react"
4
+
import { setArchiveBaseUrl, resetArchiveBaseUrl } from "@fujocoded/ao3.js/urls"
4
5
import themes from "@/lib/themes.js"
5
6
import baseFonts from "@/lib/baseFonts.js"
6
7
import titleFonts from "@/lib/titleFonts.js"
···
13
14
const [addr, setAddr] = useState('')
14
15
const [imgData, setImgData] = useState(null)
15
16
const [props, setProps] = useState(defaults)
17
+
const [domain, setDomain] = useState('')
16
18
17
19
const updateProp = (name, value) => {
18
20
const newProps = props
···
22
24
}
23
25
24
26
const updateData = async () => {
27
+
if (url === '') return
25
28
const workMatch = /\/works\/(?<workId>[0-9]+)(?:\/chapters\/(?<chapterId>[0-9]+))?$/
26
29
const seriesMatch = /\/series\/(?<seriesId>[0-9]+)$/
30
+
const baseurl = /https:\/\/(?<domain>[a-z0-9\-\.]+)\//
31
+
const domainMatch = url.match(baseurl)
32
+
if (!domainMatch) return
33
+
setDomain(domainMatch.groups.domain)
34
+
const domainParam = domain && !(["ao3.org", "archiveofourown.org", "archive.transformativeworks.org"].includes(domain)) ? '' : `?archive=${domain}`
27
35
if (workMatch.test(url)) {
28
36
const match = url.match(workMatch)
29
-
const resp = match.groups.chapterId ? await fetch(`/api/works/${match.groups.workId}/chapters/${match.groups.chapterId}`) : await fetch(`/api/works/${match.groups.workId}`)
37
+
const resp = match.groups.chapterId ? await fetch(`/api/works/${match.groups.workId}/chapters/${match.groups.chapterId}${domainParam}`) : await fetch(`/api/works/${match.groups.workId}${domainParam}`)
30
38
const data = await resp.json()
31
39
setAddr(match.groups.chapterId ? `works/${match.groups.workId}/chapters/${match.groups.chapterId}` : `works/${match.groups.workId}`)
32
40
setWorkData(data)
33
41
} else if (seriesMatch.test(url)) {
34
42
const match = url.match(seriesMatch)
35
-
const resp = await fetch(`/api/series/${match.groups.seriesId}`)
43
+
const resp = await fetch(`/api/series/${match.groups.seriesId}${domainParam}`)
36
44
const data = await resp.json()
37
45
setAddr(`series/${match.groups.seriesId}`)
38
46
setWorkData(data)
···
47
55
const fn = async () => {
48
56
if (!addr) return;
49
57
const params = new URLSearchParams(props)
50
-
const image = await fetch(`/${addr}/preview?${params.toString()}`)
58
+
const image = await fetch(`/${addr}/preview?${params.toString()}&archive=${domain}`)
51
59
if (image.status !== 200) return;
52
60
const imageBlob = await image.blob()
53
61
const reader = new FileReader()
+3
src/app/series/[seriesId]/preview/route.js
+3
src/app/series/[seriesId]/preview/route.js
···
1
1
import { getSeries } from "@fujocoded/ao3.js"
2
+
import { setArchiveBaseUrl, resetArchiveBaseUrl } from "@fujocoded/ao3.js/urls"
2
3
import querystring from 'node:querystring'
3
4
import sanitizeData from "@/lib/sanitizeData.js"
4
5
import OGImage from "@/lib/ogimage.js"
···
17
18
const p = await req.nextUrl.searchParams
18
19
const props = querystring.parse(p.toString())
19
20
const addr = `series/${seriesId}`
21
+
if (props.archive) setArchiveBaseUrl('https://'+props.archive)
20
22
const data = await getSeries({seriesId: seriesId})
23
+
if (props.archive) resetArchiveBaseUrl()
21
24
const imageParams = await sanitizeData({type: 'series', data: data, props: props})
22
25
const theme = imageParams.theme
23
26
const baseFont = baseFonts[imageParams.baseFont].displayName
+17
-6
src/lib/sanitizeData.js
+17
-6
src/lib/sanitizeData.js
···
1
1
import { getWork } from "@fujocoded/ao3.js"
2
+
import { setArchiveBaseUrl, resetArchiveBaseUrl } from "@fujocoded/ao3.js/urls"
2
3
import DOM from "fauxdom"
3
4
import { readFile } from 'node:fs/promises'
4
5
import { join } from 'node:path'
···
6
7
import baseFonts from '@/lib/baseFonts.js'
7
8
import titleFonts from '@/lib/titleFonts.js'
8
9
9
-
const getHighestRating = async (works) => {
10
+
const getHighestRating = async (works, archive = null) => {
10
11
const ratings = await Promise.all(works.map(async (w) => {
12
+
if (archive) setArchiveBaseUrl('https://'+archive)
11
13
const work = await getWork({workId: w.id})
14
+
if (archive) resetArchiveBaseUrl()
12
15
return work.rating
13
16
}))
14
17
if (ratings.includes("Not Rated")) {
···
23
26
return "G"
24
27
}
25
28
26
-
const getHighestWarning = async (works) => {
29
+
const getHighestWarning = async (works, archive = null) => {
27
30
const warnings = await Promise.all(works.map(async (w) => {
31
+
if (archive) setArchiveBaseUrl('https://'+archive)
28
32
const work = await getWork({workId: w.id})
33
+
if (archive) resetArchiveBaseUrl()
29
34
return work.tags.warnings
30
35
}))
31
36
const warningsUnique = warnings.reduce((a, b) => { return a.concat(b) }).filter((w, i) => { return i === warnings.indexOf(w) })
···
37
42
return "W"
38
43
}
39
44
40
-
const getCategory = async (works) => {
45
+
const getCategory = async (works, archive = null) => {
41
46
const categories = await Promise.all(works.map(async (w) => {
47
+
if (archive) setArchiveBaseUrl('https://'+archive)
42
48
const work = await getWork({workId: w.id})
49
+
if (archive) resetArchiveBaseUrl()
43
50
return work.category
44
51
}))
45
52
const categoriesJoined = categories.reduce((a, b) => { return a.concat(b) })
···
76
83
77
84
export default async function sanitizeData ({ type, data, props}) {
78
85
const propsParsed = sanitizeProps(props)
86
+
const archive = propsParsed.archive
79
87
const baseFont = propsParsed.baseFont ? propsParsed.baseFont : process.env.DEFAULT_BASE_FONT
80
88
const baseFontData = baseFonts[baseFont]
81
89
const titleFont = propsParsed.titleFont ? propsParsed.titleFont : process.env.DEFAULT_TITLE_FONT
82
90
const titleFontData = titleFonts[titleFont]
83
91
const themeData = propsParsed.theme ? themes[propsParsed.theme] : themes[process.env.DEFAULT_THEME]
92
+
if (archive) setArchiveBaseUrl('https://'+archive)
84
93
const parentWork = type === 'work' && data.chapterInfo ? await getWork({workId: data.id}) : null
94
+
if (archive) resetArchiveBaseUrl()
85
95
const bfs = await Promise.all(baseFontData.defs.map(async (bf) => {
86
96
return {
87
97
name: baseFontData.displayName,
···
109
119
return a.username
110
120
})
111
121
: []
112
-
const rating = type === 'work' ? await getHighestRating([data]) : await getHighestRating(data.works)
113
-
const warning = type === 'work' ? await getHighestWarning([data]) : await getHighestWarning(data.works)
114
-
const category = type === 'work' ? await getCategory([data]) : await getCategory(data.works)
122
+
const rating = type === 'work' ? await getHighestRating([data], archive) : await getHighestRating(data.works, archive)
123
+
const warning = type === 'work' ? await getHighestWarning([data], archive) : await getHighestWarning(data.works, archive)
124
+
const category = type === 'work' ? await getCategory([data], archive) : await getCategory(data.works, archive)
115
125
const authorString = authorsFormatted.length > 1
116
126
? authorsFormatted.slice(0, -1).join(", ") + " & " +
117
127
authorsFormatted.slice(-1)[0]
···
126
136
/(<([^>]+)>)/ig,
127
137
"",
128
138
).split("\n")
139
+
console.log(data)
129
140
const titleString = type === 'work' ? data.title : data.name
130
141
const chapterString = data.chapterInfo ? (data.chapterInfo.name
131
142
? data.chapterInfo.name