63 lines
3.1 KiB
Python
63 lines
3.1 KiB
Python
#!/usr/bin/env python3
|
|
"""Extract the saved inner artifact, preserving its UI and inference code."""
|
|
from pathlib import Path
|
|
import concurrent.futures
|
|
import hashlib
|
|
import json
|
|
import re
|
|
import urllib.request
|
|
import zipfile
|
|
|
|
ROOT = Path(__file__).resolve().parent
|
|
ARCHIVE = ROOT.parent / 'reports/2026-10-21/artifact/chrome-export.zip'
|
|
OUT = ROOT / 'site'
|
|
OUT.mkdir(exist_ok=True)
|
|
with zipfile.ZipFile(ARCHIVE) as z:
|
|
names = z.namelist()
|
|
inner = next(n for n in names if n.endswith('/saved_resource.html'))
|
|
original = z.read(inner).decode('utf-8')
|
|
css = z.read(next(n for n in names if n.endswith('/css2'))).decode('utf-8')
|
|
scripts = re.findall(r'<script\b[^>]*>(.*?)</script>', original, re.S)
|
|
assert len(scripts) == 3 and scripts[2].lstrip().startswith('const D = ')
|
|
app = scripts[2]
|
|
# Chrome saves the already populated DOM. The original code appends these controls.
|
|
reset = '// Remove Chrome-saved controls before the original application recreates them.\n' \
|
|
'document.getElementById("switch").replaceChildren();\n' \
|
|
'document.getElementById("gal").replaceChildren();\n'
|
|
(OUT / 'app.js').write_text(reset + app)
|
|
html = re.sub(r'<script\b[^>]*>.*?</script>', '', original, flags=re.S)
|
|
html = re.sub(r'<!-- saved from url=.*?-->', '', html)
|
|
html = html.replace('<html>', '<html lang="ru">', 1)
|
|
html = html.replace('<head>', '<head><meta name="viewport" content="width=device-width,initial-scale=1,viewport-fit=cover">', 1)
|
|
html = html.replace('href="./css2"', 'href="./fonts.css"')
|
|
html = re.sub(r'<link rel="preconnect"[^>]*>', '', html)
|
|
html = html.replace('</body>', '<script src="./app.js"></script>\n</body>')
|
|
(OUT / 'index.html').write_text(html)
|
|
fonts = OUT / 'fonts'
|
|
fonts.mkdir(exist_ok=True)
|
|
urls = sorted(set(re.findall(r'url\((https://[^)]+)\)', css)))
|
|
def fetch(url):
|
|
name = hashlib.sha256(url.encode()).hexdigest()[:20] + '.woff2'
|
|
target = fonts / name
|
|
if not target.exists():
|
|
with urllib.request.urlopen(url, timeout=30) as r:
|
|
target.write_bytes(r.read())
|
|
return url, './fonts/' + name
|
|
with concurrent.futures.ThreadPoolExecutor(max_workers=6) as pool:
|
|
for url, local in pool.map(fetch, urls):
|
|
css = css.replace(url, local)
|
|
(OUT / 'fonts.css').write_text(css)
|
|
manifest = {
|
|
'source': 'https://claude.ai/artifact/Vc1q1WCZuPY2QAHBSGtrKF',
|
|
'export_url': 'http://drop.t.snw.su/mearl',
|
|
'archive_sha256': hashlib.sha256(ARCHIVE.read_bytes()).hexdigest(),
|
|
'inner_html_sha256': hashlib.sha256(original.encode()).hexdigest(),
|
|
'original_app_sha256': hashlib.sha256(app.encode()).hexdigest(),
|
|
'changes': ['remove Claude iframe runtime', 'clear saved controls before original startup',
|
|
'local font files', 'viewport and Russian document language'],
|
|
'inference_code_and_weights': 'preserved verbatim after the control-reset prelude',
|
|
'files': {str(p.relative_to(OUT)): hashlib.sha256(p.read_bytes()).hexdigest()
|
|
for p in sorted(OUT.rglob('*')) if p.is_file()},
|
|
}
|
|
(ROOT / 'SOURCE.json').write_text(json.dumps(manifest, ensure_ascii=False, indent=2) + '\n')
|
|
print(json.dumps({'fonts': len(urls), 'files': len(manifest['files']), 'archive_sha256': manifest['archive_sha256']}))
|