Add Chinese covers and source-bound library edition metadata

This commit is contained in:
Kai Tan
2026-10-08 12:58:32 +08:00
parent 8297e6d2c8
commit 5dbd7bd240
14 changed files with 699 additions and 3 deletions
+12 -2
View File
@@ -196,10 +196,14 @@ def coverage_report(manifest, source, structure=None):
def audit_pair(source, translated, manifest=None, structure=None):
from src.edition.localize import audit_edition
edition = audit_edition(translated)
before = book_inventory(source)
after = book_inventory(translated)
sa, ta = audit_epub(source), audit_epub(translated)
issues = compare_audits(sa, ta) + compare_navigation(before, after)
if edition:
issues.extend({'kind': error, 'detail': 'Inspect edition cover/metadata'} for error in edition['issues'])
baseline_nav = navigation_markup(before)
issues.extend(f for f in navigation_markup(after) if f not in baseline_nav)
for name, digest in before['binaries'].items():
@@ -252,7 +256,7 @@ def audit_pair(source, translated, manifest=None, structure=None):
'source_sha256': hashlib.sha256(Path(source).read_bytes()).hexdigest(),
'translated_sha256': hashlib.sha256(Path(translated).read_bytes()).hexdigest(),
'source_audit': sa, 'translated_audit': ta, 'new_issues': issues,
'coverage': coverage, 'toc_items': len(after['toc']),
'coverage': coverage, 'edition': edition, 'toc_items': len(after['toc']),
'unchanged_binary_resources': len(before['binaries']),
'notes': {'source': sn, 'translated': tn}, 'visual_review': 'pending',
'render_status': 'not_requested', 'semantic_review': 'pending'}, before, after
@@ -304,6 +308,11 @@ LAYOUT_JS = """() => {
def render_pair(source, translated, before, after, out, chapters=None, max_documents=4, pages=2, width=900, height=1200):
from playwright.sync_api import sync_playwright
from src.edition.localize import read_package, edition_record, audit_edition
edition = edition_record(read_package(translated)[1])
added_cover_pages = set()
if edition and not audit_edition(translated)['issues']:
added_cover_pages = {b['file'] for b in edition['cover_bindings'] if b['target'] == edition['cover_path']}
candidates = [n for n in after['spine'] if n in after['documents']]
risky = []
for predicate in (lambda n: re.search(r'part|chapter|ch\d', n, re.I),
@@ -316,7 +325,7 @@ def render_pair(source, translated, before, after, out, chapters=None, max_docum
if not selected:
raise ValueError('No documents selected for rendering')
for name in selected:
if name not in before['documents'] or name not in after['documents']:
if name not in after['documents'] or (name not in before['documents'] and name not in added_cover_pages):
raise ValueError(f'Document absent from source or translation: {name}')
evidence = []; layout = []; clicks = []; browser_version = None
with archive_server({'source': source, 'translated': translated}) as base, sync_playwright() as p:
@@ -328,6 +337,7 @@ def render_pair(source, translated, before, after, out, chapters=None, max_docum
page = context.new_page()
for index, name in enumerate(selected):
for label in ('source', 'translated'):
if label == 'source' and name not in before['documents']: continue
url = base + '/' + label + '/' + quote(name)
page.goto(url, wait_until='networkidle', timeout=30000)
page.evaluate('() => document.fonts.ready')