No active crawls
@@ -625,7 +621,7 @@
const treeContainer = document.getElementById('tree-container');
const crawlTree = document.getElementById('crawl-tree');
const idleMessage = document.getElementById('idle-message');
- const thumbnailStrip = document.getElementById('thumbnail-strip');
+ const thumbnailStrip = null;
let pollInterval = null;
let pollDelayMs = 1000;
@@ -697,65 +693,8 @@
}
- function renderThumbnail(thumb, isNew) {
- const ext = (thumb.embed_path || '').toLowerCase().split('.').pop();
- const isImage = ['png', 'jpg', 'jpeg', 'gif', 'webp', 'svg', 'ico'].includes(ext);
-
- const item = document.createElement('a');
- item.className = 'thumbnail-item' + (isNew ? ' new' : '');
- item.href = `/admin/core/snapshot/${thumb.snapshot_id}/change/`;
- item.title = `${thumb.plugin}: ${thumb.snapshot_url}`;
- item.dataset.id = thumb.id;
-
- const archiveUrl = thumb.archive_url || thumb.archive_path;
- if (isImage && archiveUrl) {
- item.innerHTML = `
-

-
${thumb.plugin}
- `;
- } else {
- item.innerHTML = `
-
${getPluginIcon(thumb.plugin)}
-
${thumb.plugin}
- `;
- }
-
- return item;
- }
-
- function updateThumbnails(thumbnails) {
- if (!thumbnails || thumbnails.length === 0) {
- thumbnailStrip.classList.add('empty');
- return;
- }
-
- thumbnailStrip.classList.remove('empty');
-
- // Find new thumbnails (ones we haven't seen before)
- const newThumbs = thumbnails.filter(t => !knownThumbnailIds.has(t.id));
-
- // Add new thumbnails to the beginning (after the label)
- const label = thumbnailStrip.querySelector('.thumbnail-label');
- newThumbs.reverse().forEach(thumb => {
- const item = renderThumbnail(thumb, true);
- if (label.nextSibling) {
- thumbnailStrip.insertBefore(item, label.nextSibling);
- } else {
- thumbnailStrip.appendChild(item);
- }
- knownThumbnailIds.add(thumb.id);
- });
-
- // Limit to 20 thumbnails (remove old ones)
- const items = thumbnailStrip.querySelectorAll('.thumbnail-item');
- if (items.length > 20) {
- for (let i = 20; i < items.length; i++) {
- const id = items[i].dataset.id;
- knownThumbnailIds.delete(id);
- items[i].remove();
- }
- }
- }
+ function renderThumbnail(thumb, isNew) { return null; }
+ function updateThumbnails(thumbnails) {}
function renderExtractor(extractor) {
const icon = extractor.status === 'started' ? '↻' :
@@ -1009,8 +948,7 @@
crawlTree.innerHTML = '';
}
- // Update thumbnail strip with recently completed results
- updateThumbnails(data.recent_thumbnails || []);
+ // Recent thumbnails removed
}
function fetchProgress() {
diff --git a/archivebox/templates/core/snapshot.html b/archivebox/templates/core/snapshot.html
index 6adbf7c4..0ad5a226 100644
--- a/archivebox/templates/core/snapshot.html
+++ b/archivebox/templates/core/snapshot.html
@@ -717,7 +717,7 @@
{{ result_info.path }}
- {{ result_info.name|plugin_display_name|title }}
+ {{ result_info.name|title }}
{% if result_info.result %}
{% with plugin_base=result_info.name|plugin_name %}
diff --git a/archivebox/tests/test_auth_ldap.py b/archivebox/tests/test_auth_ldap.py
index a56d29f7..10972acd 100644
--- a/archivebox/tests/test_auth_ldap.py
+++ b/archivebox/tests/test_auth_ldap.py
@@ -63,7 +63,7 @@ class TestLDAPConfig(unittest.TestCase):
config = LDAPConfig(
LDAP_ENABLED=True,
- LDAP_SERVER_URI="ldap://localhost:389",
+ LDAP_SERVER_URI="ldap://ldap-test.localhost:389",
LDAP_BIND_DN="cn=admin,dc=example,dc=com",
LDAP_BIND_PASSWORD="password",
LDAP_USER_BASE="ou=users,dc=example,dc=com",
@@ -172,7 +172,7 @@ class TestArchiveBoxWithLDAP(unittest.TestCase):
env={
**os.environ,
'LDAP_ENABLED': 'False',
- 'LDAP_SERVER_URI': 'ldap://localhost:389',
+ 'LDAP_SERVER_URI': 'ldap://ldap-test.localhost:389',
}
)
diff --git a/archivebox/tests/test_hooks.py b/archivebox/tests/test_hooks.py
index 308633ba..9d0afa0e 100755
--- a/archivebox/tests/test_hooks.py
+++ b/archivebox/tests/test_hooks.py
@@ -468,7 +468,7 @@ class TestPluginMetadata(unittest.TestCase):
def test_plugin_name_added(self):
"""run_hook() should add plugin name to records."""
# Simulate what run_hook() does
- script = Path('/archivebox/plugins/wget/on_Snapshot__50_wget.py')
+ script = Path('/abx_plugins/plugins/wget/on_Snapshot__50_wget.py')
plugin_name = script.parent.name
record = {'type': 'ArchiveResult', 'status': 'succeeded'}
diff --git a/archivebox/workers/orchestrator.py b/archivebox/workers/orchestrator.py
index 6465ef88..c83d4a55 100644
--- a/archivebox/workers/orchestrator.py
+++ b/archivebox/workers/orchestrator.py
@@ -3,13 +3,16 @@ Orchestrator for managing worker processes.
The Orchestrator polls the Crawl queue and spawns CrawlWorkers as needed.
-Architecture:
- Orchestrator (polls Crawl queue)
- āāā CrawlWorker(s) (one per active Crawl)
- āāā SnapshotWorker(s) (one per Snapshot, up to limit)
- āāā Hook Processes (sequential, forked by SnapshotWorker)
+Orchestrator (takes list of specific crawls | polls for pending queued crawls forever) spawns:
+āāā CrawlWorker(s) (one per active Crawl)
+ āāā SnapshotWorker(s) (one per Snapshot, up to limit)
+ āāā Hook Processes (sequential, forked by SnapshotWorker)
+ e.g on_Snapshot__23_save_pdf.js
+ on_Snapshot__24_save_screenshot.js
+ ...
Usage:
+
# Default: runs forever (for use as subprocess of server)
orchestrator = Orchestrator(exit_on_idle=False)
orchestrator.runloop()
diff --git a/pyproject.toml b/pyproject.toml
index 65983d51..23f34ab7 100755
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -84,6 +84,7 @@ dependencies = [
"yt-dlp>=2024.1.0", # for: media extractor
### Binary/Package Management
"abx-pkg>=0.1.0", # for: detecting, versioning, and installing binaries via apt/brew/pip/npm
+ "abx-plugins>=0.1.0", # shared plugin package (sourced from uv workspace in local dev)
"gallery-dl>=1.31.1",
### UUID7 backport for Python <3.14
"uuid7>=0.1.0; python_version < '3.14'", # for: uuid7 support on Python 3.13 (provides uuid_extensions module)
@@ -164,6 +165,9 @@ package = true
python-version = "3.13"
# compile-bytecode = true
+[tool.uv.sources]
+abx-plugins = { workspace = true }
+
[build-system]
requires = ["pdm-backend"]
build-backend = "pdm.backend"