mirror of
https://github.com/thegeneralist01/archivr
synced 2026-07-22 11:15:41 +02:00
feat: uBlock Origin Lite integration for ad-blocking during WebPage captures
- singlefile.rs: when ARCHIVR_UBLOCK=true and ARCHIVR_UBLOCK_EXT is set,
archivr owns Chrome's lifecycle (--headless=new, --remote-debugging-port,
--load-extension); single-file connects via --browser-server instead of
launching its own Chrome. Falls back to old behaviour with ublock_skipped=true
when the ext path is missing or invalid.
- capture.rs: thread ublock_skipped through CaptureResult
- database.rs: add notes_json TEXT column to capture_jobs (DDL + idempotent
ALTER TABLE migration); update_capture_job_status gains notes_json param
- archive.rs: expose notes_json in CaptureJobSummary
- routes.rs: store {"ublock_skipped":true} in notes_json on completed captures
- ToastStack.jsx: warning toast variant (toast--warning) with Details expander
and Ignore button
- CaptureDialog.jsx: fire warning toast when poll result has ublock_skipped
- App.jsx: sessionStorage-backed Ignore suppression for ublock warnings
- styles.css: .toast--warning (amber left border) + .toast-warning-detail
- flake.nix: ublockLite derivation fetches uBOLite_2026.705.2152.chromium.zip
(pinned SHA256) from uBlockOrigin/uBOL-home; sets ARCHIVR_UBLOCK_EXT in both
archivr and archivr-server wrappers
Env vars:
ARCHIVR_UBLOCK=true (default) — enable uBlock during WebPage captures
ARCHIVR_UBLOCK_EXT — path to unpacked uBOL extension dir (set by Nix)
This commit is contained in:
parent
dae61e585d
commit
8a90259a76
14 changed files with 546 additions and 226 deletions
|
|
@ -105,6 +105,7 @@ pub struct CaptureJobRecord {
|
|||
pub run_uid: Option<String>,
|
||||
pub status: String,
|
||||
pub error_text: Option<String>,
|
||||
pub notes_json: Option<String>,
|
||||
pub created_at: String,
|
||||
pub updated_at: String,
|
||||
}
|
||||
|
|
@ -308,6 +309,7 @@ pub fn initialize_schema(conn: &Connection) -> Result<()> {
|
|||
run_uid TEXT,
|
||||
status TEXT NOT NULL CHECK (status IN ('pending','running','completed','failed')) DEFAULT 'pending',
|
||||
error_text TEXT,
|
||||
notes_json TEXT,
|
||||
created_at TEXT NOT NULL,
|
||||
updated_at TEXT NOT NULL
|
||||
);
|
||||
|
|
@ -393,6 +395,10 @@ pub fn initialize_schema(conn: &Connection) -> Result<()> {
|
|||
)?;
|
||||
}
|
||||
|
||||
// Migration: add notes_json column to existing capture_jobs tables.
|
||||
// Silently ignored when the column already exists (idempotent).
|
||||
let _ = conn.execute("ALTER TABLE capture_jobs ADD COLUMN notes_json TEXT", []);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
|
@ -1142,19 +1148,21 @@ pub fn create_capture_job(conn: &Connection, archive_id: &str) -> Result<String>
|
|||
Ok(job_uid)
|
||||
}
|
||||
|
||||
/// Updates the status (and optionally run_uid / error_text) of a capture job.
|
||||
/// Updates the status (and optionally run_uid / error_text / notes_json) of a capture job.
|
||||
pub fn update_capture_job_status(
|
||||
conn: &Connection,
|
||||
job_uid: &str,
|
||||
status: &str,
|
||||
run_uid: Option<&str>,
|
||||
error_text: Option<&str>,
|
||||
notes_json: Option<&str>,
|
||||
) -> Result<()> {
|
||||
let now = now_timestamp();
|
||||
conn.execute(
|
||||
"UPDATE capture_jobs SET status = ?1, run_uid = COALESCE(?2, run_uid),
|
||||
error_text = ?3, updated_at = ?4 WHERE job_uid = ?5",
|
||||
rusqlite::params![status, run_uid, error_text, now, job_uid],
|
||||
error_text = ?3, notes_json = COALESCE(?4, notes_json), updated_at = ?5
|
||||
WHERE job_uid = ?6",
|
||||
rusqlite::params![status, run_uid, error_text, notes_json, now, job_uid],
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
|
|
@ -1162,7 +1170,7 @@ pub fn update_capture_job_status(
|
|||
/// Returns a capture job by uid.
|
||||
pub fn get_capture_job(conn: &Connection, job_uid: &str) -> Result<Option<CaptureJobRecord>> {
|
||||
conn.query_row(
|
||||
"SELECT job_uid, archive_id, run_uid, status, error_text, created_at, updated_at
|
||||
"SELECT job_uid, archive_id, run_uid, status, error_text, notes_json, created_at, updated_at
|
||||
FROM capture_jobs WHERE job_uid = ?1",
|
||||
[job_uid],
|
||||
|row| {
|
||||
|
|
@ -1172,8 +1180,9 @@ pub fn get_capture_job(conn: &Connection, job_uid: &str) -> Result<Option<Captur
|
|||
run_uid: row.get(2)?,
|
||||
status: row.get(3)?,
|
||||
error_text: row.get(4)?,
|
||||
created_at: row.get(5)?,
|
||||
updated_at: row.get(6)?,
|
||||
notes_json: row.get(5)?,
|
||||
created_at: row.get(6)?,
|
||||
updated_at: row.get(7)?,
|
||||
})
|
||||
},
|
||||
)
|
||||
|
|
@ -2806,8 +2815,8 @@ mod tests {
|
|||
fn capture_job_status_transitions() {
|
||||
let conn = conn();
|
||||
let job_uid = create_capture_job(&conn, "test").unwrap();
|
||||
update_capture_job_status(&conn, &job_uid, "running", None, None).unwrap();
|
||||
update_capture_job_status(&conn, &job_uid, "completed", Some("run_abc"), None).unwrap();
|
||||
update_capture_job_status(&conn, &job_uid, "running", None, None, None).unwrap();
|
||||
update_capture_job_status(&conn, &job_uid, "completed", Some("run_abc"), None, None).unwrap();
|
||||
let job = get_capture_job(&conn, &job_uid).unwrap().unwrap();
|
||||
assert_eq!(job.status, "completed");
|
||||
assert_eq!(job.run_uid.as_deref(), Some("run_abc"));
|
||||
|
|
@ -2819,7 +2828,7 @@ mod tests {
|
|||
|
||||
// Simulate an in-progress capture_job (run_uid still NULL — common crash case).
|
||||
let uid = create_capture_job(&conn, "test").unwrap();
|
||||
update_capture_job_status(&conn, &uid, "running", None, None).unwrap();
|
||||
update_capture_job_status(&conn, &uid, "running", None, None, None).unwrap();
|
||||
|
||||
// Simulate an in-progress archive_run and item with no associated capture_job
|
||||
// (covers the case where run_uid was never written back before the crash).
|
||||
|
|
@ -3177,7 +3186,7 @@ mod tests {
|
|||
fn has_active_capture_jobs_true_for_running() {
|
||||
let conn = conn();
|
||||
let uid = create_capture_job(&conn, "test").unwrap();
|
||||
update_capture_job_status(&conn, &uid, "running", None, None).unwrap();
|
||||
update_capture_job_status(&conn, &uid, "running", None, None, None).unwrap();
|
||||
assert!(has_active_capture_jobs(&conn).unwrap());
|
||||
}
|
||||
|
||||
|
|
@ -3185,7 +3194,7 @@ mod tests {
|
|||
fn has_active_capture_jobs_false_for_completed() {
|
||||
let conn = conn();
|
||||
let uid = create_capture_job(&conn, "test").unwrap();
|
||||
update_capture_job_status(&conn, &uid, "completed", Some("run_x"), None).unwrap();
|
||||
update_capture_job_status(&conn, &uid, "completed", Some("run_x"), None, None).unwrap();
|
||||
assert!(!has_active_capture_jobs(&conn).unwrap());
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue