feat: moving api/

This commit is contained in:
Travis Fischer
2021-01-17 19:45:09 -05:00
parent b26dbba816
commit 23b712d4b9
4 changed files with 19 additions and 11 deletions

View File

@@ -1,75 +0,0 @@
import { NextApiRequest, NextApiResponse } from 'next'
import got from 'got'
import lqip from 'lqip-modern'
import * as types from '../../lib/types'
import * as db from '../../lib/db'
export default async (req: NextApiRequest, res: NextApiResponse) => {
if (req.method !== 'POST') {
return res.status(405).send({ error: 'method not allowed' })
}
const { url, id } = req.body
const result = await createPreviewImage(url, id)
res.setHeader(
'Cache-Control',
result.error
? 'public, s-maxage=60, max-age=60, stale-while-revalidate=60'
: 'public, immutable, s-maxage=31536000, max-age=31536000, stale-while-revalidate=60'
)
res.status(200).json(result)
}
export async function createPreviewImage(
url: string,
id: string
): Promise<types.PreviewImage> {
const doc = db.images.doc(id)
try {
const model = await doc.get()
if (model.exists) {
return model.data() as types.PreviewImage
}
const { body } = await got(url, { responseType: 'buffer' })
const result = await lqip(body)
console.log('lqip', result.metadata)
const image = {
url,
originalWidth: result.metadata.originalWidth,
originalHeight: result.metadata.originalHeight,
width: result.metadata.width,
height: result.metadata.height,
type: result.metadata.type,
dataURIBase64: result.metadata.dataURIBase64
}
await doc.create(image)
return image
} catch (err) {
console.error('lqip error', err)
try {
const error: any = {
url,
error: err.message || 'unknown error'
}
if (err?.response?.statusCode) {
error.statusCode = err?.response?.statusCode
}
await doc.create(error)
return error
} catch (err) {
// ignore errors
console.error(err)
}
}
}

View File

@@ -1,115 +0,0 @@
import { NextApiRequest, NextApiResponse } from 'next'
import chromium from 'chrome-aws-lambda'
import renderSocialImage from 'puppeteer-social-image-transitive-bs'
import { getBlockIcon, getBlockTitle } from 'notion-utils'
import { getPage } from 'lib/notion'
import * as types from 'lib/types'
import {
siteDescription,
defaultPageCover,
defaultPageIcon,
siteDomain,
siteName
} from 'lib/config'
import { getPageDescription } from 'lib/get-page-description'
export interface SocialImageConfig {
title: string
subtitle?: string
eyebrow?: string
logo?: string
imageUrl?: string
unsplashId?: string
unsplashKeywords?: string
backgroundImageAnchor?: string
backgroundImageOverlay?: boolean
background?: string
color?: string
googleFont?: string
fontFamily?: string
watermark?: string
size?:
| 'facebook'
| 'twitter'
| 'ig-landscape'
| 'ig-portrait'
| 'ig-square'
| 'ig-story'
}
export default async (req: NextApiRequest, res: NextApiResponse) => {
if (req.method !== 'GET') {
return res.status(405).send({ error: 'method not allowed' })
}
const pageId = req.query.pageId as string
if (!pageId) {
return res.status(400).send({ error: 'missing required parameter pageId' })
}
let recordMap: types.ExtendedRecordMap
let block: types.PageBlock
try {
recordMap = await getPage(pageId)
const pageBlockId = Object.keys(recordMap.block)[0]
block = recordMap.block[pageBlockId]?.value as types.PageBlock
if (!block) {
return res.status(404).send({
error: `unable to resolve root block for notion page "${pageId}"`
})
}
} catch (err) {
return res
.status(404)
.send({ error: `unable to load notion page "${pageId}"` })
}
// TODO: centralize these default config values
const image = await createSocialImage({
imageUrl: block.format?.page_cover ?? defaultPageCover,
title: getBlockTitle(block, recordMap) ?? siteName,
logo: getBlockIcon(block, recordMap) ?? defaultPageIcon,
subtitle: getPageDescription(block, recordMap) ?? siteDescription,
watermark: siteDomain
})
res.setHeader(
'Cache-Control',
'public, immutable, s-maxage=31536000, max-age=31536000, stale-while-revalidate=60'
)
res.setHeader('Content-Type', 'image/jpeg')
res.status(200).send(image)
}
async function createSocialImage(params: SocialImageConfig) {
let browser
try {
browser = await chromium.puppeteer.launch({
args: chromium.args,
defaultViewport: chromium.defaultViewport,
executablePath: await chromium.executablePath,
headless: true, // chromium.headless,
ignoreHTTPSErrors: true
})
const res = await renderSocialImage({
template: 'article',
templateParams: params,
templateStyles: `h1 { font-size: 96px; text-align: center; } h2 { font-size: 32px; }`,
size: params.size,
browser
})
return res
} finally {
if (browser) {
await browser.close()
}
}
}

View File

@@ -1,20 +0,0 @@
import { NextApiRequest, NextApiResponse } from 'next'
import * as types from 'lib/types'
import * as notion from 'lib/notion'
export default async (req: NextApiRequest, res: NextApiResponse) => {
if (req.method !== 'POST') {
return res.status(405).send({ error: 'method not allowed' })
}
const searchParams: types.SearchParams = req.body
const results = await notion.search(searchParams)
res.setHeader(
'Cache-Control',
'public, s-maxage=60, max-age=60, stale-while-revalidate=60'
)
res.status(200).json(results)
}