import {
PDFDocument,
PDFPage,
rgb,
} from "https://cdn.skypack.dev/pdf-lib@^1.11.1?dts";
import fontkit from "https://cdn.skypack.dev/@pdf-lib/fontkit@^1.0.0?dts";
type Result = {
id: number;
word: string;
answer: string;
};
async function generateVoca(level: number, day: number) {
const re =
/
(?\d+?)\. (?.+?)<\/p>.*?(?.+?)<\/span>/gis;
const res = await fetch(
`https://www.hackers.co.kr/?c=s_toeic/new_voca_toeic_testpaper/toeic_study/new_paper&mode=new_view&level=${level}&level_type=&lang_text=2&question=1000&day3=${day}&day4=${day}&day_auto=N&index=1`,
);
const body = (await res.text());
const matches = [...body.matchAll(re)].map((m) => ({
...m.groups as unknown as Result,
id: Number.parseInt(m.groups?.id as string),
}));
const pdfDoc = await PDFDocument.create();
const fontBytes = await Deno.readFile("./NanumGothic.ttf");
pdfDoc.registerFontkit(fontkit);
const customFont = await pdfDoc.embedFont(fontBytes);
const fontSize = 12;
const margin = 20;
const perColumn = 25;
const perPage = 50;
let page!: PDFPage;
let col = -1;
let yCursor = 1;
// 문제 생성
for (let i = 0; i < matches.length; ++i) {
const data = matches[i];
if (i % perPage === 0) {
page = pdfDoc.addPage();
yCursor = 1;
col = -1;
}
if (i % perColumn === 0) {
col++;
yCursor = 1;
}
page.drawText(`${data.id}. ${data.word}`, {
x: margin + (page.getWidth() / 2 * col),
y: page.getHeight() - (fontSize + margin) * (yCursor),
size: fontSize,
font: customFont,
color: rgb(0, 0, 0),
});
page.drawText("_________________", {
x: margin + (page.getWidth() / 2 * col) + 140,
y: page.getHeight() - (fontSize + margin) * (yCursor) - 3,
size: fontSize,
font: customFont,
color: rgb(0, 0, 0),
});
yCursor++;
}
// 답 생성
for (let i = 0; i < matches.length; ++i) {
const data = matches[i];
if (i % perPage === 0) {
page = pdfDoc.addPage();
yCursor = 1;
col = -1;
}
if (i % perColumn === 0) {
col++;
yCursor = 1;
}
page.drawText(`${data.id}. ${data.word}`, {
x: margin + (page.getWidth() / 2 * col),
y: page.getHeight() - (fontSize + margin) * (yCursor),
size: fontSize,
font: customFont,
color: rgb(0, 0, 0),
});
page.drawText("_________________", {
x: margin + (page.getWidth() / 2 * col) + 140,
y: page.getHeight() - (fontSize + margin) * (yCursor) - 3,
size: fontSize,
font: customFont,
color: rgb(0, 0, 0),
});
page.drawText(data.answer, {
x: margin + (page.getWidth() / 2 * col) + 140,
y: page.getHeight() - (fontSize + margin) * (yCursor),
size: fontSize,
font: customFont,
color: rgb(1, 0, 0),
});
yCursor++;
}
const pdfBytes = await pdfDoc.save();
return pdfBytes;
}
const port = 8055;
const server = Deno.listen({ port });
console.log(
`HTTP webserver running. Access it at: http://localhost:${port}/`,
);
for await (const conn of server) {
serveHttp(conn);
}
async function serveHttp(conn: Deno.Conn) {
const httpConn = Deno.serveHttp(conn);
for await (const requestEvent of httpConn) {
const url = new URL(requestEvent.request.url);
if (!url.searchParams.has("level") || !url.searchParams.has("day")) {
requestEvent.respondWith(
new Response("Not Found", {
status: 404,
}),
);
return;
}
const level = Number.parseInt(url.searchParams.get("level")!) ?? 7;
const day = Number.parseInt(url.searchParams.get("day")!) ?? 1;
const data = await generateVoca(level, day);
requestEvent.respondWith(
new Response(data, {
status: 200,
}),
);
}
}