Structure: tolerate OCR-damaged CHAPTER numerals, drop contents-page entries, one synthetic chapter when a book has no headings; metadata: OCR at 300 dpi, title-page text logged, OCR-read author flagged

This commit is contained in:
Audiobook Producer
2026-10-18 13:34:38 -05:00
parent b0b8050b0c
commit 2e33a24ea3
5 changed files with 114 additions and 11 deletions
+8 -2
View File
@@ -223,7 +223,7 @@ def ocr_first_pages(pdf, first, last, lang):
return None
out = []
with tempfile.TemporaryDirectory() as tmp:
subprocess.run(["pdftoppm", "-r", "200", "-gray", "-f", str(first), "-l", str(last), "-png", pdf, os.path.join(tmp, "p")],
subprocess.run(["pdftoppm", "-r", "300", "-gray", "-f", str(first), "-l", str(last), "-png", pdf, os.path.join(tmp, "p")],
capture_output=True, timeout=600)
for name in sorted(os.listdir(tmp)):
m = re.match(r"p-0*(\d+)\.png$", name)
@@ -276,6 +276,7 @@ def detect_from_pdf(cfg, pdf, hint=None):
pages, blank = first_pages_text(cfg, pdf, n, notes)
page = read_title_page([(p, t) for p, t, _ in pages], hint)
ocr_used = False
allpages = [(p, t) for p, t, _ in pages]
if not page.get("author") and blank and cfg["ocr"]["enabled"]:
if not (res["title"] and info_author): # nothing more to learn if metadata already gives both
ocr = ocr_first_pages(pdf, min(blank), max(blank), cfg["ocr"]["language"])
@@ -288,12 +289,17 @@ def detect_from_pdf(cfg, pdf, hint=None):
ocr_used = True
src = "first-page-ocr" if ocr_used and page.get("page") in blank else "first-page-text"
if page.get("author"):
if src == "first-page-ocr":
notes.append("author %r was read by OCR from pdf page %s; check it. A file named like the PDF with .json (author field) overrides it" % (page["author"], page["page"]))
res["author"] = page["author"]
res["author_source"] = ("%s (%s, pdf page %s)" % (src, page["author_source"], page["page"]))
elif info_author:
res["author"], res["author_source"] = display_name(info_author), "pdf-metadata"
if not res["title"] and page.get("title") and page.get("author"):
res["title"], res["title_source"] = bookio.title_case(page["title"]), "%s (pdf page %s)" % (src, page["page"])
if page.get("page") is not None:
txt = dict(allpages).get(page["page"], "")
res["excerpt"] = " / ".join(s for _, s in page_lines(txt)[:14])[:600]
res["_page_title"] = bookio.title_case(page["title"]) if page.get("title") else ""
res["_page_src"] = "%s (pdf page %s)" % (src, page.get("page"))
return res
@@ -356,5 +362,5 @@ def resolve(cfg, pdf, title=None, author=None, sidecar=None, name_hints=None):
else:
a, as_ = UNKNOWN_AUTHOR, "default"
warnings.append(("metadata-author", os.path.basename(pdf), "no author found in the PDF or its file name; using 'Unknown' (folder 'unknown'). Add %s.json with {\"author\": \"...\"} next to the PDF to set it" % os.path.splitext(os.path.basename(pdf))[0]))
log = ["metadata: title %r from %s" % (t, ts), "metadata: author %r from %s" % (a, as_)] + ["metadata: " + n for n in det.get("notes", [])]
log = ["metadata: title %r from %s" % (t, ts), "metadata: author %r from %s" % (a, as_)] + ["metadata: " + n for n in det.get("notes", [])] + (["metadata: title page text: " + det["excerpt"]] if det.get("excerpt") else [])
return {"title": t, "author": a, "title_source": ts, "author_source": as_, "warnings": warnings, "log": log}