diff --git a/README.md b/README.md index 09bab62..57bf4b2 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ node src/index.js --help Usage: pdfy [options] Arguments: - url URL of the article to convert + url URL of the article to convert, or path to a local HTML file Options: -t, --theme Reader View theme (light, dark, sepia, groove-dark, solarized-light, solarized-dark, nord-light, nord-dark) @@ -77,7 +77,9 @@ CLI flags always override config file values. Use `--config ` to specify a ```bash node src/index.js https://example.com/article +node src/index.js /path/to/saved/page.html node src/index.js https://example.com/article --theme dark --css config/rules.css +node src/index.js /path/to/saved/page.html --theme dark --highlight-style monokai node src/index.js https://example.com/article --prefs config/reader-view-preferences.json node src/index.js https://example.com/article --highlight-style monokai node src/index.js https://example.com/article --config .pdfyrc diff --git a/src/cli.js b/src/cli.js index d264256..14b9705 100644 --- a/src/cli.js +++ b/src/cli.js @@ -16,7 +16,7 @@ const program = new Command() program .name('pdfy') .description('Convert web articles to PDF using Reader View and Puppeteer') - .argument('', 'URL of the article to convert') + .argument('', 'URL of the article to convert, or path to a local HTML file') .option( '-t, --theme ', `Reader View theme (${VALID_THEMES.join(', ')})` @@ -42,6 +42,8 @@ program Examples: node src/index.js node src/index.js --theme dark --highlight-style monokai --css config/rules.css + node src/index.js --theme dark --highlight-style monokai + node src/index.js --prefs config/reader-view-preferences.json npm start -- --theme dark --highlight-style monokai --css config/rules.css ` ) diff --git a/src/index.js b/src/index.js index 260f6fa..8a6da28 100644 --- a/src/index.js +++ b/src/index.js @@ -1,6 +1,7 @@ import fs from 'node:fs' -import process from 'node:process' import path from 'node:path' +import { pathToFileURL } from 'node:url' +import process from 'node:process' import readline from 'node:readline/promises' import { parseArgs } from './cli.js' import { loadConfigFile, loadPreferences, readCustomCss } from './config.js' @@ -31,7 +32,12 @@ async function main () { const customCss = cssPath ? readCustomCss(path.resolve(cssPath)) : null let html - const currentUrl = url + const filePath = path.resolve(url) + let currentUrl = url + if (fs.existsSync(filePath) && fs.statSync(filePath).isFile()) { + currentUrl = pathToFileURL(filePath).href + logger.info(`Detected local file, converting to file URL: ${currentUrl}`) + } for (let attempt = 0; attempt < 2; attempt++) { try { @@ -66,6 +72,7 @@ async function main () { logger.info(`Loading article from local file: "${resolvedPath}"`) html = fs.readFileSync(resolvedPath, 'utf-8') + currentUrl = pathToFileURL(resolvedPath).href continue } throw err diff --git a/src/pdf.js b/src/pdf.js index 27a249f..09d7c9d 100644 --- a/src/pdf.js +++ b/src/pdf.js @@ -1,5 +1,6 @@ import fs from 'node:fs' import path from 'node:path' +import { pathToFileURL } from 'node:url' import logger from './logger.js' const HIGHLIGHT_JS = @@ -44,8 +45,19 @@ export function enhanceHtml (html, customCss, highlightStyle = 'github') { return enhanced } -export async function generatePdf (page, html, outputPath, { timeout = 30000 } = {}) { - await page.setContent(html, { waitUntil: 'networkidle0', timeout }) +export async function generatePdf (page, html, outputPath, { timeout = 30000, url = null } = {}) { + const isFileUrl = url && url.startsWith('file://') + + let tempFile = null + if (isFileUrl) { + const sourceDir = path.dirname(new URL(url).pathname) + tempFile = path.join(sourceDir, `.pdfy-temp-${Date.now()}.html`) + fs.writeFileSync(tempFile, html) + await page.goto(pathToFileURL(tempFile).href, { waitUntil: 'networkidle0', timeout }) + } else { + await page.setContent(html, { waitUntil: 'networkidle0', timeout }) + } + await page.waitForFunction( () => Array.from(document.images).every(img => img.complete), { timeout, polling: 200 } @@ -68,5 +80,8 @@ export async function generatePdf (page, html, outputPath, { timeout = 30000 } = if (outputPath) { logger.info(`PDF saved: "${outputPath}"`) } + if (tempFile) { + try { fs.unlinkSync(tempFile) } catch { } + } return buffer } diff --git a/src/pdfy.js b/src/pdfy.js index 0f915f3..a0dae0d 100644 --- a/src/pdfy.js +++ b/src/pdfy.js @@ -124,7 +124,7 @@ export async function convert (url, options = {}) { fs.mkdirSync(path.dirname(outputPath), { recursive: true }) } - const pdfBuffer = await generatePdf(pdfPage, enhancedHtml, outputPath, { timeout }) + const pdfBuffer = await generatePdf(pdfPage, enhancedHtml, outputPath, { timeout, url }) await pdfPage.close() return { title, pdfBuffer, outputPath }