Restore the original Quartz Producer on the CV without duplicating the pitch link.

The script now repairs metadata independently of the annotation, and a repeat run leaves the bytes untouched.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-08-26 13:51:58 +02:00
parent b8b9e57d06
commit e63b4edade
2 changed files with 60 additions and 44 deletions

BIN
CV.pdf

Binary file not shown.

View File

@@ -11,6 +11,10 @@ const TEXT_X = 59.6;
const TEXT_Y = 215.4; const TEXT_Y = 215.4;
const FONT_SIZE = 10.5; const FONT_SIZE = 10.5;
const PADDING = 2; const PADDING = 2;
const ORIGINAL_TITLE = 'CV';
const ORIGINAL_CREATOR = 'Pages';
// Producer from the unmodified Pages/Quartz export of CV.pdf.
const ORIGINAL_PRODUCER = 'macOS Version 26.5.2 (Build 25F84) Quartz PDFContext';
function asString(value) { function asString(value) {
if (!value) { if (!value) {
@@ -50,58 +54,70 @@ function pageHasPitchLink(page) {
return false; return false;
} }
const bytes = readFileSync(CV_PATH); function hasOriginalMetadata(pdfDoc) {
const pdfDoc = await PDFDocument.load(bytes); return (
const title = pdfDoc.getTitle(); pdfDoc.getTitle() === ORIGINAL_TITLE &&
const author = pdfDoc.getAuthor(); pdfDoc.getCreator() === ORIGINAL_CREATOR &&
const creator = pdfDoc.getCreator(); pdfDoc.getProducer() === ORIGINAL_PRODUCER
const page = pdfDoc.getPage(0); );
}
if (pageHasPitchLink(page)) { const bytes = readFileSync(CV_PATH);
console.log('Pitch link annotation already present; leaving CV.pdf unchanged.'); const pdfDoc = await PDFDocument.load(bytes, { updateMetadata: false });
const page = pdfDoc.getPage(0);
const needsLink = !pageHasPitchLink(page);
const needsMetadata = !hasOriginalMetadata(pdfDoc);
if (!needsLink && !needsMetadata) {
console.log('Pitch link and original metadata already present; leaving CV.pdf unchanged.');
process.exit(0); process.exit(0);
} }
const font = await pdfDoc.embedFont(StandardFonts.Helvetica); if (needsLink) {
const textWidth = font.widthOfTextAtSize(VISIBLE_TEXT, FONT_SIZE); const font = await pdfDoc.embedFont(StandardFonts.Helvetica);
const textWidth = font.widthOfTextAtSize(VISIBLE_TEXT, FONT_SIZE);
page.drawText(VISIBLE_TEXT, { page.drawText(VISIBLE_TEXT, {
x: TEXT_X, x: TEXT_X,
y: TEXT_Y, y: TEXT_Y,
size: FONT_SIZE, size: FONT_SIZE,
font, font,
color: rgb(54 / 255, 125 / 255, 162 / 255), color: rgb(54 / 255, 125 / 255, 162 / 255),
}); });
const link = pdfDoc.context.register( const link = pdfDoc.context.register(
pdfDoc.context.obj({ pdfDoc.context.obj({
Type: 'Annot', Type: 'Annot',
Subtype: 'Link', Subtype: 'Link',
Rect: [ Rect: [
TEXT_X - PADDING, TEXT_X - PADDING,
TEXT_Y - PADDING, TEXT_Y - PADDING,
TEXT_X + textWidth + PADDING, TEXT_X + textWidth + PADDING,
TEXT_Y + FONT_SIZE + PADDING, TEXT_Y + FONT_SIZE + PADDING,
], ],
Border: [0, 0, 0], Border: [0, 0, 0],
A: { A: {
S: 'URI', S: 'URI',
URI: PDFString.of(PITCH_URI), URI: PDFString.of(PITCH_URI),
}, },
}), }),
); );
page.node.addAnnot(link); page.node.addAnnot(link);
if (title) {
pdfDoc.setTitle(title);
} }
if (author) {
pdfDoc.setAuthor(author); if (needsMetadata) {
} pdfDoc.setTitle(ORIGINAL_TITLE);
if (creator) { pdfDoc.setCreator(ORIGINAL_CREATOR);
pdfDoc.setCreator(creator); pdfDoc.setProducer(ORIGINAL_PRODUCER);
} }
const saved = await pdfDoc.save({ useObjectStreams: false }); const saved = await pdfDoc.save({ useObjectStreams: false });
writeFileSync(CV_PATH, saved); writeFileSync(CV_PATH, saved);
console.log('Added visible pitch URL and link annotation to page 1 of CV.pdf.');
if (needsLink && needsMetadata) {
console.log('Added the pitch link and restored the original CV.pdf metadata.');
} else if (needsLink) {
console.log('Added visible pitch URL and link annotation to page 1 of CV.pdf.');
} else {
console.log('Restored the original Title, Creator and Producer on CV.pdf.');
}