更新
This commit is contained in:
@@ -0,0 +1,81 @@
|
||||
"""向指定抖音 UID 发送私信(文本 / 结构化 JSON)。"""
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import asyncio
|
||||
import json
|
||||
import sqlite3
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
from dotenv import load_dotenv
|
||||
|
||||
ROOT = Path(__file__).resolve().parent
|
||||
load_dotenv(ROOT.parent / ".env")
|
||||
sys.path.insert(0, str(ROOT))
|
||||
|
||||
from rpa_engine.credential import build_im_session_from_storage
|
||||
from rpa_engine.device_profiles import resolve_user_agent
|
||||
from rpa_engine.douyin_im.conv_util import build_conversation_id
|
||||
from rpa_engine.douyin_im.http_client import DouyinImHttpClient
|
||||
from utils.cookie_store import read_cookie_file
|
||||
|
||||
|
||||
def _load_account(account_id: int) -> dict:
|
||||
db_path = ROOT / "kefu.db"
|
||||
conn = sqlite3.connect(db_path)
|
||||
conn.row_factory = sqlite3.Row
|
||||
row = conn.execute(
|
||||
"SELECT id, douyin_uid, cookie_data, im_session_data, user_agent FROM accounts WHERE id = ?",
|
||||
(account_id,),
|
||||
).fetchone()
|
||||
conn.close()
|
||||
if not row:
|
||||
raise SystemExit(f"账号 id={account_id} 不存在")
|
||||
cookie_data = row["cookie_data"] or read_cookie_file(account_id)
|
||||
if not cookie_data:
|
||||
raise SystemExit(f"账号 id={account_id} 无 Cookie")
|
||||
return {
|
||||
"id": int(row["id"]),
|
||||
"douyin_uid": str(row["douyin_uid"] or "").strip(),
|
||||
"cookie_data": cookie_data,
|
||||
"im_session_data": row["im_session_data"],
|
||||
"user_agent": row["user_agent"],
|
||||
}
|
||||
|
||||
|
||||
def _build_session(account: dict):
|
||||
storage = json.loads(account["cookie_data"]) if account["cookie_data"] else {}
|
||||
session = build_im_session_from_storage(storage, account.get("im_session_data"))
|
||||
session.user_agent = resolve_user_agent(account.get("user_agent") or session.user_agent)
|
||||
return session
|
||||
|
||||
|
||||
async def _send(account_id: int, peer_uid: str, text: str, conversation_id: str = "") -> None:
|
||||
account = _load_account(account_id)
|
||||
session = _build_session(account)
|
||||
my_uid = account["douyin_uid"] or str(session.my_uid or "")
|
||||
if not my_uid:
|
||||
raise SystemExit("无法确定发送方 UID")
|
||||
conv = conversation_id.strip() or build_conversation_id(my_uid, peer_uid)
|
||||
print(f"from={my_uid} to={peer_uid} conv={conv}")
|
||||
async with DouyinImHttpClient(session, account_id=account_id) as http:
|
||||
ok = await http.send_text_message(conv, text)
|
||||
print("sent:", ok)
|
||||
if not ok:
|
||||
print(http.last_error or "发送失败")
|
||||
raise SystemExit(1)
|
||||
|
||||
|
||||
def main() -> None:
|
||||
parser = argparse.ArgumentParser(description="向指定抖音 UID 发私信")
|
||||
parser.add_argument("--account-id", type=int, default=1)
|
||||
parser.add_argument("--peer-uid", required=True, help="对方抖音 UID")
|
||||
parser.add_argument("--text", default="你好", help="文本内容")
|
||||
parser.add_argument("--conversation-id", default="", help="可选,已知会话 ID 时传入")
|
||||
args = parser.parse_args()
|
||||
asyncio.run(_send(args.account_id, args.peer_uid, args.text, args.conversation_id))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user