All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
En prod le PDF est dans .output/public/, pas dans public/. Cherche dans les deux emplacements (dev et prod). Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
52 lines
1.5 KiB
TypeScript
52 lines
1.5 KiB
TypeScript
import { join } from 'node:path'
|
|
import { readFileSync, existsSync } from 'node:fs'
|
|
|
|
export default defineEventHandler(async () => {
|
|
const config = await readYaml('bookplayer.config.yml')
|
|
const pdfFile = config?.book?.pdfFile || '/pdf/une-economie-du-don.pdf'
|
|
|
|
// En dev : public/, en prod : .output/public/
|
|
const cwd = process.cwd()
|
|
const candidates = [
|
|
join(cwd, 'public', pdfFile),
|
|
join(cwd, '.output', 'public', pdfFile),
|
|
]
|
|
const pdfPath = candidates.find(p => existsSync(p))
|
|
if (!pdfPath) return []
|
|
|
|
let data: Uint8Array
|
|
try {
|
|
data = new Uint8Array(readFileSync(pdfPath))
|
|
} catch {
|
|
return []
|
|
}
|
|
|
|
const pdfjsLib = await import('pdfjs-dist/legacy/build/pdf.mjs')
|
|
const doc = await pdfjsLib.getDocument({ data, useSystemFonts: true }).promise
|
|
const outline = await doc.getOutline()
|
|
|
|
if (!outline || outline.length === 0) {
|
|
doc.destroy()
|
|
return []
|
|
}
|
|
|
|
const entries: Array<{ title: string; page: number; level: number }> = []
|
|
|
|
async function extract(items: any[], level: number) {
|
|
for (const item of items) {
|
|
let page: number | null = null
|
|
try {
|
|
let dest = item.dest
|
|
if (typeof dest === 'string') dest = await doc.getDestination(dest)
|
|
if (dest) page = (await doc.getPageIndex(dest[0])) + 1
|
|
} catch {}
|
|
if (page !== null) entries.push({ title: item.title, page, level })
|
|
if (item.items?.length) await extract(item.items, level + 1)
|
|
}
|
|
}
|
|
|
|
await extract(outline, 0)
|
|
doc.destroy()
|
|
return entries
|
|
})
|