Metadata: library-style PDF author 'Last, First, dates' becomes 'First Last'

This commit is contained in:
Audiobook Producer
2026-10-18 13:27:06 -05:00
parent 889b775a58
commit b0b8050b0c
2 changed files with 20 additions and 1 deletions
+13 -1
View File
@@ -57,6 +57,16 @@ def junk_author(a):
return len(re.sub(r"[^A-Za-z]", "", a)) < 3 or a.lower() in JUNK_AUTHORS or bool(re.search(r"\d{3,}", a)) return len(re.sub(r"[^A-Za-z]", "", a)) < 3 or a.lower() in JUNK_AUTHORS or bool(re.search(r"\d{3,}", a))
def info_author_name(a):
"""PDF metadata authors often look like 'Lincoln, Abraham, 1809-1865': drop the dates and put the first name first."""
a = re.sub(r"[,\s]*\(?\b(?:c\.?\s*)?\d{3,4}\s*-\s*(?:\d{3,4})?\)?\.?\s*$", "", clean_text(a)).strip(" ,;")
parts = [p.strip() for p in a.split(",")]
if len(parts) == 2 and all(re.fullmatch(r"[A-Za-z.'’\- ]+", p) for p in parts) and 1 <= len(parts[0].split()) <= 2 \
and not any(w.lower().strip(".") in NOT_NAME_WORDS | {"inc", "ltd", "llc", "jr", "sr", "corp", "gmbh"} for w in (parts[0] + " " + parts[1]).split()):
a = parts[1] + " " + parts[0]
return a
def display_name(name): def display_name(name):
"""'YOGI RAMACHARAKA' / 'yogi ramacharaka' -> 'Yogi Ramacharaka'. Mixed case is kept (McDonald).""" """'YOGI RAMACHARAKA' / 'yogi ramacharaka' -> 'Yogi Ramacharaka'. Mixed case is kept (McDonald)."""
out = [] out = []
@@ -259,7 +269,9 @@ def detect_from_pdf(cfg, pdf, hint=None):
res = {"title": "", "title_source": "", "author": "", "author_source": "", "notes": notes} res = {"title": "", "title_source": "", "author": "", "author_source": "", "notes": notes}
if info["title"] and not junk_title(info["title"]): if info["title"] and not junk_title(info["title"]):
res["title"], res["title_source"] = bookio.title_case(clean_text(info["title"])), "pdf-metadata" res["title"], res["title_source"] = bookio.title_case(clean_text(info["title"])), "pdf-metadata"
info_author = info["author"] if info["author"] and not junk_author(info["author"]) else "" info_author = info_author_name(info["author"]) if info["author"] else ""
if info_author and junk_author(info_author):
info_author = ""
pages, blank = first_pages_text(cfg, pdf, n, notes) pages, blank = first_pages_text(cfg, pdf, n, notes)
page = read_title_page([(p, t) for p, t, _ in pages], hint) page = read_title_page([(p, t) for p, t, _ in pages], hint)
+7
View File
@@ -158,6 +158,13 @@ class PureTests(unittest.TestCase):
self.assertEqual(meta.clean_filename_title("my_book_final"), "my book") self.assertEqual(meta.clean_filename_title("my_book_final"), "my book")
self.assertEqual(meta.filename_candidates(["2401.01234.pdf", "Deep Work.url"])[0], "Deep Work") self.assertEqual(meta.filename_candidates(["2401.01234.pdf", "Deep Work.url"])[0], "Deep Work")
def test_library_style_metadata_author(self):
self.assertEqual(meta.info_author_name("Lincoln, Abraham, 1809-1865"), "Abraham Lincoln")
self.assertEqual(meta.info_author_name("Pope, Alexander, 1688-1744"), "Alexander Pope")
self.assertEqual(meta.info_author_name("Jane Doe"), "Jane Doe")
self.assertEqual(meta.info_author_name("Doe, Jane Q."), "Jane Q. Doe")
self.assertEqual(meta.info_author_name("Acme Press, Inc."), "Acme Press, Inc.")
def test_author_rules(self): def test_author_rules(self):
self.assertEqual(meta.first_author("YOGI RAMACHARAKA"), "Yogi Ramacharaka") self.assertEqual(meta.first_author("YOGI RAMACHARAKA"), "Yogi Ramacharaka")
self.assertEqual(meta.first_author("Glenn Clark and Walter Russell"), "Glenn Clark") self.assertEqual(meta.first_author("Glenn Clark and Walter Russell"), "Glenn Clark")