mirror of
https://github.com/NohamR/pdfy.git
synced 2026-10-10 18:29:55 +00:00
Support local HTML files for conversion
Allow the CLI argument to be either a remote URL or a local HTML path, and document the new usage in README/help examples.
This commit is contained in:
@@ -30,7 +30,7 @@ node src/index.js --help
|
||||
Usage: pdfy [options] <url>
|
||||
|
||||
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 <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 <path>` 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
|
||||
|
||||
@@ -16,7 +16,7 @@ const program = new Command()
|
||||
program
|
||||
.name('pdfy')
|
||||
.description('Convert web articles to PDF using Reader View and Puppeteer')
|
||||
.argument('<url>', 'URL of the article to convert')
|
||||
.argument('<url>', 'URL of the article to convert, or path to a local HTML file')
|
||||
.option(
|
||||
'-t, --theme <theme>',
|
||||
`Reader View theme (${VALID_THEMES.join(', ')})`
|
||||
@@ -42,6 +42,8 @@ program
|
||||
Examples:
|
||||
node src/index.js <URL>
|
||||
node src/index.js <URL> --theme dark --highlight-style monokai --css config/rules.css
|
||||
node src/index.js <path/to/file.html> --theme dark --highlight-style monokai
|
||||
node src/index.js <URL> --prefs config/reader-view-preferences.json
|
||||
npm start -- <URL> --theme dark --highlight-style monokai --css config/rules.css
|
||||
`
|
||||
)
|
||||
|
||||
11
src/index.js
11
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
|
||||
|
||||
19
src/pdf.js
19
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
|
||||
}
|
||||
|
||||
@@ -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 }
|
||||
|
||||
Reference in New Issue
Block a user