reading-list: RU-клетка больше не пустая для найденных изданий (47 -> 0): (1) make_rootlist card_ru_title — таблица без separator-строки, header 'RU title', lang-first-строки, + cross-ref-резолвинг RU-названия из канонической карточки по Status ('cross-ref secNN #MM' / 'see ../NN-.. #MM'); (2) 6 карточек: sec01 #04/#35 (остатки '— нет' -> cross-ref-строки + Status), #21 («О природе анимуса» неофиц. 2013), sec04 #28 (глава «Символизм в изобразительном искусстве»), #30 («О духовном в искусстве»), sec12 #20 («В самые тёмные места» ИОИ 2020); (3) 3 user-rescue 09-27 (sec09 #12/#24/#35) — RU-таблицы заполнены (СТД 2003 / ИАП 2001+ИОИ 2016 / Касталия 2026); (4) sec08 #13 Wilkinson Coming into Mind: INDEX ✅->❌ (канон sec01 #55 = RU нет, ✅ было ошибкой)

This commit is contained in:
Dmitry Kokorin 2026-10-01 10:45:49 +03:00
parent 33979959fa
commit c78a1fe792
13 changed files with 129 additions and 81 deletions

View file

@ -125,22 +125,42 @@ def card_path(sec, card):
return os.path.join(d, cands[0])
return None
def card_ru_title(sec, card):
def card_ru_title(sec, card, _depth=0):
p = card_path(sec, card)
if p is None:
return ""
s = open(p, encoding="utf-8").read()
m = re.search(r'## Editions — RU\s*\n+\|.*?\n\|[-| ]*\n((?:\|.*\n?)+)', s)
if not m:
return ""
rows = [r for r in m.group(1).strip().splitlines() if r.startswith("|")]
if not rows:
return ""
first = [c.strip() for c in rows[0].strip("|").split("|")]
if first and (first[0].startswith("—") or first[0] in ("", "RU title")):
return "— нет"
t = first[0].strip("«» ")
return t[:90]
m = re.search(r'## Editions — RU\s*\n(.*?)(?=\n## )', s, re.S)
if m:
for r in [x for x in m.group(1).splitlines() if x.strip().startswith("|")]:
cells = [c.strip() for c in r.strip("|").split("|")]
if not cells or all(set(c) <= set("-: ") for c in cells):
continue # separator
if cells[0].lower().endswith("title") or cells[0].startswith("Title"):
continue # header
if cells[0] in ("EN", "RU", "DE", "ES", "FR", "IT"):
continue # lang-first table: no title column
tt = cells[0].strip("«» ")
if tt.startswith("—"):
return "— нет"
if tt:
return tt[:90]
# RU title via cross-ref in Status line (cross-section / xref cards)
if _depth < 2:
stat = re.search(r'\*\*Status:\*\*([^\n]*)', s)
if stat:
mm = (re.search(r'cross-ref (?:IWT: )?sec(\d\d) #(\d{2})', stat.group(1))
or re.search(r'see `../(\d\d)-[\w\-]+/`(?:\s*#|item )(\d{2})', stat.group(1)))
if mm:
full = SECNUM_TO_FULL.get(mm.group(1))
if full:
_name, items = idxs[full]
it = items.get(mm.group(2))
if it:
sub = card_ru_title(full, it["card"], _depth + 1)
if sub and sub != "— нет":
return f"{sub} (sec{mm.group(1)})"
return ""
def file_links(sec, files, ddir):
out = []
@ -194,6 +214,7 @@ def mkpath(name, sz_hint=""):
def main():
# pre-parse all manifests (needed for cross-section resolution)
manifs = {sec: parse_manifest(sec) for sec in SECS}
global idxs
idxs = {}
for sec in SECS:
idxs[sec] = parse_index(sec)