| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113 |
- # -*- coding: utf-8 -*-
- """Refresh TOC fields in one docx via a fresh Word process."""
- from __future__ import annotations
- import hashlib
- import shutil
- import sys
- import tempfile
- import time
- from pathlib import Path
- WD_COLOR_BLACK = 0
- WD_STAT_PAGES = 2
- def retry(fn, times=8, wait=0.8):
- last = None
- for i in range(times):
- try:
- return fn()
- except Exception as exc:
- last = exc
- time.sleep(wait * (i + 1))
- raise last
- def main() -> int:
- if len(sys.argv) < 2:
- return 2
- src = Path(sys.argv[1])
- tmp_dir = Path(tempfile.gettempdir()) / "aidop_toc_word"
- tmp_dir.mkdir(exist_ok=True)
- tmp = tmp_dir / f"{hashlib.md5(str(src).encode('utf-8')).hexdigest()}_{int(time.time())}.docx"
- shutil.copy2(src, tmp)
- import pythoncom
- import win32com.client as win32
- pythoncom.CoInitialize()
- word = None
- doc = None
- try:
- word = retry(lambda: win32.DispatchEx("Word.Application"))
- word.Visible = False
- try:
- word.DisplayAlerts = 0
- except Exception:
- pass
- try:
- word.AutomationSecurity = 3
- except Exception:
- pass
- time.sleep(1)
- doc = retry(
- lambda: word.Documents.Open(
- str(tmp),
- ConfirmConversions=False,
- ReadOnly=False,
- AddToRecentFiles=False,
- )
- )
- time.sleep(1)
- retry(lambda: doc.Fields.Update())
- def update_tocs():
- for i in range(1, doc.TablesOfContents.Count + 1):
- doc.TablesOfContents(i).Update()
- retry(update_tocs)
- try:
- doc.Repaginate()
- except Exception:
- pass
- retry(update_tocs)
- for name in ("TOC 1", "TOC 2", "TOC 3", "TOC 4", "Hyperlink"):
- try:
- doc.Styles(name).Font.Color = WD_COLOR_BLACK
- except Exception:
- pass
- pages = retry(lambda: doc.ComputeStatistics(WD_STAT_PAGES))
- lines = 0
- if doc.TablesOfContents.Count:
- lines = len([x for x in doc.TablesOfContents(1).Range.Text.split("\r") if x.strip()])
- retry(doc.Save)
- retry(lambda: doc.Close(False))
- doc = None
- retry(word.Quit)
- word = None
- time.sleep(0.5)
- shutil.copy2(tmp, src)
- print(f"pages={pages} toc={lines}", flush=True)
- return 0
- finally:
- try:
- if doc is not None:
- doc.Close(False)
- except Exception:
- pass
- try:
- if word is not None:
- word.Quit()
- except Exception:
- pass
- try:
- pythoncom.CoUninitialize()
- except Exception:
- pass
- try:
- tmp.unlink(missing_ok=True)
- except Exception:
- pass
- if __name__ == "__main__":
- raise SystemExit(main())
|