ForcePilot/backend/package/yuxi/channel/extensions/twitter/social.py
Kris 1c590097be feat(channel): 添加 Twitter 和 Viber 渠道扩展
新增 Twitter 和 Viber 两个渠道扩展。

Twitter 渠道扩展功能模块:
- auth: OAuth 认证管理
- config: 渠道配置管理
- gateway: SSE/WebSocket 网关接入
- webhook: Webhook 事件处理
- outbound: 外发消息管理
- streaming: 流式消息处理
- pairing: 用户配对与绑定
- security: 安全校验
- dedupe: 消息去重
- monitor: 渠道状态监控
- status: 会话状态管理
- session: 会话管理
- tweets: 推文管理
- social: 社交互动
- reactions: 表情反应
- media: 媒体资源处理

Viber 渠道扩展功能模块:
- config: 渠道配置管理
- gateway: SSE/WebSocket 网关接入
- webhook: Webhook 事件处理
- outbound: 外发消息管理
- streaming: 流式消息处理
- pairing: 用户配对与绑定
- security: 安全校验
- dedupe: 消息去重
- monitor: 渠道状态监控
- status: 会话状态管理
- rate_limiter: 速率限制
- media: 媒体资源处理
2026-05-21 11:57:22 +08:00

309 lines
9.9 KiB
Python

from __future__ import annotations
import asyncio
import logging
from yuxi.channel.extensions.twitter.auth import create_tweepy_client
logger = logging.getLogger(__name__)
class TwitterSocial:
@staticmethod
async def like_tweet(account: dict, tweet_id: str) -> bool:
client = create_tweepy_client(account)
user_id = account.get("user_id", "")
try:
await asyncio.to_thread(client.like, user_id=user_id, tweet_id=tweet_id)
return True
except Exception as e:
logger.warning("Twitter like error: %s", e)
return False
@staticmethod
async def unlike_tweet(account: dict, tweet_id: str) -> bool:
client = create_tweepy_client(account)
user_id = account.get("user_id", "")
try:
await asyncio.to_thread(client.unlike, user_id=user_id, tweet_id=tweet_id)
return True
except Exception as e:
logger.warning("Twitter unlike error: %s", e)
return False
@staticmethod
async def retweet(account: dict, tweet_id: str) -> bool:
client = create_tweepy_client(account)
user_id = account.get("user_id", "")
try:
await asyncio.to_thread(client.retweet, user_id=user_id, tweet_id=tweet_id)
return True
except Exception as e:
logger.warning("Twitter retweet error: %s", e)
return False
@staticmethod
async def unretweet(account: dict, tweet_id: str) -> bool:
client = create_tweepy_client(account)
user_id = account.get("user_id", "")
try:
await asyncio.to_thread(
client.unretweet, user_id=user_id, tweet_id=tweet_id
)
return True
except Exception as e:
logger.warning("Twitter unretweet error: %s", e)
return False
@staticmethod
async def follow_user(account: dict, target_user_id: str) -> bool:
client = create_tweepy_client(account)
user_id = account.get("user_id", "")
try:
await asyncio.to_thread(
client.follow_user,
source_user_id=user_id,
target_user_id=target_user_id,
)
return True
except Exception as e:
logger.warning("Twitter follow error: %s", e)
return False
@staticmethod
async def unfollow_user(account: dict, target_user_id: str) -> bool:
client = create_tweepy_client(account)
user_id = account.get("user_id", "")
try:
await asyncio.to_thread(
client.unfollow_user,
source_user_id=user_id,
target_user_id=target_user_id,
)
return True
except Exception as e:
logger.warning("Twitter unfollow error: %s", e)
return False
@staticmethod
async def bookmark_tweet(account: dict, tweet_id: str) -> bool:
client = create_tweepy_client(account)
user_id = account.get("user_id", "")
try:
await asyncio.to_thread(client.bookmark, user_id=user_id, tweet_id=tweet_id)
return True
except Exception as e:
logger.warning("Twitter bookmark error: %s", e)
return False
@staticmethod
async def unbookmark_tweet(account: dict, tweet_id: str) -> bool:
client = create_tweepy_client(account)
user_id = account.get("user_id", "")
try:
await asyncio.to_thread(
client.unbookmark, user_id=user_id, tweet_id=tweet_id
)
return True
except Exception as e:
logger.warning("Twitter unbookmark error: %s", e)
return False
@staticmethod
async def get_following(
account: dict,
*,
max_results: int = 100,
) -> list[dict] | None:
client = create_tweepy_client(account)
user_id = account.get("user_id", "")
try:
response = await asyncio.to_thread(
client.get_users_following,
id=user_id,
max_results=max_results,
user_fields=["id", "username", "name", "profile_image_url"],
)
return response.get("data", [])
except Exception as e:
logger.warning("Twitter get_following error: %s", e)
return None
@staticmethod
async def get_followers(
account: dict,
*,
max_results: int = 100,
) -> list[dict] | None:
client = create_tweepy_client(account)
user_id = account.get("user_id", "")
try:
response = await asyncio.to_thread(
client.get_users_followers,
id=user_id,
max_results=max_results,
user_fields=["id", "username", "name", "profile_image_url"],
)
return response.get("data", [])
except Exception as e:
logger.warning("Twitter get_followers error: %s", e)
return None
@staticmethod
async def get_liking_users(
account: dict,
tweet_id: str,
*,
max_results: int = 100,
) -> list[dict] | None:
client = create_tweepy_client(account)
try:
response = await asyncio.to_thread(
client.get_liking_users,
id=tweet_id,
max_results=max_results,
user_fields=["id", "username", "name"],
)
return response.get("data", [])
except Exception as e:
logger.warning("Twitter get_liking_users error: %s", e)
return None
@staticmethod
async def get_retweeted_by(
account: dict,
tweet_id: str,
*,
max_results: int = 100,
) -> list[dict] | None:
client = create_tweepy_client(account)
try:
response = await asyncio.to_thread(
client.get_retweeters,
id=tweet_id,
max_results=max_results,
user_fields=["id", "username", "name"],
)
return response.get("data", [])
except Exception as e:
logger.warning("Twitter get_retweeted_by error: %s", e)
return None
@staticmethod
async def get_user_liked_tweets(
account: dict,
user_id: str | None = None,
*,
max_results: int = 100,
) -> list[dict] | None:
client = create_tweepy_client(account)
uid = user_id or account.get("user_id", "")
if not uid:
return None
try:
response = await asyncio.to_thread(
client.get_liked_tweets,
id=uid,
max_results=max_results,
tweet_fields=[
"id",
"text",
"created_at",
"author_id",
"public_metrics",
],
expansions=["author_id"],
)
return response.get("data", [])
except Exception as e:
logger.warning("Twitter get_user_liked_tweets error: %s", e)
return None
@staticmethod
async def get_quote_tweets(
account: dict,
tweet_id: str,
*,
max_results: int = 100,
) -> list[dict] | None:
client = create_tweepy_client(account)
try:
response = await asyncio.to_thread(
client.get_quote_tweets,
id=tweet_id,
max_results=max_results,
tweet_fields=[
"id",
"text",
"created_at",
"author_id",
"public_metrics",
],
expansions=["author_id"],
)
return response.get("data", [])
except Exception as e:
logger.warning("Twitter get_quote_tweets error: %s", e)
return None
@staticmethod
async def block_user(account: dict, target_user_id: str) -> bool:
client = create_tweepy_client(account)
user_id = account.get("user_id", "")
if not user_id:
return False
try:
await asyncio.to_thread(
client.block, user_id=user_id, target_user_id=target_user_id
)
return True
except Exception as e:
logger.warning("Twitter block_user error: %s", e)
return False
@staticmethod
async def unblock_user(account: dict, target_user_id: str) -> bool:
client = create_tweepy_client(account)
user_id = account.get("user_id", "")
if not user_id:
return False
try:
await asyncio.to_thread(
client.unblock, user_id=user_id, target_user_id=target_user_id
)
return True
except Exception as e:
logger.warning("Twitter unblock_user error: %s", e)
return False
@staticmethod
async def mute_user(account: dict, target_user_id: str) -> bool:
client = create_tweepy_client(account)
user_id = account.get("user_id", "")
if not user_id:
return False
try:
await asyncio.to_thread(
client.mute, user_id=user_id, target_user_id=target_user_id
)
return True
except Exception as e:
logger.warning("Twitter mute_user error: %s", e)
return False
@staticmethod
async def unmute_user(account: dict, target_user_id: str) -> bool:
client = create_tweepy_client(account)
user_id = account.get("user_id", "")
if not user_id:
return False
try:
await asyncio.to_thread(
client.unmute, user_id=user_id, target_user_id=target_user_id
)
return True
except Exception as e:
logger.warning("Twitter unmute_user error: %s", e)
return False