ForcePilot/backend/package/yuxi/channel/extensions/twitter/auth.py

89 lines
2.7 KiB
Python
Raw Normal View History

from __future__ import annotations
import asyncio
import logging
import tweepy
logger = logging.getLogger(__name__)
X_API_V2_BASE = "https://api.x.com"
X_UPLOAD_BASE = "https://upload.twitter.com"
def create_tweepy_client(account: dict) -> tweepy.Client:
return tweepy.Client(
consumer_key=account["api_key"],
consumer_secret=account["api_secret"],
access_token=account["access_token"],
access_token_secret=account["access_secret"],
return_type=dict,
wait_on_rate_limit=False,
)
async def verify_credentials(
account: dict, timeout_seconds: float = 5.0
) -> dict | None:
try:
client = create_tweepy_client(account)
response = await asyncio.to_thread(
client.get_me,
user_fields=["id", "username", "name", "profile_image_url"],
)
data = response.get("data", {})
if data:
return {
"user_id": data.get("id", ""),
"username": data.get("username", ""),
"name": data.get("name", ""),
"profile_image_url": data.get("profile_image_url", ""),
}
except tweepy.Unauthorized:
logger.warning("X API: OAuth 1.0a credentials invalid or revoked")
except tweepy.TooManyRequests:
logger.warning("X API: rate limited during credential verification")
except Exception:
logger.exception("X API: credential verification failed")
return None
async def probe(account: dict, timeout_seconds: float = 5.0) -> bool:
user = await verify_credentials(account, timeout_seconds)
return user is not None
async def get_user_by_username(account: dict, username: str) -> dict | None:
client = create_tweepy_client(account)
try:
response = await asyncio.to_thread(
client.get_user,
username=username,
user_fields=[
"id",
"username",
"name",
"description",
"public_metrics",
"profile_image_url",
],
)
return response.get("data", {})
except Exception as e:
logger.warning("Twitter get_user_by_username error: %s", e)
return None
async def get_users_by_ids(account: dict, user_ids: list[str]) -> list[dict]:
client = create_tweepy_client(account)
try:
response = await asyncio.to_thread(
client.get_users,
ids=user_ids,
user_fields=["id", "username", "name", "profile_image_url"],
)
return response.get("data", [])
except Exception as e:
logger.warning("Twitter get_users_by_ids error: %s", e)
return []