41 lines
1.2 KiB
Python
41 lines
1.2 KiB
Python
import vobject
|
|
|
|
def get_contact_name(card: vobject.vCard) -> str:
|
|
"""Extract best available display name from a vCard, never raises."""
|
|
|
|
# 1. FN — formatted name, most reliable
|
|
try:
|
|
fn = card.contents["fn"][0].value.strip()
|
|
if fn:
|
|
return fn
|
|
except (KeyError, IndexError, AttributeError):
|
|
pass
|
|
|
|
# 2. N — structured name: last, first, middle, prefix, suffix
|
|
try:
|
|
n = card.contents["n"][0].value
|
|
parts = [n.prefix, n.given, n.additional, n.family, n.suffix]
|
|
name = " ".join(p for p in parts if p and p.strip())
|
|
if name.strip():
|
|
return name.strip()
|
|
except (KeyError, IndexError, AttributeError):
|
|
pass
|
|
|
|
# 3. ORG — organization name as last resort
|
|
try:
|
|
org = card.contents["org"][0].value
|
|
# org can be a list ["Company", "Department"] or a string
|
|
if isinstance(org, list):
|
|
org = " / ".join(p for p in org if p and p.strip())
|
|
if org and org.strip():
|
|
return org.strip()
|
|
except (KeyError, IndexError, AttributeError):
|
|
pass
|
|
|
|
# 4. EMAIL
|
|
try:
|
|
return card.contents["email"][0].value.strip()
|
|
except (KeyError, IndexError, AttributeError):
|
|
pass
|
|
|
|
return "Unknown" |