feat(scripts): cached plugin bundle, single-plugin fetch, free-chapter prefix, nightly appender
- load-plugins: bundle once per source revision with an id index; loadPlugin(id) loads one plugin (144 ms / 87 MB instead of ~15 s / 1.2 GB). - fetch-novel: keep only the contiguous run of free chapters (no locked teasers). - update-novels: append newly free chapters to our EPUBs without moving positions. - find-novel --json for programs; shared EPUB pieces in epub.js. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,28 @@
|
||||
// EPUB pieces shared by fetch-novel.js (new books) and update-novels.js (appends).
|
||||
import { load } from 'cheerio';
|
||||
import { stripPromo } from './clean-chapter.js';
|
||||
|
||||
export const esc = s =>
|
||||
String(s ?? '').replace(
|
||||
/[&<>"]/g,
|
||||
c => ({ '&': '&', '<': '<', '>': '>', '"': '"' })[c],
|
||||
);
|
||||
|
||||
// Chapter HTML is tag soup; re-serialise it as well-formed XHTML without
|
||||
// scripts, remote resources (an EPUB must be self-contained) or promo lines.
|
||||
export const toXhtml = html => {
|
||||
const $ = load(html, null, false);
|
||||
$('script, style, iframe, link, meta, img, video, audio, source').remove();
|
||||
stripPromo($);
|
||||
return $.xml();
|
||||
};
|
||||
|
||||
export const page = (title, body) => `<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE html>
|
||||
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:epub="http://www.idpf.org/2007/ops" lang="en" xml:lang="en">
|
||||
<head><meta charset="UTF-8"/><title>${esc(title)}</title></head>
|
||||
<body>${body}</body>
|
||||
</html>`;
|
||||
|
||||
export const chapterPage = (title, body) =>
|
||||
page(title, `<h2>${esc(title)}</h2>\n${body}`);
|
||||
Reference in New Issue
Block a user