mirror of
https://github.com/thegeneralist01/archivr
synced 2026-07-22 03:05:32 +02:00
fix: use correct single-file hook event (single-file-on-before-capture-request)
Prior scripts listened on 'single-file-on-before-capture-start' which does not exist in single-file-core 1.1.49. The real hook is: single-file-on-before-capture-request (dispatched by initUserScriptHandler after receiving single-file-user-script-init; userScriptEnabled defaults to true in args.js so it always fires when --browser-script is passed) Changes: - strip-scripts: -start -> -request (no preventDefault needed; synchronous) - READER_MODE_SCRIPT: -start -> -request; add 'installed' meta marker at script-evaluation time so artifact inspection can distinguish 'script not injected' / 'hook never fired' / 'Readability parse failed'
This commit is contained in:
parent
ef8b5ac83b
commit
b4e092f10d
1 changed files with 87 additions and 53 deletions
|
|
@ -13,18 +13,47 @@ use crate::downloader::cookies::{domain_from_url, write_netscape_cookie_file};
|
||||||
use crate::hash::hash_file;
|
use crate::hash::hash_file;
|
||||||
|
|
||||||
/// Mozilla Readability.js (Apache 2.0) — embedded at compile time so captures
|
/// Mozilla Readability.js (Apache 2.0) — embedded at compile time so captures
|
||||||
/// don't need it on PATH. Path is relative to this source file.
|
/// Combined reader-mode script: Readability.js (Apache 2.0) bundled with the
|
||||||
const READABILITY_JS: &str =
|
/// archivr wrapper in a single IIFE so both share the same execution scope —
|
||||||
include_str!("../../../../vendor/readability/Readability.js");
|
/// passing them as separate `--browser-script` files can put each in its own
|
||||||
|
/// context (observed with single-file-cli 1.1.49), making Readability invisible
|
||||||
/// Single-file user script that applies Readability just before the page is
|
/// to the wrapper.
|
||||||
/// serialised. Fires on `single-file-on-before-capture-start`.
|
///
|
||||||
const READER_MODE_WRAPPER_JS: &str = r#"
|
/// Emits `<meta name="archivr-reader-mode" content="applied|failed:REASON">`
|
||||||
addEventListener('single-file-on-before-capture-start', function() {
|
/// so the outcome is observable in the saved HTML.
|
||||||
|
const READER_MODE_SCRIPT: &str = concat!(
|
||||||
|
// Readability.js is injected verbatim first so `Readability` is in scope.
|
||||||
|
include_str!("../../../../vendor/readability/Readability.js"),
|
||||||
|
// Wrapper IIFE — runs on single-file-on-before-capture-request.
|
||||||
|
// Sets 'installed' immediately at script-evaluation time so a missing meta
|
||||||
|
// means the browser-script was never injected at all.
|
||||||
|
r#"
|
||||||
|
;(function() {
|
||||||
|
function _archivrReaderMark(content) {
|
||||||
try {
|
try {
|
||||||
if (typeof Readability === 'undefined') return;
|
var m = document.querySelector('meta[name="archivr-reader-mode"]');
|
||||||
|
if (!m) {
|
||||||
|
m = document.createElement('meta');
|
||||||
|
m.name = 'archivr-reader-mode';
|
||||||
|
(document.head || document.documentElement).appendChild(m);
|
||||||
|
}
|
||||||
|
m.content = content;
|
||||||
|
} catch(_) {}
|
||||||
|
}
|
||||||
|
// Mark immediately: if this meta is absent in the artifact the script
|
||||||
|
// was never injected (separate from the hook never firing).
|
||||||
|
_archivrReaderMark('installed');
|
||||||
|
function _archivrApplyReader() {
|
||||||
|
try {
|
||||||
|
if (typeof Readability === 'undefined') {
|
||||||
|
_archivrReaderMark('failed:no-readability');
|
||||||
|
return;
|
||||||
|
}
|
||||||
var article = new Readability(document.cloneNode(true)).parse();
|
var article = new Readability(document.cloneNode(true)).parse();
|
||||||
if (!article || !article.content || article.content.length < 100) return;
|
if (!article || !article.content || article.content.length < 100) {
|
||||||
|
_archivrReaderMark('failed:no-article');
|
||||||
|
return;
|
||||||
|
}
|
||||||
document.body.innerHTML = article.content;
|
document.body.innerHTML = article.content;
|
||||||
if (article.title) document.title = article.title;
|
if (article.title) document.title = article.title;
|
||||||
var hdr = document.createElement('header');
|
var hdr = document.createElement('header');
|
||||||
|
|
@ -53,9 +82,16 @@ addEventListener('single-file-on-before-capture-start', function() {
|
||||||
'blockquote{border-left:3px solid #ccc;margin:1em 0;padding-left:1.2em;color:#555}',
|
'blockquote{border-left:3px solid #ccc;margin:1em 0;padding-left:1.2em;color:#555}',
|
||||||
].join('');
|
].join('');
|
||||||
document.head.appendChild(style);
|
document.head.appendChild(style);
|
||||||
} catch (e) { /* non-fatal: fall back to original page */ }
|
_archivrReaderMark('applied');
|
||||||
});
|
} catch (e) {
|
||||||
"#;
|
_archivrReaderMark('failed:exception:' + (e && e.message ? e.message : String(e)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Synchronous work — no preventDefault()/response dispatch needed.
|
||||||
|
addEventListener('single-file-on-before-capture-request', _archivrApplyReader);
|
||||||
|
})();
|
||||||
|
"#
|
||||||
|
);
|
||||||
|
|
||||||
/// Result of archiving a web page with single-file.
|
/// Result of archiving a web page with single-file.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
|
@ -183,24 +219,22 @@ fn save_with(
|
||||||
let strip_scripts_path = temp_dir.join("sf-strip-scripts.js");
|
let strip_scripts_path = temp_dir.join("sf-strip-scripts.js");
|
||||||
std::fs::write(
|
std::fs::write(
|
||||||
&strip_scripts_path,
|
&strip_scripts_path,
|
||||||
"addEventListener('single-file-on-before-capture-start',()=>{\
|
"addEventListener('single-file-on-before-capture-request',()=>{\
|
||||||
document.querySelectorAll('script:not([type=\"application/ld+json\"])')\
|
document.querySelectorAll('script:not([type=\"application/ld+json\"])')\
|
||||||
.forEach(el=>el.remove());\
|
.forEach(el=>el.remove());\
|
||||||
});",
|
});",
|
||||||
)
|
)
|
||||||
.context("failed to write single-file user script")?;
|
.context("failed to write single-file user script")?;
|
||||||
|
|
||||||
// Optional reader-mode scripts (Readability.js + wrapper).
|
// Optional reader-mode script: Readability.js + wrapper combined into one
|
||||||
|
// file so both run in the same execution scope. (Separate --browser-script
|
||||||
|
// files can each get their own context depending on single-file version.)
|
||||||
let mut extra_browser_scripts: Vec<PathBuf> = Vec::new();
|
let mut extra_browser_scripts: Vec<PathBuf> = Vec::new();
|
||||||
if reader_mode {
|
if reader_mode {
|
||||||
let readability_path = temp_dir.join("sf-readability.js");
|
let reader_path = temp_dir.join("sf-reader-mode.js");
|
||||||
std::fs::write(&readability_path, READABILITY_JS)
|
std::fs::write(&reader_path, READER_MODE_SCRIPT)
|
||||||
.context("failed to write Readability.js script")?;
|
.context("failed to write reader-mode script")?;
|
||||||
let wrapper_path = temp_dir.join("sf-reader-mode.js");
|
extra_browser_scripts.push(reader_path);
|
||||||
std::fs::write(&wrapper_path, READER_MODE_WRAPPER_JS)
|
|
||||||
.context("failed to write reader-mode wrapper script")?;
|
|
||||||
extra_browser_scripts.push(readability_path);
|
|
||||||
extra_browser_scripts.push(wrapper_path);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Isolated Chrome profile directory; cleaned up with the rest of temp.
|
// Isolated Chrome profile directory; cleaned up with the rest of temp.
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue