feat: Add support for adding contacts by username without phone number

- Modified add_contact function to support username-based contact addition
- If phone parameter is empty or starts with @, function resolves username first
- Uses contacts.AddContactRequest API for username-based contacts
- Maintains backward compatibility with phone-based contact addition
- Allows adding contacts as done in Telegram UI when searching by username
This commit is contained in:
gvidonind-commits 2026-01-29 20:23:33 +03:00
parent 36522e5ebc
commit 4693719798

115
main.py
View file

@ -1304,52 +1304,107 @@ async def add_contact(phone: str, first_name: str, last_name: str = "") -> str:
""" """
Add a new contact to your Telegram account. Add a new contact to your Telegram account.
Args: Args:
phone: The phone number of the contact (with country code). phone: The phone number of the contact (with country code) OR username (starting with @) OR empty string for username-based addition.
first_name: The contact's first name. first_name: The contact's first name.
last_name: The contact's last name (optional). last_name: The contact's last name (optional).
Note: If phone is empty or starts with @, the function will try to resolve it as a username
and add the contact using contacts.addContact API (which supports adding contacts without phone numbers).
""" """
try: try:
# Try to import the required types first # Check if phone is empty or is a username (starts with @)
from telethon.tl.types import InputPhoneContact is_username = not phone or phone.startswith("@")
result = await client( if is_username:
functions.contacts.ImportContactsRequest( # Handle username-based contact addition
contacts=[ username = phone.lstrip("@") if phone else ""
InputPhoneContact( if not username:
client_id=0, return "Error: Username cannot be empty when adding contact by username."
phone=phone,
# Resolve username to get user information
try:
resolve_result = await client(functions.contacts.ResolveUsernameRequest(username=username))
# Extract user from the result
if not resolve_result.users:
return f"Error: User with username @{username} not found."
user = resolve_result.users[0]
if not isinstance(user, User):
return f"Error: Resolved entity is not a user."
user_id = user.id
access_hash = user.access_hash
# Use contacts.addContact to add the contact by user ID
from telethon.tl.types import InputUser
result = await client(
functions.contacts.AddContactRequest(
id=InputUser(user_id=user_id, access_hash=access_hash),
first_name=first_name, first_name=first_name,
last_name=last_name, last_name=last_name,
phone="", # Empty phone for username-based contacts
) )
] )
)
) if hasattr(result, "updates") and result.updates:
if result.imported: return f"Contact {first_name} {last_name} (@{username}) added successfully."
return f"Contact {first_name} {last_name} added successfully." else:
return f"Contact {first_name} {last_name} (@{username}) added successfully (no updates returned)."
except Exception as resolve_e:
logger.exception(f"add_contact (username resolve) failed (username={username})")
return log_and_format_error("add_contact", resolve_e, username=username)
else: else:
return f"Contact not added. Response: {str(result)}" # Original phone-based contact addition
except (ImportError, AttributeError) as type_err: from telethon.tl.types import InputPhoneContact
# Try alternative approach using raw API
try:
result = await client( result = await client(
functions.contacts.ImportContactsRequest( functions.contacts.ImportContactsRequest(
contacts=[ contacts=[
{ InputPhoneContact(
"client_id": 0, client_id=0,
"phone": phone, phone=phone,
"first_name": first_name, first_name=first_name,
"last_name": last_name, last_name=last_name,
} )
] ]
) )
) )
if hasattr(result, "imported") and result.imported: if result.imported:
return f"Contact {first_name} {last_name} added successfully (alt method)." return f"Contact {first_name} {last_name} added successfully."
else: else:
return f"Contact not added. Alternative method response: {str(result)}" return f"Contact not added. Response: {str(result)}"
except Exception as alt_e: except (ImportError, AttributeError) as type_err:
logger.exception(f"add_contact (alt method) failed (phone={phone})") # Try alternative approach using raw API (only for phone-based)
return log_and_format_error("add_contact", alt_e, phone=phone) # Check if phone is empty or is a username (starts with @)
is_username_alt = not phone or phone.startswith("@")
if not is_username_alt:
try:
result = await client(
functions.contacts.ImportContactsRequest(
contacts=[
{
"client_id": 0,
"phone": phone,
"first_name": first_name,
"last_name": last_name,
}
]
)
)
if hasattr(result, "imported") and result.imported:
return f"Contact {first_name} {last_name} added successfully (alt method)."
else:
return f"Contact not added. Alternative method response: {str(result)}"
except Exception as alt_e:
logger.exception(f"add_contact (alt method) failed (phone={phone})")
return log_and_format_error("add_contact", alt_e, phone=phone)
else:
logger.exception(f"add_contact (type error for username) failed")
return log_and_format_error("add_contact", type_err)
except Exception as e: except Exception as e:
logger.exception(f"add_contact failed (phone={phone})") logger.exception(f"add_contact failed (phone={phone})")
return log_and_format_error("add_contact", e, phone=phone) return log_and_format_error("add_contact", e, phone=phone)