Add a reproducible pitch URL and link annotation to the CV.

The script is idempotent, keeps the twelve A4 pages, and writes antoniolede.de/pitch on page 1 with a matching URI annotation.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-08-26 12:52:26 +02:00
parent 162bd790da
commit 5921fc5ede
4 changed files with 159 additions and 2 deletions

View File

@@ -0,0 +1,107 @@
import { readFileSync, writeFileSync } from 'node:fs';
import { dirname, join } from 'node:path';
import { fileURLToPath } from 'node:url';
import { PDFDocument, PDFName, PDFString, rgb, StandardFonts } from 'pdf-lib';
const ROOT = join(dirname(fileURLToPath(import.meta.url)), '..');
const CV_PATH = join(ROOT, 'CV.pdf');
const PITCH_URI = 'https://antoniolede.de/pitch';
const VISIBLE_TEXT = 'antoniolede.de/pitch';
const TEXT_X = 59.6;
const TEXT_Y = 215.4;
const FONT_SIZE = 10.5;
const PADDING = 2;
function asString(value) {
if (!value) {
return '';
}
if (typeof value.decodeText === 'function') {
return value.decodeText();
}
return String(value);
}
function annotationUri(annotation) {
const action = annotation.lookup(PDFName.of('A'));
if (!action || typeof action.lookup !== 'function') {
return '';
}
const uri = action.lookup(PDFName.of('URI'));
return asString(uri);
}
function pageHasPitchLink(page) {
const annots = page.node.lookup(PDFName.of('Annots'));
if (!annots || typeof annots.size !== 'function') {
return false;
}
for (let index = 0; index < annots.size(); index += 1) {
const annotation = annots.lookup(index);
if (annotationUri(annotation) === PITCH_URI) {
return true;
}
}
return false;
}
const bytes = readFileSync(CV_PATH);
const pdfDoc = await PDFDocument.load(bytes);
const title = pdfDoc.getTitle();
const author = pdfDoc.getAuthor();
const creator = pdfDoc.getCreator();
const page = pdfDoc.getPage(0);
if (pageHasPitchLink(page)) {
console.log('Pitch link annotation already present; leaving CV.pdf unchanged.');
process.exit(0);
}
const font = await pdfDoc.embedFont(StandardFonts.Helvetica);
const textWidth = font.widthOfTextAtSize(VISIBLE_TEXT, FONT_SIZE);
page.drawText(VISIBLE_TEXT, {
x: TEXT_X,
y: TEXT_Y,
size: FONT_SIZE,
font,
color: rgb(54 / 255, 125 / 255, 162 / 255),
});
const link = pdfDoc.context.register(
pdfDoc.context.obj({
Type: 'Annot',
Subtype: 'Link',
Rect: [
TEXT_X - PADDING,
TEXT_Y - PADDING,
TEXT_X + textWidth + PADDING,
TEXT_Y + FONT_SIZE + PADDING,
],
Border: [0, 0, 0],
A: {
S: 'URI',
URI: PDFString.of(PITCH_URI),
},
}),
);
page.node.addAnnot(link);
if (title) {
pdfDoc.setTitle(title);
}
if (author) {
pdfDoc.setAuthor(author);
}
if (creator) {
pdfDoc.setCreator(creator);
}
const saved = await pdfDoc.save({ useObjectStreams: false });
writeFileSync(CV_PATH, saved);
console.log('Added visible pitch URL and link annotation to page 1 of CV.pdf.');