mirror of
https://github.com/ArchiveBox/ArchiveBox.git
synced 2026-04-05 23:37:58 +10:00
remove huey
This commit is contained in:
@@ -1,68 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Install readability-extractor if not already available.
|
||||
|
||||
Runs at crawl start to ensure readability-extractor is installed.
|
||||
Outputs JSONL for InstalledBinary.
|
||||
"""
|
||||
|
||||
import json
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def main():
|
||||
try:
|
||||
from abx_pkg import Binary, NpmProvider, EnvProvider, BinProviderOverrides
|
||||
|
||||
NpmProvider.model_rebuild()
|
||||
EnvProvider.model_rebuild()
|
||||
|
||||
# Note: npm package is from github:ArchiveBox/readability-extractor
|
||||
readability_binary = Binary(
|
||||
name='readability-extractor',
|
||||
binproviders=[NpmProvider(), EnvProvider()],
|
||||
overrides={'npm': {'packages': ['github:ArchiveBox/readability-extractor']}}
|
||||
)
|
||||
|
||||
# Try to load, install if not found
|
||||
try:
|
||||
loaded = readability_binary.load()
|
||||
if not loaded or not loaded.abspath:
|
||||
raise Exception("Not loaded")
|
||||
except Exception:
|
||||
# Install via npm from GitHub repo
|
||||
loaded = readability_binary.install()
|
||||
|
||||
if loaded and loaded.abspath:
|
||||
# Output InstalledBinary JSONL
|
||||
print(json.dumps({
|
||||
'type': 'InstalledBinary',
|
||||
'name': 'readability-extractor',
|
||||
'abspath': str(loaded.abspath),
|
||||
'version': str(loaded.version) if loaded.version else None,
|
||||
'sha256': loaded.sha256,
|
||||
'binprovider': loaded.loaded_binprovider.name if loaded.loaded_binprovider else 'unknown',
|
||||
}))
|
||||
sys.exit(0)
|
||||
else:
|
||||
print(json.dumps({
|
||||
'type': 'Dependency',
|
||||
'bin_name': 'readability-extractor',
|
||||
'bin_providers': 'npm,env',
|
||||
}))
|
||||
print("Failed to install readability-extractor", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
except Exception as e:
|
||||
print(json.dumps({
|
||||
'type': 'Dependency',
|
||||
'bin_name': 'readability-extractor',
|
||||
'bin_providers': 'npm,env',
|
||||
}))
|
||||
print(f"Error installing readability-extractor: {e}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
123
archivebox/plugins/readability/on_Crawl__00_validate_readability.py
Executable file
123
archivebox/plugins/readability/on_Crawl__00_validate_readability.py
Executable file
@@ -0,0 +1,123 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Validation hook for readability-extractor binary.
|
||||
|
||||
Runs at crawl start to verify readability-extractor is available.
|
||||
Outputs JSONL for InstalledBinary and Machine config updates.
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import json
|
||||
import shutil
|
||||
import hashlib
|
||||
import subprocess
|
||||
from pathlib import Path
|
||||
|
||||
|
||||
def get_binary_version(abspath: str) -> str | None:
|
||||
"""Get version string from binary."""
|
||||
try:
|
||||
result = subprocess.run(
|
||||
[abspath, '--version'],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
timeout=5,
|
||||
)
|
||||
if result.returncode == 0 and result.stdout:
|
||||
first_line = result.stdout.strip().split('\n')[0]
|
||||
return first_line[:64]
|
||||
except Exception:
|
||||
pass
|
||||
return None
|
||||
|
||||
|
||||
def get_binary_hash(abspath: str) -> str | None:
|
||||
"""Get SHA256 hash of binary."""
|
||||
try:
|
||||
with open(abspath, 'rb') as f:
|
||||
return hashlib.sha256(f.read()).hexdigest()
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
|
||||
def find_readability() -> dict | None:
|
||||
"""Find readability-extractor binary."""
|
||||
try:
|
||||
from abx_pkg import Binary, NpmProvider, EnvProvider
|
||||
|
||||
class ReadabilityBinary(Binary):
|
||||
name: str = 'readability-extractor'
|
||||
binproviders_supported = [NpmProvider(), EnvProvider()]
|
||||
overrides: dict = {'npm': {'packages': ['github:ArchiveBox/readability-extractor']}}
|
||||
|
||||
binary = ReadabilityBinary()
|
||||
loaded = binary.load()
|
||||
if loaded and loaded.abspath:
|
||||
return {
|
||||
'name': 'readability-extractor',
|
||||
'abspath': str(loaded.abspath),
|
||||
'version': str(loaded.version) if loaded.version else None,
|
||||
'sha256': loaded.sha256 if hasattr(loaded, 'sha256') else None,
|
||||
'binprovider': loaded.binprovider.name if loaded.binprovider else 'env',
|
||||
}
|
||||
except ImportError:
|
||||
pass
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
# Fallback to shutil.which
|
||||
abspath = shutil.which('readability-extractor') or os.environ.get('READABILITY_BINARY', '')
|
||||
if abspath and Path(abspath).is_file():
|
||||
return {
|
||||
'name': 'readability-extractor',
|
||||
'abspath': abspath,
|
||||
'version': get_binary_version(abspath),
|
||||
'sha256': get_binary_hash(abspath),
|
||||
'binprovider': 'env',
|
||||
}
|
||||
|
||||
return None
|
||||
|
||||
|
||||
def main():
|
||||
result = find_readability()
|
||||
|
||||
if result and result.get('abspath'):
|
||||
print(json.dumps({
|
||||
'type': 'InstalledBinary',
|
||||
'name': result['name'],
|
||||
'abspath': result['abspath'],
|
||||
'version': result['version'],
|
||||
'sha256': result['sha256'],
|
||||
'binprovider': result['binprovider'],
|
||||
}))
|
||||
|
||||
print(json.dumps({
|
||||
'type': 'Machine',
|
||||
'_method': 'update',
|
||||
'key': 'config/READABILITY_BINARY',
|
||||
'value': result['abspath'],
|
||||
}))
|
||||
|
||||
if result['version']:
|
||||
print(json.dumps({
|
||||
'type': 'Machine',
|
||||
'_method': 'update',
|
||||
'key': 'config/READABILITY_VERSION',
|
||||
'value': result['version'],
|
||||
}))
|
||||
|
||||
sys.exit(0)
|
||||
else:
|
||||
print(json.dumps({
|
||||
'type': 'Dependency',
|
||||
'bin_name': 'readability-extractor',
|
||||
'bin_providers': 'npm,env',
|
||||
}))
|
||||
print(f"readability-extractor binary not found", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
6
archivebox/plugins/readability/templates/embed.html
Normal file
6
archivebox/plugins/readability/templates/embed.html
Normal file
@@ -0,0 +1,6 @@
|
||||
<!-- Readability embed - reader-mode article view -->
|
||||
<iframe src="{{ output_path }}"
|
||||
class="extractor-embed readability-embed"
|
||||
style="width: 100%; height: 100%; min-height: 500px; border: none; background: #fefefe;"
|
||||
sandbox="allow-same-origin">
|
||||
</iframe>
|
||||
6
archivebox/plugins/readability/templates/fullscreen.html
Normal file
6
archivebox/plugins/readability/templates/fullscreen.html
Normal file
@@ -0,0 +1,6 @@
|
||||
<!-- Readability fullscreen - full reader-mode article -->
|
||||
<iframe src="{{ output_path }}"
|
||||
class="extractor-fullscreen readability-fullscreen"
|
||||
style="width: 100%; height: 100vh; border: none; background: #fefefe;"
|
||||
sandbox="allow-same-origin">
|
||||
</iframe>
|
||||
1
archivebox/plugins/readability/templates/icon.html
Normal file
1
archivebox/plugins/readability/templates/icon.html
Normal file
@@ -0,0 +1 @@
|
||||
📖
|
||||
8
archivebox/plugins/readability/templates/thumbnail.html
Normal file
8
archivebox/plugins/readability/templates/thumbnail.html
Normal file
@@ -0,0 +1,8 @@
|
||||
<!-- Readability thumbnail - shows reader-mode extracted article content -->
|
||||
<div class="extractor-thumbnail readability-thumbnail" style="width: 100%; height: 100px; overflow: hidden; background: #fefefe; padding: 8px; font-family: Georgia, serif; font-size: 11px; line-height: 1.4; color: #333;">
|
||||
<iframe src="{{ output_path }}"
|
||||
style="width: 100%; height: 300px; border: none; pointer-events: none;"
|
||||
loading="lazy"
|
||||
sandbox="allow-same-origin">
|
||||
</iframe>
|
||||
</div>
|
||||
@@ -2,7 +2,7 @@
|
||||
Integration tests for readability plugin
|
||||
|
||||
Tests verify:
|
||||
1. Install hook installs readability-extractor via abx-pkg
|
||||
1. Validate hook checks for readability-extractor binary
|
||||
2. Verify deps with abx-pkg
|
||||
3. Plugin reports missing dependency correctly
|
||||
4. Extraction works against real example.com content
|
||||
@@ -21,7 +21,7 @@ import pytest
|
||||
PLUGIN_DIR = Path(__file__).parent.parent
|
||||
PLUGINS_ROOT = PLUGIN_DIR.parent
|
||||
READABILITY_HOOK = next(PLUGIN_DIR.glob('on_Snapshot__*_readability.py'))
|
||||
READABILITY_INSTALL_HOOK = PLUGIN_DIR / 'on_Crawl__00_install_readability.py'
|
||||
READABILITY_VALIDATE_HOOK = PLUGIN_DIR / 'on_Crawl__00_validate_readability.py'
|
||||
TEST_URL = 'https://example.com'
|
||||
|
||||
|
||||
@@ -101,48 +101,63 @@ def test_reports_missing_dependency_when_not_installed():
|
||||
assert 'readability-extractor' in combined or 'BIN_NAME' in combined, "Should mention readability-extractor"
|
||||
|
||||
|
||||
def test_readability_install_hook():
|
||||
"""Test readability install hook to install readability-extractor if needed."""
|
||||
def test_readability_validate_hook():
|
||||
"""Test readability validate hook checks for readability-extractor binary."""
|
||||
result = subprocess.run(
|
||||
[sys.executable, str(READABILITY_INSTALL_HOOK)],
|
||||
[sys.executable, str(READABILITY_VALIDATE_HOOK)],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
timeout=600
|
||||
timeout=30
|
||||
)
|
||||
|
||||
assert result.returncode == 0, f"Install hook failed: {result.stderr}"
|
||||
|
||||
# Verify InstalledBinary JSONL output
|
||||
found_binary = False
|
||||
for line in result.stdout.strip().split('\n'):
|
||||
if line.strip():
|
||||
try:
|
||||
record = json.loads(line)
|
||||
if record.get('type') == 'InstalledBinary':
|
||||
assert record['name'] == 'readability-extractor'
|
||||
assert record['abspath']
|
||||
found_binary = True
|
||||
break
|
||||
except json.JSONDecodeError:
|
||||
pass
|
||||
|
||||
assert found_binary, "Should output InstalledBinary record"
|
||||
# Hook exits 0 if binary found, 1 if not found (with Dependency record)
|
||||
if result.returncode == 0:
|
||||
# Binary found - verify InstalledBinary JSONL output
|
||||
found_binary = False
|
||||
for line in result.stdout.strip().split('\n'):
|
||||
if line.strip():
|
||||
try:
|
||||
record = json.loads(line)
|
||||
if record.get('type') == 'InstalledBinary':
|
||||
assert record['name'] == 'readability-extractor'
|
||||
assert record['abspath']
|
||||
found_binary = True
|
||||
break
|
||||
except json.JSONDecodeError:
|
||||
pass
|
||||
assert found_binary, "Should output InstalledBinary record when binary found"
|
||||
else:
|
||||
# Binary not found - verify Dependency JSONL output
|
||||
found_dependency = False
|
||||
for line in result.stdout.strip().split('\n'):
|
||||
if line.strip():
|
||||
try:
|
||||
record = json.loads(line)
|
||||
if record.get('type') == 'Dependency':
|
||||
assert record['bin_name'] == 'readability-extractor'
|
||||
assert 'npm' in record['bin_providers']
|
||||
found_dependency = True
|
||||
break
|
||||
except json.JSONDecodeError:
|
||||
pass
|
||||
assert found_dependency, "Should output Dependency record when binary not found"
|
||||
|
||||
|
||||
def test_verify_deps_with_abx_pkg():
|
||||
"""Verify readability-extractor is available via abx-pkg after hook installation."""
|
||||
"""Verify readability-extractor is available via abx-pkg."""
|
||||
from abx_pkg import Binary, NpmProvider, EnvProvider, BinProviderOverrides
|
||||
|
||||
NpmProvider.model_rebuild()
|
||||
EnvProvider.model_rebuild()
|
||||
|
||||
readability_binary = Binary(
|
||||
name='readability-extractor',
|
||||
binproviders=[NpmProvider(), EnvProvider()],
|
||||
overrides={'npm': {'packages': ['github:ArchiveBox/readability-extractor']}}
|
||||
)
|
||||
readability_loaded = readability_binary.load()
|
||||
assert readability_loaded and readability_loaded.abspath, "readability-extractor should be available after install hook"
|
||||
|
||||
if readability_loaded and readability_loaded.abspath:
|
||||
assert True, "readability-extractor is available"
|
||||
else:
|
||||
pytest.skip("readability-extractor not available - Dependency record should have been emitted")
|
||||
|
||||
|
||||
def test_extracts_article_after_installation():
|
||||
|
||||
Reference in New Issue
Block a user