[READ-ONLY] Mirror of https://github.com/mrgnw/cv.
0

Configure Feed

Select the types of activity you want to include in your feed.

cv / generate-pdf.js
6.5 kB 227 lines
1import { chromium } from 'playwright'; 2import fs from 'fs'; 3import path from 'path'; 4import http from 'http'; 5import { execSync } from 'child_process'; 6 7// Import our Node.js compatible version reader functions 8import { getAllVersions, getAllVersionMeta } from './pdf-version-reader.js'; 9 10 11// Use our new version reader to get available versions 12const getAvailableVersions = () => { 13 try { 14 return getAllVersions(); 15 } catch (error) { 16 console.error('Error getting versions from version reader:', error); 17 // Fallback to empty array 18 return []; 19 } 20}; 21 22// const getChangedVersions = () => { 23// try { 24// const modified_versions = execSync('git diff --name-only HEAD HEAD~1').toString(); 25 26// return modified_versions 27// .split('\n') 28// .filter(file => file.startsWith('src/lib/versions/') && file.endsWith('.json')) 29// .map(file => path.parse(file).name); 30// } catch (error) { 31// console.error('Error getting changed versions:', error.message); 32// return []; 33// } 34// }; 35 36const getVersionNames = (specificVersions) => { 37 const allVersions = getAvailableVersions(); 38 39 if (specificVersions?.includes('all')) { 40 return allVersions; 41 } 42 43 // If specific versions are provided, only process those 44 if (specificVersions?.length) { 45 return allVersions.filter(version => specificVersions.includes(version)); 46 } 47 48 return allVersions; 49}; 50 51/** 52 * Detect which port the preview server is running on 53 */ 54const detectServerPort = async () => { 55 const ports = [4173, 4174, 4175, 4176, 4177]; 56 const maxAttempts = 15; // 15 seconds total 57 58 for (let attempt = 0; attempt < maxAttempts; attempt++) { 59 for (const port of ports) { 60 const url = `http://localhost:${port}`; 61 try { 62 await new Promise((resolve, reject) => { 63 const req = http.get(url, (res) => { 64 resolve(); 65 }); 66 req.on('error', reject); 67 req.setTimeout(1000, () => { 68 req.destroy(); 69 reject(new Error('Timeout')); 70 }); 71 }); 72 console.log(`✅ Found preview server on port ${port}`); 73 return url; 74 } catch (error) { 75 // Try next port 76 } 77 } 78 79 // Wait 1 second before trying again 80 if (attempt < maxAttempts - 1) { 81 console.log(`⏳ Waiting for server to start... (${attempt + 1}/${maxAttempts})`); 82 await new Promise(resolve => setTimeout(resolve, 1000)); 83 } 84 } 85 86 throw new Error('Preview server not found on any expected port (4173-4177) after 15 seconds'); 87}; 88 89const waitForServer = (url) => { 90 return new Promise((resolve, reject) => { 91 const timeout = setTimeout(() => { 92 reject(new Error('Server start timeout')); 93 }, 30000); 94 95 const checkServer = () => { 96 http.get(url, (res) => { 97 clearTimeout(timeout); 98 resolve(); 99 }).on('error', () => { 100 setTimeout(checkServer, 100); 101 }); 102 }; 103 104 checkServer(); 105 }); 106}; 107 108async function getPageCount(page) { 109 return await page.evaluate(() => { 110 const height = document.documentElement.scrollHeight; 111 const pageHeight = 1123; // A4 height in pixels at 96 DPI 112 return Math.ceil(height / pageHeight); 113 }); 114} 115 116// Helper function to check PDF page count 117async function checkPdfPageCount(page, options) { 118 const pdf = await page.pdf({ ...options }); 119 const pageCount = (pdf.toString().match(/\/Page\s*$/gm) || []).length; 120 return pageCount; 121} 122 123export function generatePDF() { 124 // PDF generation disabled for now 125 console.log('PDF generation disabled'); 126} 127 128// Configuration option to control sans version generation 129const GENERATE_SANS_VERSION = false; // Set to true to enable sans version generation 130 131// Helper function to generate PDF for a specific version and style 132async function generateVersionPDF(page, serverUrl, version, options, isSansStyle = false) { 133 // Build URL and paths based on style (simplified - no Spanish handling) 134 const stylePrefix = isSansStyle ? '/sans' : ''; 135 const url = `${serverUrl}${stylePrefix}/${version}?print`; 136 137 const styleInfix = isSansStyle ? '-sans' : ''; 138 const pdfName = version === 'main' ? 139 `morgan-williams${styleInfix}.pdf` : 140 `morgan-williams.${version}${styleInfix}.pdf`; 141 142 const outputDir = isSansStyle ? path.join('static', 'sans') : 'static'; 143 const pdfPath = path.join(outputDir, pdfName); 144 145 let projectsToRemove = 0; 146 let pageCount; 147 148 do { 149 await page.goto(`${url}&removeProjects=${projectsToRemove}`, { waitUntil: 'networkidle' }); 150 pageCount = await checkPdfPageCount(page, options); 151 152 if (pageCount > 1) { 153 projectsToRemove++; 154 console.log(` - project ${projectsToRemove} (${pageCount} pages)`); 155 } 156 } while (pageCount > 1 && projectsToRemove < 5); 157 158 await page.pdf({ path: pdfPath, ...options }); 159 console.log(`🖨️ ${pdfPath}${projectsToRemove > 0 ? ` (removed ${projectsToRemove} projects)` : ''}`); 160} 161 162(async () => { 163 // Get versions from command line args OR get all available versions 164 const specificVersions = process.argv.length > 2 ? 165 process.argv.slice(2) : 166 getAvailableVersions(); 167 168 console.log('🔍 Detecting preview server...'); 169 let serverUrl; 170 try { 171 serverUrl = await detectServerPort(); 172 } catch (error) { 173 console.error('❌', error.message); 174 console.log('💡 Make sure to run `npm run preview` first'); 175 process.exit(1); 176 } 177 178 const versions = getVersionNames(specificVersions); 179 if (versions.length === 0) { 180 console.log('No versions to process'); 181 process.exit(0); 182 } 183 184 console.log('Generating PDFs for versions:', versions.join(', ')); 185 const browser = await chromium.launch(); 186 const page = await browser.newPage(); 187 188 const pdfOptions = { 189 format: 'A4', 190 printBackground: false, 191 margin: { 192 top: '6mm', 193 bottom: '6mm', 194 left: '8mm', 195 right: '8mm', 196 }, 197 }; 198 199 // Ensure static directory exists 200 if (!fs.existsSync('static')) { 201 fs.mkdirSync('static'); 202 } 203 204 // Ensure sans directory exists if needed 205 if (GENERATE_SANS_VERSION && !fs.existsSync('static/sans')) { 206 fs.mkdirSync('static/sans'); 207 } 208 209 // Process each version 210 for (const version of versions) { 211 try { 212 // Generate regular version 213 await generateVersionPDF(page, serverUrl, version, pdfOptions, false); 214 215 // Optionally generate sans version 216 if (GENERATE_SANS_VERSION) { 217 await generateVersionPDF(page, serverUrl, version, pdfOptions, true); 218 } 219 } catch (error) { 220 console.error(`Error generating PDFs for version ${version}:`, error); 221 } 222 } 223 224 await browser.close(); 225 console.log('✅ Done'); 226 process.exit(0); 227})();