fix: #1114 加入云游戏登录超时处理 (#1115)

This commit is contained in:
Hoshi Sumi 2026-06-08 20:55:31 +08:00 committed by GitHub
parent 11a29f556a
commit 6d6a30e1d2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 64 additions and 10 deletions

View File

@ -895,6 +895,13 @@ class SettingInterface(ScrollArea):
tr("最大排队等待时间(分钟)"),
''
)
self.cloudGameLoginTimeoutCard = RangeSettingCard1(
"cloud_game_login_timeout",
[1, 120],
FIF.DATE_TIME,
tr("登录超时时间(分钟)"),
tr("等待用户完成登录的最长时间,超时后将终止运行")
)
# self.cloudGameVideoQualityCard = ComboBoxSettingCard2(
# "cloud_game_video_quality",
# FIF.VIDEO,
@ -2616,6 +2623,7 @@ class SettingInterface(ScrollArea):
self.CloudGameGroup.addSettingCard(self.browserHeadlessCard)
self.browserHeadlessCard.addSettingCards([self.browserHeadlessRestartCard])
self.CloudGameGroup.addSettingCard(self.cloudGameMaxQueueTimeCard)
self.CloudGameGroup.addSettingCard(self.cloudGameLoginTimeoutCard)
# self.CloudGameGroup.addSettingCard(self.cloudGameVideoQualityCard)
# self.CloudGameGroup.addSettingCard(self.cloudGameSmoothFirstCard)
# self.CloudGameGroup.addSettingCard(self.cloudGameShowStatusCard)

View File

@ -54,6 +54,7 @@ cloud_game_enable: False # 是否启动云游戏
cloud_game_fullscreen_enable: True # 云崩铁是否全屏运行
cloud_game_use_paid_time: False # 是否使用付费时长
cloud_game_max_queue_time: 60 # 最大排队等待时间(分钟)
cloud_game_login_timeout: 20 # 等待登录的超时时间(分钟),超时后终止运行
# cloud_game_video_quality: '0' # 云崩铁画质 '0'(超高清)'1'(高清), '2'(标清), '3'(低清)
# cloud_game_smooth_first_enable: False # 是否流畅优先
# cloud_game_status_bar_enable: False # 是否显示网速

View File

@ -175,6 +175,8 @@
"打开后可在使用云游戏时使用付费时长免除排队": "Enable to use paid time for cloud gaming to skip queue",
"当前账号付费时间不足,已切换为免费时间。": "Insufficient paid time on current account, switched to free time.",
"最大排队等待时间(分钟)": "Max Queue Wait Time (Minutes)",
"登录超时时间(分钟)": "Login Timeout (Minutes)",
"等待用户完成登录的最长时间,超时后将终止运行": "Maximum time to wait for login. The run will stop after timeout.",
"浏览器类型": "Browser Type",
"建议保持默认的“集成Chrome For Testing”效果最好": "Recommended to keep default 'Integrated (Chrome For Testing)'",
"集成Chrome For Testing": "Integrated (Chrome For Testing)",
@ -1483,4 +1485,4 @@
"界面可切换性测试": "Screen Switchability Test",
"测试": "Test",
"以最短路径遍历所有可达界面,验证界面切换是否正常": "Traverse all reachable screens via the shortest path to verify screen switching works correctly"
}
}

View File

@ -175,6 +175,8 @@
"打开后可在使用云游戏时使用付费时长免除排队": "有効にすると、クラウドゲーム使用時に有料時間を使って待機時間を免除できます。",
"当前账号付费时间不足,已切换为免费时间。": "現在のアカウントの有料時間が不足しているため、無料時間に切り替えました。",
"最大排队等待时间(分钟)": "最大待機時間(分)",
"登录超时时间(分钟)": "ログインタイムアウト(分)",
"等待用户完成登录的最长时间,超时后将终止运行": "ユーザーのログイン完了を待つ最大時間です。タイムアウト後は実行を終了します。",
"浏览器类型": "ブラウザー種類",
"建议保持默认的“集成Chrome For Testing”效果最好": "通常はデフォルトの「統合Chrome For Testing」推奨です。",
"集成Chrome For Testing": "統合Chrome For Testing",
@ -1483,4 +1485,4 @@
"界面可切换性测试": "画面切替テスト",
"测试": "テスト",
"以最短路径遍历所有可达界面,验证界面切换是否正常": "最短経路で到達可能なすべての画面を巡回し、画面切替が正常に動作するか検証します"
}
}

View File

@ -175,6 +175,8 @@
"打开后可在使用云游戏时使用付费时长免除排队": "켜면 클라우드 게임 사용 시 유료 시간을 사용하여 대기열을 건너뛸 수 있습니다",
"当前账号付费时间不足,已切换为免费时间。": "현재 계정의 유료 시간이 부족하여 무료 시간으로 전환되었습니다。",
"最大排队等待时间(分钟)": "최대 대기열 대기 시간 (분)",
"登录超时时间(分钟)": "로그인 타임아웃 (분)",
"等待用户完成登录的最长时间,超时后将终止运行": "사용자가 로그인을 완료할 때까지 기다리는 최대 시간입니다. 타임아웃 후 실행을 종료합니다.",
"浏览器类型": "브라우저 유형",
"建议保持默认的“集成Chrome For Testing”效果最好": "기본값 '통합 (Chrome For Testing)' 사용 권장",
"集成Chrome For Testing": "통합 (Chrome For Testing)",

View File

@ -175,6 +175,8 @@
"打开后可在使用云游戏时使用付费时长免除排队": "打开后可在使用云游戏时使用付费时长免除排队",
"当前账号付费时间不足,已切换为免费时间。": "当前账号付费时间不足,已切换为免费时间。",
"最大排队等待时间(分钟)": "最大排队等待时间(分钟)",
"登录超时时间(分钟)": "登录超时时间(分钟)",
"等待用户完成登录的最长时间,超时后将终止运行": "等待用户完成登录的最长时间,超时后将终止运行",
"浏览器类型": "浏览器类型",
"建议保持默认的“集成Chrome For Testing”效果最好": "建议保持默认的“集成Chrome For Testing”效果最好",
"集成Chrome For Testing": "集成Chrome For Testing",
@ -1483,4 +1485,4 @@
"界面可切换性测试": "界面可切换性测试",
"测试": "测试",
"以最短路径遍历所有可达界面,验证界面切换是否正常": "以最短路径遍历所有可达界面,验证界面切换是否正常"
}
}

View File

@ -175,6 +175,8 @@
"打开后可在使用云游戏时使用付费时长免除排队": "打開後可在使用雲遊戲時使用付費時長免除排隊",
"当前账号付费时间不足,已切换为免费时间。": "當前帳號付費時間不足,已切換為免費時間。",
"最大排队等待时间(分钟)": "最大排隊等待時間(分鐘)",
"登录超时时间(分钟)": "登入逾時時間(分鐘)",
"等待用户完成登录的最长时间,超时后将终止运行": "等待使用者完成登入的最長時間,逾時後將終止執行",
"浏览器类型": "瀏覽器類型",
"建议保持默认的“集成Chrome For Testing”效果最好": "建議保持預設的「整合Chrome For Testing」效果最好",
"集成Chrome For Testing": "整合Chrome For Testing",
@ -1483,4 +1485,4 @@
"界面可切换性测试": "界面可切換性測試",
"测试": "測試",
"以最短路径遍历所有可达界面,验证界面切换是否正常": "以最短路徑遍歷所有可達界面,驗證界面切換是否正常"
}
}

View File

@ -32,6 +32,10 @@ from module.logger import Logger
from utils.console import is_docker_started
class CloudGameLoginTimeoutError(RuntimeError):
"""云游戏登录等待超时,不应按启动失败重试。"""
class CloudGameController(GameControllerBase):
COOKIE_PATH = "settings/cookies.enc" # Cookies 保存地址(仅用于调试)
GAME_URL = "https://sr.mihoyo.com/cloud" # 游戏地址
@ -489,6 +493,24 @@ class CloudGameController(GameControllerBase):
self.log_warning("检测登录状态超时:未出现登录或未登录标志元素")
return None
def _get_login_timeout_seconds(self) -> int:
try:
timeout_minutes = int(self.cfg.get_value("cloud_game_login_timeout", 10))
except (TypeError, ValueError):
timeout_minutes = 10
return max(1, timeout_minutes) * 60
def _abort_login_timeout(self, timeout_seconds: int) -> None:
timeout_minutes = timeout_seconds // 60
message = f"等待云游戏登录超时({timeout_minutes} 分钟),停止运行"
self.log_error(message)
self.stop_game()
raise CloudGameLoginTimeoutError(message)
def _check_login_timeout(self, deadline: float, timeout_seconds: int) -> None:
if time.monotonic() >= deadline:
self._abort_login_timeout(timeout_seconds)
def _click_enter_game(self, timeout=5) -> None:
"""
点击进入游戏按钮
@ -979,10 +1001,13 @@ class CloudGameController(GameControllerBase):
except Exception as e:
self.log_warning(f"解析二维码内容失败: {e}")
def _wait_scan_success_with_refresh(self, qr_filename: str) -> None:
def _wait_scan_success_with_refresh(self, qr_filename: str, login_deadline: float = None, timeout_seconds: int = None) -> None:
import os
check_interval = 2
while True:
if login_deadline is not None and timeout_seconds is not None:
self._check_login_timeout(login_deadline, timeout_seconds)
# 成功
if self.driver.find_elements(By.XPATH, "//*[contains(text(), '扫码成功')]"):
try:
@ -1025,7 +1050,7 @@ class CloudGameController(GameControllerBase):
time.sleep(check_interval)
def _run_qr_login_flow(self) -> None:
def _run_qr_login_flow(self, login_deadline: float = None, timeout_seconds: int = None) -> None:
self.log_info("正在切换到二维码登录...")
# 每次进入二维码登录流程时重置通知限流状态
@ -1047,7 +1072,7 @@ class CloudGameController(GameControllerBase):
self._decode_qr_from_element(qr_img, qr_filename)
self.log_info("=" * 60)
self.log_info("等待扫码(二维码过期将自动刷新)...")
self._wait_scan_success_with_refresh(qr_filename)
self._wait_scan_success_with_refresh(qr_filename, login_deadline, timeout_seconds)
except TimeoutException:
self.log_warning("等待二维码加载超时")
except Exception as e:
@ -1086,6 +1111,8 @@ class CloudGameController(GameControllerBase):
try:
# 检测登录状态
while not self._check_login():
login_timeout_seconds = self._get_login_timeout_seconds()
login_deadline = time.monotonic() + login_timeout_seconds
self.log_info("未登录")
# 如果是 headless 且配置了自动重启,则以非 headless 模式重启启动让用户登录
@ -1095,12 +1122,15 @@ class CloudGameController(GameControllerBase):
# 如果是 headless 且配置了不重启,则尝试二维码登录
if self.cfg.browser_headless_enable and (not self.cfg.browser_headless_restart_on_not_logged_in):
self._run_qr_login_flow()
self._run_qr_login_flow(login_deadline, login_timeout_seconds)
self.log_info("请在浏览器中完成登录操作")
self.log_info(f"请在浏览器中完成登录操作,超时时间:{login_timeout_seconds // 60} 分钟")
# 循环检测用户是否登录
while not self._check_login():
while True:
self._check_login_timeout(login_deadline, login_timeout_seconds)
if self._check_login():
break
time.sleep(2)
self.log_info("检测到登录成功")
@ -1146,6 +1176,8 @@ class CloudGameController(GameControllerBase):
self._confirm_viewport_resolution() # 将浏览器内部分辨率设置为 1920x1080
self.log_info("进入云游戏成功")
return True
except CloudGameLoginTimeoutError:
raise
except Exception as e:
self.try_dump_page()
self.log_error(f"进入云游戏失败: {e}")

View File

@ -12,6 +12,7 @@ from utils.date import Date
from utils.console import pause_on_success
from tasks.power.power import Power
from module.game import cloud_game, get_game_controller
from module.game.cloud import CloudGameLoginTimeoutError
from module.logger import log
from module.screen import screen
from module.automation import auto
@ -207,6 +208,8 @@ def start_game():
starrail.stop_game()
continue
break
except CloudGameLoginTimeoutError:
raise
except Exception as e:
log.error(f"尝试启动游戏时发生错误:{e}")
# 确保在重试前停止游戏