"""iframe 版登录接口策略""" import time import urllib.parse from .crypto import encrypt_nickname_or_phone, encrypt_password from .login_api import LoginAPIStrategy class IframeLoginAPI(LoginAPIStrategy): """iframe 版接口策略 混合模式(与 e 语言一致): - 登录:使用 wgapi 接口 - 邮箱验证:使用 iframe 接口 """ @property def name(self) -> str: return "iframe" @property def first_login_url(self) -> str: """第一次登录用 wgapi 接口获取极验参数""" return "https://passport.douyu.com/wgapi/member/passport/login" @property def login_url(self) -> str: """第二次登录用 wgapi 接口(与 e 语言一致)""" return "https://passport.douyu.com/wgapi/member/passport/login" @property def send_email_url(self) -> str: """发送邮箱验证用 iframe 接口""" return "https://passport.douyu.com/iframe/sendEmail" @property def verify_url(self) -> str: """提交验证码用 iframe 接口""" return "https://passport.douyu.com/iframe/remoteLogin" def encrypt_username(self, username: str) -> str: """RC4 加密后 URL 编码""" encrypted = encrypt_nickname_or_phone(username) return urllib.parse.quote(encrypted, safe='') def build_first_login_data(self, username: str, password: str, referer: str) -> dict: """构建第一次登录参数(获取极验参数) 注:第一次登录使用 wgapi 接口,所以用户名用 base64 编码(而非 URL 编码)。 """ # 第一次登录用 wgapi 接口,需要 base64 编码的用户名 encrypted_username = encrypt_nickname_or_phone(username) return { 'type': '1', 'nicknameOrPhoneEncrypt': encrypted_username, 'password': encrypt_password(password), 'biz_type': '1', 'room_id': '0', 'redirect_url': referer, 't': str(int(time.time() * 1000)), 'client_id': '1', 'did': '', 'lang': '', 'isMultiAccount': '0', } def build_second_login_data( self, username: str, password: str, gt: str, challenge: str, validate: str, seccode: str, code_token: str, referer: str, ) -> dict: """构建第二次登录参数(带极验验证) 登录使用 wgapi 接口,参数格式与 wgapi 策略一致。 """ # seccode 格式: validate|jordan(requests 会自动 URL 编码) seccode_value = validate + '|jordan' # 使用 base64 编码(wgapi 接口要求),而不是 URL 编码 encrypted_username = encrypt_nickname_or_phone(username) return { 'type': '1', 'nicknameOrPhoneEncrypt': encrypted_username, 'password': encrypt_password(password), 'room_id': '0', 'code_type': '1', 'code_token': code_token, 'gt_version': 'v3', 'geetest_challenge': challenge, 'geetest_validate': validate, 'geetest_seccode': seccode_value, 'code_data[geetest_challenge]': challenge, 'code_data[geetest_validate]': validate, 'code_data[geetest_seccode]': seccode_value, 'code_data[gt_version]': 'v3', 'code_data[code]': '', 'redirect_url': referer, 't': str(int(time.time() * 1000)), 'client_id': '1', 'did': '', 'lang': '', 'isMultiAccount': '0', 'biz_type': '1', } def build_send_email_data(self, code: str) -> dict: """构建发送邮箱验证参数""" return {'cacheId': code} def build_verify_data(self, code: str, captcha: str) -> dict: """构建提交验证码参数""" return { 'veify_type': '2', # e 语言原文如此,斗鱼接口拼写 'phoneCaptcha': captcha, 'client_id': '1', 'isMultiAccount': '0', 'cacheId': code, }