March7thAssistant/app/setting_interface.py
2026-03-31 20:29:44 +08:00

1813 lines
80 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

from PySide6.QtCore import Qt, QUrl
from PySide6.QtGui import QDesktopServices
from PySide6.QtWidgets import QWidget, QLabel, QFileDialog, QVBoxLayout, QStackedWidget, QSpacerItem, QScroller, QScrollerProperties
from qfluentwidgets import FluentIcon as FIF
from qfluentwidgets import SettingCardGroup, PushSettingCard, ScrollArea, InfoBar, PrimaryPushSettingCard
from app.sub_interfaces.accounts_interface import accounts_interface
from .common.style_sheet import StyleSheet
from .components.pivot import SettingPivot
from .card.comboboxsettingcard1 import ComboBoxSettingCard1
from .card.comboboxsettingcard2 import ComboBoxSettingCard2, ComboBoxSettingCardUpdateSource, ComboBoxSettingCardLog, ComboBoxSettingCardLanguage
from .card.switchsettingcard1 import SwitchSettingCard1, StartMarch7thAssistantSwitchSettingCard, SwitchSettingCardTeam, SwitchSettingCardImmersifier, SwitchSettingCardGardenofplenty, SwitchSettingCardEchoofwar, SwitchSettingCardHotkey, SwitchSettingCardCloudGameStatus
from .card.rangesettingcard1 import RangeSettingCard1
from .card.pushsettingcard1 import CustomPushSettingCard, PushSettingCardInstance, PushSettingCardInstanceChallengeCount, PushSettingCardNotifyTemplate, PushSettingCardMirrorchyan, PushSettingCardEval, PushSettingCardDate, PushSettingCardKey, PushSettingCardTeam, PushSettingCardFriends, PushSettingCardTeamWithSwap, PushSettingCardPowerPlan, InstanceTeamSettingCard
from .card.timepickersettingcard1 import TimePickerSettingCard1
from .card.expandable_switch_setting_card import ExpandableSwitchSettingCard, ExpandableComboBoxSettingCardUpdateSource, ExpandableComboBoxSettingCard, ExpandableComboBoxSettingCardInstanceType, ExpandableSwitchSettingCardEchoofwar
from .card.messagebox_custom import MessageBoxEdit
from module.config import cfg
from module.notification import init_notifiers
from module.localization import tr
from tasks.base.tasks import start_task
from .tools.check_update import checkUpdate
import os
import sys
class SettingInterface(ScrollArea):
def __init__(self, parent=None):
super().__init__(parent)
self.parent = parent
self.scrollWidget = QWidget()
self.vBoxLayout = QVBoxLayout(self.scrollWidget)
# self.title_area = QScrollArea(self)
self.pivot = SettingPivot(self)
self.stackedWidget = QStackedWidget(self)
self.settingLabel = QLabel(tr("设置"), self)
self.__initWidget()
self.__initCard()
self.__initLayout()
self.__connectSignalToSlot()
def __initWidget(self):
self.setWidget(self.scrollWidget)
self.setWidgetResizable(True)
self.setViewportMargins(0, 140, 0, 5)
self.setHorizontalScrollBarPolicy(Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
# self.title_area.setWidget(self.pivot)
# self.title_area.setWidgetResizable(True)
# self.title_area.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
# self.title_area.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
# self.title_area.setMinimumSize(800, 50)
# self.title_area.setStyleSheet("""
# QScrollBar:horizontal {
# height: 4px;
# background: #f0f0f0;
# border-radius: 10px;
# }
# QScrollBar::handle:horizontal {
# background: #888;
# border-radius: 10px;
# }
# QScrollBar::add-line:horizontal, QScrollBar::sub-line:horizontal {
# background: none;
# }
# QScrollBar::handle:horizontal:hover {
# background: #555;
# }
# """)
self.setObjectName('settingInterface')
self.scrollWidget.setObjectName('scrollWidget')
self.settingLabel.setObjectName('settingLabel')
StyleSheet.SETTING_INTERFACE.apply(self)
QScroller.grabGesture(self.viewport(), QScroller.ScrollerGestureType.LeftMouseButtonGesture)
scroller = QScroller.scroller(self.viewport())
scroller_props = scroller.scrollerProperties()
scroller_props.setScrollMetric(QScrollerProperties.ScrollMetric.OvershootDragDistanceFactor, 0.05)
scroller_props.setScrollMetric(QScrollerProperties.ScrollMetric.OvershootScrollDistanceFactor, 0.05)
scroller_props.setScrollMetric(QScrollerProperties.ScrollMetric.DecelerationFactor, 0.5)
scroller.setScrollerProperties(scroller_props)
def __initCard(self):
self.PowerGroup = SettingCardGroup(tr("体力设置"), self.scrollWidget)
self.powerPlanCard = PushSettingCardPowerPlan(
tr('配置'),
FIF.CALENDAR,
tr("体力计划"),
"power_plan"
)
self.instanceTypeCard = ExpandableComboBoxSettingCardInstanceType(
"instance_type",
FIF.ALIGNMENT,
tr("副本类型"),
None,
texts=[tr('拟造花萼(金)'), tr('拟造花萼(赤)'), tr('凝滞虚影'), tr('侵蚀隧洞'), tr('饰品提取')]
)
# self.calyxGoldenPreferenceCard = ComboBoxSettingCard2(
# "calyx_golden_preference",
# FIF.PIE_SINGLE,
# '拟造花萼(金)偏好地区',
# '',
# texts={'雅利洛-VI': 'Jarilo-VI', '仙舟「罗浮」': 'XianzhouLuofu', '匹诺康尼': 'Penacony'}
# )
self.instanceNameCard = PushSettingCardInstance(
tr('修改'),
FIF.PALETTE,
tr("副本名称"),
"instance_names"
)
# self.maxCalyxPerRoundNumOfAttempts = RangeSettingCard1(
# "max_calyx_per_round_num_of_attempts",
# [1, 6],
# FIF.HISTORY,
# "每轮拟造花萼挑战次数",
# '',
# )
self.instanceTeamEnableCard = InstanceTeamSettingCard(
FIF.EDIT,
tr("自动切换队伍"),
None
)
self.tpBeforeInstanceEnableCard = SwitchSettingCard1(
FIF.LEAF,
tr("清体力前传送至任意锚点"),
"",
"tp_before_instance"
)
# self.instanceTeamNumberCard = ComboBoxSettingCard1(
# "instance_team_number",
# FIF.FLAG,
# '队伍编号',
# None,
# texts=['3', '4', '5', '6', '7']
# )
self.useReservedTrailblazePowerEnableCard = SwitchSettingCard1(
FIF.HEART,
tr("使用后备开拓力"),
tr("单次上限300点全部使用需要将“任务完成后”选项修改为“循环”然后点击“完整运行”"),
"use_reserved_trailblaze_power"
)
self.useFuelEnableCard = SwitchSettingCard1(
FIF.CAFE,
tr("使用燃料"),
tr("单次上限5个全部使用需要将“任务完成后”选项修改为“循环”然后点击“完整运行”"),
"use_fuel"
)
self.breakDownLevelFourRelicsetEnableCard = SwitchSettingCard1(
FIF.FILTER,
tr("自动分解四星遗器(建议在游戏内配置结算遗器时自动分解)"),
tr("侵蚀隧洞、饰品提取、历战余响和模拟宇宙完成后自动分解四星及以下遗器"),
"break_down_level_four_relicset"
)
self.mergeImmersifierEnableCard = SwitchSettingCardImmersifier(
FIF.BASKETBALL,
tr("体力优先合成沉浸器(建议直接通过饰品提取获取位面饰品)"),
tr("达到指定上限后停止"),
"merge_immersifier"
)
self.instanceNameChallengeCountCard = PushSettingCardInstanceChallengeCount(
tr('修改'),
FIF.HISTORY,
tr("副本最大连续挑战次数(通常不建议修改保持默认即可)"),
"instance_names_challenge_count"
)
self.borrowEnableCard = ExpandableSwitchSettingCard(
"borrow_enable",
FIF.PIN,
tr("启用使用支援角色"),
''
)
self.borrowCharacterEnableCard = SwitchSettingCard1(
FIF.UNPIN,
tr("强制使用支援角色"),
tr("无论何时都要使用支援角色,即使日常实训中的要求已经完成"),
"borrow_character_enable"
)
self.borrowFriendsCard = PushSettingCardFriends(
tr('修改'),
FIF.FLAG,
tr("支援列表"),
"borrow_friends"
)
self.borrowScrollTimesCard = RangeSettingCard1(
"borrow_scroll_times",
[1, 10],
FIF.HISTORY,
tr("滚动查找次数"),
'',
)
self.buildTargetEnableCard = ExpandableSwitchSettingCard(
"build_target_enable",
FIF.LEAF,
tr("启用培养目标"),
tr("根据培养目标刷取行迹与遗器副本,如果无法获取培养目标则回退到默认的副本设置")
)
self.buildTargetPlanarOrnamentWeeklyCountCard = RangeSettingCard1(
"build_target_ornament_weekly_count",
[0, 7],
FIF.CALENDAR,
tr("每周饰品提取次数"),
tr("目标有足够资源后,执行饰品提取的次数,其余时间执行侵蚀隧洞"),
)
self.echoofwarEnableCard = ExpandableSwitchSettingCardEchoofwar(
"echo_of_war_enable",
FIF.MEGAPHONE,
tr("启用历战余响"),
tr("每周体力优先完成三次「历战余响」,支持配置从周几后开始执行,仅限完整运行生效"),
)
self.echoofwarRunTimeCard = PushSettingCardDate(
tr('修改'),
FIF.DATE_TIME,
tr("上次完成历战余响的时间"),
"echo_of_war_timestamp"
)
# self.echoofwarStartDayOfWeekCard = RangeSettingCard1(
# "echo_of_war_start_day_of_week",
# [1, 7],
# FIF.HISTORY,
# "周几开始执行【历战余响】",
# "假设值为4那么周1、2、3不执行「历战余响」周4、5、6、7则执行",
# )
# self.borrowCharacterFromCard = PushSettingCardEval(
# '修改',
# FIF.PEOPLE,
# "指定好友的支援角色(填写用户名,模糊匹配模式)",
# "borrow_character_from"
# )
# self.borrowCharacterInfoCard = PrimaryPushSettingCard(
# '打开角色文件夹',
# FIF.INFO,
# "↓↓支援角色↓↓",
# "角色对应的英文名字可以在 \"March7thAssistant\\assets\\images\\share\\character\" 中查看"
# )
# self.borrowCharacterCard = PushSettingCardEval(
# '修改',
# FIF.ARROW_DOWN,
# "支援角色优先级(从高到低)",
# "borrow_character"
# )
self.DailyGroup = SettingCardGroup(tr("日常设置"), self.scrollWidget)
self.dailyEnableCard = ExpandableSwitchSettingCard(
"daily_enable",
FIF.CALENDAR,
tr("启用每日实训"),
""
)
self.dailyMaterialEnableCard = SwitchSettingCard1(
FIF.CHECKBOX,
tr('通过 “合成材料” 完成任务'),
tr("请确保背包中有足够的 “熄灭原核” 用于合成 “微光原核” "),
"daily_material_enable"
)
# self.dailyHimekoTryEnableCard = SwitchSettingCard1(
# FIF.CHECKBOX,
# '通过 “姬子试用” 完成任务',
# "",
# "daily_himeko_try_enable"
# )
self.dailyMemoryOneEnableCard = SwitchSettingCard1(
FIF.CHECKBOX,
tr('通过 “回忆一” 完成任务'),
tr("请解锁混沌回忆并配置了队伍后再打开该选项"),
"daily_memory_one_enable"
)
self.dailyMemoryOneTeamCard = PushSettingCardTeam(
tr('修改'),
FIF.FLAG,
tr("回忆一队伍"),
"daily_memory_one_team"
)
self.lastRunTimeCard = PushSettingCardDate(
tr('修改'),
FIF.DATE_TIME,
tr("上次检测到完成日常的时间"),
"last_run_timestamp"
)
self.activityEnableCard = ExpandableSwitchSettingCard(
"activity_enable",
FIF.CERTIFICATE,
tr('启用活动检测'),
None
)
self.activityDailyCheckInEnableCard = SwitchSettingCard1(
FIF.COMPLETED,
tr('每日签到'),
tr("自动领取「星轨专票」或「星琼」,包含巡星之礼、巡光之礼和庆典祝礼活动"),
"activity_dailycheckin_enable"
)
self.activityGardenOfPlentyEnableCard = SwitchSettingCardGardenofplenty(
FIF.CALORIES,
tr('花藏繁生'),
tr("存在双倍次数时体力优先「拟造花萼」"),
"activity_gardenofplenty_enable"
)
self.activityRealmOfTheStrangeEnableCard = SwitchSettingCard1(
FIF.CALORIES,
tr('异器盈界'),
tr("存在双倍次数时体力优先「侵蚀隧洞」"),
"activity_realmofthestrange_enable"
)
self.activityPlanarFissureEnableCard = SwitchSettingCard1(
FIF.CALORIES,
tr('位面分裂'),
tr("存在双倍次数时体力优先「饰品提取」"),
"activity_planarfissure_enable"
)
self.rewardEnableCard = ExpandableSwitchSettingCard(
"reward_enable",
FIF.TRANSPARENT,
tr('启用奖励领取'),
""
)
self.dispatchEnableCard = SwitchSettingCard1(
FIF.STOP_WATCH,
tr('委托'),
None,
"reward_dispatch_enable"
)
self.mailEnableCard = SwitchSettingCard1(
FIF.MAIL,
tr('邮件'),
None,
"reward_mail_enable"
)
self.assistEnableCard = SwitchSettingCard1(
FIF.BRUSH,
tr('支援'),
None,
"reward_assist_enable"
)
self.questEnableCard = SwitchSettingCard1(
FIF.STOP_WATCH,
tr('每日实训'),
None,
"reward_quest_enable"
)
self.srpassEnableCard = SwitchSettingCard1(
FIF.QUIET_HOURS,
tr('无名勋礼'),
None,
"reward_srpass_enable"
)
self.achievementEnableCard = SwitchSettingCard1(
FIF.CERTIFICATE,
tr('成就'),
None,
"reward_achievement_enable"
)
# 兑换码奖励开关
self.redemptionEnableCard = SwitchSettingCard1(
FIF.BOOK_SHELF,
tr('兑换码'),
None,
"reward_redemption_code_enable"
)
self.assetEnableCard = ExpandableSwitchSettingCard(
"asset_manager_enable",
FIF.LIBRARY,
tr("启用资产管理"),
""
)
self.lc3StarSuperimposeEnableCard = SwitchSettingCard1(
FIF.ZIP_FOLDER,
tr("启用「3星光锥自动叠加」"),
tr("自动将3星光锥进行叠加以节省背包空间"),
"asset_lc3_star_superimpose_enable",
)
self.CurrencywarsGroup = SettingCardGroup(tr("货币"), self.scrollWidget)
self.currencywarsEnableCard = ExpandableSwitchSettingCard(
"currencywars_enable",
FIF.DICTIONARY,
tr('启用「货币战争」积分奖励'),
""
)
self.currencywarsRunTimeCard = PushSettingCardDate(
tr('修改'),
FIF.DATE_TIME,
tr("上次检测到完成货币战争积分奖励的时间"),
"currencywars_timestamp"
)
self.currencywarsTypeCard = ComboBoxSettingCard2(
"currencywars_type",
FIF.COMMAND_PROMPT,
tr('类别'),
'',
texts={tr('标准博弈'): 'normal', tr('超频博弈'): 'overclock'}
)
self.currencywarsBonusEnableCard = SwitchSettingCard1(
FIF.IOT,
tr('自动执行位面饰品快速提取'),
tr("在领取积分奖励后自动执行位面饰品快速提取消耗深度沉浸器"),
"currencywars_bonus_enable"
)
self.UniverseGroup = SettingCardGroup(tr("差分宇宙"), self.scrollWidget)
self.weeklyDivergentEnableCard = ExpandableSwitchSettingCard(
"weekly_divergent_enable",
FIF.DICTIONARY,
tr('启用「差分宇宙」积分奖励'),
""
)
self.weeklyDivergentRunTimeCard = PushSettingCardDate(
tr('修改'),
FIF.DATE_TIME,
tr("上次检测到完成差分宇宙积分奖励的时间"),
"weekly_divergent_timestamp"
)
self.weeklyDivergentTypeCard = ComboBoxSettingCard2(
"weekly_divergent_type",
FIF.COMMAND_PROMPT,
tr('类别'),
'',
texts={tr('常规演算'): 'normal', tr('周期演算'): 'cycle'}
)
self.weeklyDivergentLevelCard = RangeSettingCard1(
"weekly_divergent_level",
[1, 5],
FIF.HISTORY,
tr("难度等级"),
"",
)
self.weeklyDivergentBonusEnableCard = SwitchSettingCard1(
FIF.IOT,
tr('自动执行饰品提取'),
tr("在领取积分奖励后自动执行饰品提取消耗沉浸器"),
"weekly_divergent_bonus_enable"
)
self.weeklyDivergentStableModeCard = SwitchSettingCard1(
FIF.SPEED_OFF,
tr('启用稳定模式'),
tr("运行若出现问题可尝试开启,适配低性能环境,云游戏默认使用此模式"),
"weekly_divergent_stable_mode"
)
self.universeEnableCard = ExpandableSwitchSettingCard(
"universe_enable",
FIF.VPN,
tr('启用模拟宇宙/差分宇宙 (Auto_Simulated_Universe)'),
tr("通常用于反复刷取遗器经验和灵之珠泪(代替敌方掉落素材)直到每周上限")
)
self.universeOperationModeCard = ComboBoxSettingCard2(
"universe_operation_mode",
FIF.COMMAND_PROMPT,
tr('运行模式'),
'',
texts={tr('集成'): 'exe', tr('源码'): 'source'}
)
self.universeCategoryCard = ComboBoxSettingCard2(
"universe_category",
FIF.COMMAND_PROMPT,
tr('类别'),
'',
texts={tr('差分宇宙'): 'divergent', tr('模拟宇宙'): 'universe'}
)
self.divergentTypeCard = ComboBoxSettingCard2(
"divergent_type",
FIF.COMMAND_PROMPT,
tr('选择差分宇宙时类别'),
'',
texts={tr('常规演算'): 'normal', tr('周期演算'): 'cycle'}
)
self.universeTimeoutCard = RangeSettingCard1(
"universe_timeout",
[1, 24],
FIF.HISTORY,
tr("模拟宇宙/差分宇宙超时"),
tr("超过设定时间强制停止(单位小时)"),
)
self.universeRunTimeCard = PushSettingCardDate(
tr('修改'),
FIF.DATE_TIME,
tr("上次运行模拟宇宙/差分宇宙的时间"),
"universe_timestamp"
)
self.universeBonusEnableCard = SwitchSettingCard1(
FIF.IOT,
tr('自动执行饰品提取/领取沉浸奖励'),
tr("类别为“差分宇宙”时,在领取积分奖励后自动执行饰品提取消耗沉浸器。类别为“模拟宇宙”时,自动领取沉浸奖励。"),
"universe_bonus_enable"
)
self.universeFrequencyCard = ComboBoxSettingCard2(
"universe_frequency",
FIF.MINIMIZE,
tr('运行频率'),
'',
texts={tr('每周'): 'weekly', tr('每天'): 'daily'}
)
self.universeCountCard = RangeSettingCard1(
"universe_count",
[0, 34],
FIF.HISTORY,
tr("运行次数"),
tr("注意中途停止不会计数0 代表不指定,使用模拟宇宙原版逻辑"),
)
# self.divergentTeamTypeCard = ComboBoxSettingCard2(
# "divergent_team_type",
# FIF.FLAG,
# tr('差分宇宙队伍类型'),
# '',
# texts={tr('追击'): '追击', tr('持续伤害 (DoT)'): 'dot', tr('终结技'): '终结技', tr('击破'): '击破', tr('盾反'): '盾反'}
# )
fates = {}
fates = {}
for a in [tr("不配置"), tr("存护"), tr("记忆"), tr("虚无"), tr("丰饶"), tr("巡猎"), tr("毁灭"), tr("欢愉"), tr("繁育"), tr("智识")]:
fates[a] = a
self.universeFateCard = ComboBoxSettingCard2(
"universe_fate",
FIF.PIE_SINGLE,
tr('命途(仅模拟宇宙生效)'),
'',
texts=fates
)
self.universeDifficultyCard = RangeSettingCard1(
"universe_difficulty",
[0, 5],
FIF.HISTORY,
tr("难度 (0为不配置仅模拟宇宙生效)"),
"",
)
self.FightGroup = SettingCardGroup(tr("锄地"), self.scrollWidget)
self.fightEnableCard = ExpandableSwitchSettingCard(
"fight_enable",
FIF.BUS,
tr('启用锄大地 (Fhoe-Rail)'),
""
)
self.fightOperationModeCard = ComboBoxSettingCard2(
"fight_operation_mode",
FIF.COMMAND_PROMPT,
tr('运行模式'),
'',
texts={tr('集成'): 'exe', tr('源码'): 'source'}
)
self.universeEnableGpuCard = SwitchSettingCard1(
FIF.COMMAND_PROMPT,
tr('启用模拟宇宙 GPU 加速'),
tr('开启后可能提升运行速度,若出现错误、异常或不稳定,请关闭此选项'),
"universe_enable_gpu"
)
self.fightTimeoutCard = RangeSettingCard1(
"fight_timeout",
[1, 24],
FIF.HISTORY,
tr("锄大地超时"),
tr("超过设定时间强制停止(单位小时)"),
)
self.fightTeamEnableCard = SwitchSettingCardTeam(
FIF.EDIT,
tr('自动切换队伍'),
None,
"fight_team_enable",
"fight_team_number"
)
# self.fightTeamNumberCard = ComboBoxSettingCard1(
# "fight_team_number",
# FIF.FLAG,
# '队伍编号',
# None,
# texts=['3', '4', '5', '6', '7']
# )
self.FightRunTimeCard = PushSettingCardDate(
tr('修改'),
FIF.DATE_TIME,
tr("上次运行锄大地的时间"),
"fight_timestamp"
)
self.fightAllowMapBuyCard = ComboBoxSettingCard2(
"fight_allow_map_buy",
FIF.GLOBE,
tr('购买代币与过期邮包'),
'',
texts={tr("不配置"): "不配置", tr("启用"): True, tr("停用"): False}
)
self.fightAllowSnackBuyCard = ComboBoxSettingCard2(
"fight_allow_snack_buy",
FIF.GLOBE,
tr('购买秘技零食并合成零食'),
'',
texts={tr("不配置"): "不配置", tr("启用"): True, tr("停用"): False}
)
self.fightMainMapCard = ComboBoxSettingCard2(
"fight_main_map",
FIF.GLOBE,
tr('优先星球'),
'',
texts={tr("不配置"): "0", tr("空间站"): "1", tr("雅利洛"): "2", tr("仙舟"): "3", tr("匹诺康尼"): "4", tr("翁法罗斯"): 5}
)
self.ImmortalGameGroup = SettingCardGroup(tr("逐光捡金"), self.scrollWidget)
self.forgottenhallEnableCard = ExpandableSwitchSettingCard(
"forgottenhall_enable",
FIF.SPEED_HIGH,
tr('启用混沌回忆'),
""
)
self.forgottenhallLevelCard = PushSettingCardEval(
tr('修改'),
FIF.MINIMIZE,
tr("关卡范围"),
"forgottenhall_level"
)
# self.forgottenhallRetriesCard = RangeSettingCard1(
# "forgottenhall_retries",
# [0, 10],
# FIF.REMOVE_FROM,
# "重试次数",
# )
self.forgottenhallTeamsCard = PushSettingCardTeamWithSwap(
FIF.FLAG,
tr("混沌回忆队伍配置"),
"forgottenhall_team1",
"forgottenhall_team2"
)
self.forgottenhallRunTimeCard = PushSettingCardDate(
tr('修改'),
FIF.DATE_TIME,
tr("上次运行混沌回忆的时间"),
"forgottenhall_timestamp"
)
self.purefictionEnableCard = ExpandableSwitchSettingCard(
"purefiction_enable",
FIF.SPEED_HIGH,
tr('启用虚构叙事'),
""
)
self.purefictionLevelCard = PushSettingCardEval(
tr('修改'),
FIF.MINIMIZE,
tr("关卡范围"),
"purefiction_level"
)
self.purefictionTeamsCard = PushSettingCardTeamWithSwap(
FIF.FLAG,
tr("虚构叙事队伍配置"),
"purefiction_team1",
"purefiction_team2"
)
self.purefictionRunTimeCard = PushSettingCardDate(
tr('修改'),
FIF.DATE_TIME,
tr("上次运行虚构叙事的时间"),
"purefiction_timestamp"
)
self.ApocalypticEnableCard = ExpandableSwitchSettingCard(
"apocalyptic_enable",
FIF.SPEED_HIGH,
tr('启用末日幻影'),
""
)
self.ApocalypticLevelCard = PushSettingCardEval(
tr('修改'),
FIF.MINIMIZE,
tr("关卡范围"),
"apocalyptic_level"
)
self.ApocalypticTeamsCard = PushSettingCardTeamWithSwap(
FIF.FLAG,
tr("末日幻影队伍配置"),
"apocalyptic_team1",
"apocalyptic_team2"
)
self.ApocalypticRunTimeCard = PushSettingCardDate(
tr('修改'),
FIF.DATE_TIME,
tr("上次运行末日幻影的时间"),
"apocalyptic_timestamp"
)
self.CloudGameGroup = SettingCardGroup(
tr("云崩铁设置"),
self.scrollWidget
)
self.cloudGameEnableCard = SwitchSettingCard1(
FIF.SPEED_HIGH,
tr("使用“云·星穹铁道”"),
tr("开启后,将改用云·星穹铁道来执行清体力等自动化任务。无需固定窗口,可在后台运行。(模拟宇宙和锄大地仍需保持窗口全屏)"),
"cloud_game_enable"
)
self.cloudGameFullScreenCard = SwitchSettingCard1(
FIF.FULL_SCREEN,
tr("全屏运行"),
None,
"cloud_game_fullscreen_enable"
)
self.cloudGameMaxQueueTimeCard = RangeSettingCard1(
"cloud_game_max_queue_time",
[1, 120],
FIF.SPEED_MEDIUM,
tr("最大排队等待时间(分钟)"),
''
)
# self.cloudGameVideoQualityCard = ComboBoxSettingCard2(
# "cloud_game_video_quality",
# FIF.VIDEO,
# "云游戏画质",
# None,
# texts={"超高清": "0", "高清": "1", "标清": "2", "低清": "3"}
# )
# self.cloudGameSmoothFirstCard = SwitchSettingCard1(
# FIF.SPEED_HIGH,
# "画面流畅优先",
# "启用这个选项后,当网速过慢时,会自动调低画质",
# "cloud_game_smooth_first_enable"
# )
# self.cloudGameShowStatusCard = SwitchSettingCardCloudGameStatus(
# FIF.INFO,
# "云游戏内显示网络状态",
# None,
# "cloud_game_status_bar_enable",
# "cloud_game_status_bar_type"
# )
self.browserTypeCard = ExpandableComboBoxSettingCard(
"browser_type",
FIF.GLOBE,
tr("浏览器类型"),
tr("建议保持默认的“集成Chrome For Testing”效果最好"),
{tr("集成Chrome For Testing"): "integrated", tr("Chrome"): "chrome", tr("Edge"): "edge"}
)
self.browserDownloadUseMirrorCard = SwitchSettingCard1(
FIF.CLOUD_DOWNLOAD,
tr("使用国内镜像下载浏览器和驱动"),
None,
"browser_download_use_mirror"
)
self.browserPersistentCard = SwitchSettingCard1(
FIF.DOWNLOAD,
tr("保存浏览器数据(游戏的登录状态和本地数据)"),
None,
"browser_persistent_enable"
)
self.browserScaleCard = ComboBoxSettingCard2(
"browser_scale_factor",
FIF.ZOOM,
tr("浏览器画面缩放DPI"),
tr("非 1920x1080 屏幕下,云游戏画面无法铺满屏幕,可以调整这个值改变画面缩放"),
texts={'50%': 0.5, '67%': 0.67, '75%': 0.75, '80%': 0.80, '90%': 0.90, tr('无缩放100%'): 1.0,
'110%': 1.10, '125%': 1.25, '150%': 1.5, '175%': 1.75, '200%': 2.0}
)
self.browserLaunchArgCard = PushSettingCardEval(
"修改",
FIF.CODE,
tr("浏览器启动参数"),
"browser_launch_argument"
)
self.browserHeadlessCard = ExpandableSwitchSettingCard(
"browser_headless_enable",
FIF.VIEW,
tr("启用无窗口模式(后台运行)"),
tr("不支持模拟宇宙和锄大地")
)
self.browserHeadlessRestartCard = SwitchSettingCard1(
FIF.SYNC,
tr("未登录时自动切换为有窗口模式"),
tr("开启后:在无窗口模式检测到未登录时,将自动以有窗口模式重启浏览器以便登录;关闭后:将在无窗口模式下尝试二维码登录。"),
"browser_headless_restart_on_not_logged_in"
)
# self.browserCookiesCard = SwitchSettingCard1(
# FIF.PALETTE, # 这个画盘长得很像 Cookie
# "保存 Cookies登录状态",
# None,
# "browser_dump_cookies_enable"
# )
self.ProgramGroup = SettingCardGroup(tr('程序设置'), self.scrollWidget)
self.logLevelCard = ComboBoxSettingCardLog(
"log_level",
FIF.TAG,
tr('日志等级'),
"",
texts={tr('简洁'): 'INFO', tr('详细'): 'DEBUG'}
)
self.gamePathCard = PushSettingCard(
tr('修改'),
FIF.GAME,
tr("游戏路径"),
cfg.game_path
)
self.updateViaLauncherEnableCard = ExpandableSwitchSettingCard(
"update_via_launcher",
FIF.UPDATE,
tr('通过启动器更新游戏【测试版】'),
""
)
self.launcherPathCard = PushSettingCard(
tr('修改'),
FIF.GAME,
tr("米哈游启动器路径"),
cfg.launcher_path
)
self.startGameTimeoutCard = RangeSettingCard1(
"start_game_timeout",
[10, 60],
FIF.DATE_TIME,
tr("启动游戏超时时间(分)"),
"",
)
self.updateGameTimeoutCard = RangeSettingCard1(
"update_game_timeout",
[1, 24],
FIF.DATE_TIME,
tr("更新游戏超时时间(时)"),
"",
)
# self.importConfigCard = PushSettingCard(
# '导入',
# FIF.ADD_TO,
# '导入配置',
# '选择需要导入的 config.yaml 文件(重启后生效)'
# )
self.pauseAfterSuccess = SwitchSettingCard1(
FIF.SYNC,
tr('成功后暂停程序'),
tr("如果勾选,除非循环模式,执行成功后暂停程序。"),
"pause_after_success"
)
self.exitAfterFailure = SwitchSettingCard1(
FIF.SYNC,
tr('失败后直接退出'),
tr("如果勾选,那么失败后直接退出,否则失败后暂停程序。"),
"exit_after_failure"
)
self.afterFinishCard = ExpandableComboBoxSettingCard(
"after_finish",
FIF.POWER_BUTTON,
tr('任务完成后'),
tr('“退出”指退出游戏,不再建议使用循环模式,请改用日志界面的定时运行功能'),
texts={tr(''): 'None', tr('退出'): 'Exit', tr('关机'): 'Shutdown', tr('睡眠'): 'Sleep', tr('休眠'): 'Hibernate', tr('重启'): 'Restart', tr('注销'): 'Logoff', tr('关闭显示器'): 'TurnOffDisplay', tr('运行脚本'): 'RunScript', tr('循环'): 'Loop'}
)
self.loopModeCard = ComboBoxSettingCard2(
"loop_mode",
FIF.COMMAND_PROMPT,
tr('循环模式(请改用日志界面的定时运行功能)'),
'',
texts={tr('定时任务'): 'scheduled', tr('根据开拓力'): 'power'}
)
self.scheduledCard = TimePickerSettingCard1(
"scheduled_time",
FIF.DATE_TIME,
tr("定时任务时间"),
)
self.powerLimitCard = RangeSettingCard1(
"power_limit",
[10, 300],
FIF.HEART,
tr("循环运行再次启动所需开拓力"),
tr("游戏刷新后优先级更高"),
)
self.refreshHourEnableCard = RangeSettingCard1(
"refresh_hour",
[0, 23],
FIF.DATE_TIME,
tr("游戏刷新时间"),
tr("用于循环运行及判断任务状态,默认凌晨四点"),
)
self.ScriptPathCard = PushSettingCard(
tr('修改'),
FIF.CODE,
tr("脚本或程序路径(选择运行脚本时生效)"),
cfg.script_path
)
self.playAudioCard = SwitchSettingCard1(
FIF.ALBUM,
tr('声音提示'),
tr('任务完成后列车长唱歌提示帕!'),
"play_audio"
)
self.closeWindowActionCard = ComboBoxSettingCard2(
"close_window_action",
FIF.CLOSE,
tr('关闭窗口时'),
tr('选择关闭窗口时的默认行为,也可以在关闭时由对话框询问'),
texts={tr('询问'): 'ask', tr('最小化到托盘'): 'minimize', tr('关闭程序'): 'close'}
)
self.NotifyGroup = SettingCardGroup(tr("消息推送"), self.scrollWidget)
self.notifyMasterEnableCard = ExpandableSwitchSettingCard(
"notification_enable",
FIF.RINGER,
tr("启用消息推送"),
tr("消息推送总开关")
)
self.testNotifyCard = PrimaryPushSettingCard(
tr("发送消息"),
FIF.SEND,
tr("测试消息推送"),
""
)
self.notifyLevelCard = ComboBoxSettingCard2(
"notify_level",
FIF.COMMAND_PROMPT,
tr('通知级别'),
'',
texts={tr('推送所有通知'): 'all', tr('仅推送错误通知'): 'error'}
)
self.notifyMergeCard = SwitchSettingCard1(
FIF.PASTE,
tr('通知合并'),
tr('开启后,完整运行结束时将所有通知合并为一条发送'),
"notify_merge"
)
self.notifyImageEnableCard = SwitchSettingCard1(
FIF.CAMERA,
tr('推送图片'),
tr('关闭后推送消息时不再发送截图'),
"notify_send_images"
)
self.notifyTemplateCard = PushSettingCardNotifyTemplate(
tr('修改'),
FIF.FONT_SIZE,
tr("消息推送格式"),
"notify_template"
)
self.notifyEnableGroup = []
self.notifyProviderMeta = {
"winotify": {
"icon": FIF.BACK_TO_WINDOW,
"display_name": "Windows",
"description": tr("Windows 原生通知"),
},
"telegram": {
"icon": FIF.AIRPLANE,
"display_name": "Telegram",
"description": tr("通常需要可访问 Telegram 网络"),
"support_image": True,
"params": {
"token": {"title": tr("机器人令牌"), "description": tr("获取方式:创建 Bot → @BotFather → /newbot → 获取 Token")},
"userid": {"title": tr("用户/群组 ID"), "description": tr("接收通知的用户 ID 或群组 ID以 - 开头)")},
"api_url": {"title": tr("自定义 API 地址"), "description": tr("可选参数,自定义 Telegram API 地址,例如 api.telegram.org")},
"proxies": {"title": tr("代理配置"), "description": tr("可选参数,例如 127.0.0.1:10808 或 socks5://127.0.0.1:1080不填则使用系统 PAC 代理")},
}
},
"matrix": {
"icon": FIF.GLOBE,
"display_name": "Matrix",
"description": tr("适用于 Matrix 协议"),
"support_image": True,
"params": {
"homeserver": {"title": tr("服务器地址"), "description": tr("服务器地址,例如 https://matrix.org")},
"device_id": {"title": tr("设备 ID"), "description": tr("设备 ID通常是 10 位大写字母或数字")},
"user_id": {"title": tr("用户 ID"), "description": tr("用户 ID例如 @user:matrix.org")},
"access_token": {"title": tr("访问令牌"), "description": tr("登录后分配的 Access Token")},
"room_id": {"title": tr("房间 ID"), "description": tr("目标房间 ID例如 !xxx:matrix.org")},
"proxy": {"title": tr("代理配置"), "description": tr("可选参数,例如 127.0.0.1:10808 或 socks5://127.0.0.1:1080不填则使用系统 PAC 代理")},
"separately_text_media": {"title": tr("文字与图片分开发送"), "description": tr("是否分开发送文字和图片,避免部分客户端不显示文字"), "type": "bool"},
}
},
"serverchanturbo": {
"icon": FIF.ROBOT,
"display_name": tr("Server酱·Turbo版"),
"description": tr("微信推送,适合轻量通知"),
"params": {
"sctkey": {"title": tr("SendKey"), "description": tr("在 https://sct.ftqq.com/ 获取的 SendKey")},
"channel": {"title": tr("发送通道"), "description": tr("可选参数")},
"openid": {"title": tr("接收人 OpenID"), "description": tr("可选参数")},
}
},
"serverchan3": {
"icon": FIF.ROBOT,
"display_name": tr("Server酱³"),
"description": tr("Server酱³ APP 推送"),
"params": {
"sendkey": {"title": tr("SendKey",), "description": tr("在 https://sc3.ft07.com/ 获取的 SendKey")},
}
},
"bark": {
"icon": FIF.MAIL,
"display_name": "Bark",
"description": tr("适合 iOS 设备推送"),
"params": {
"key": {"title": tr("推送密钥"), "description": tr("在 Bark APP 中获取的唯一标识符")},
"group": {"title": tr("分组名"), "description": tr("可选参数Bark 通知的分组名")},
"icon": {"title": tr("图标地址"), "description": tr("可选参数,通知图标的 URL")},
"isarchive": {"title": tr("归档"), "description": tr("可选参数1 归档0 不归档")},
"sound": {"title": tr("提示音"), "description": tr("可选参数,自定义提示音名称")},
"url": {"title": tr("服务地址"), "description": tr("可选参数,自定义 Bark 服务的 URL")},
"copy": {"title": tr("复制内容"), "description": tr("可选参数,通知点击后复制内容")},
"autocopy": {"title": tr("自动复制"), "description": tr("可选参数,是否自动复制")},
"cipherkey": {"title": tr("加密密钥"), "description": tr("可选参数,推送加密密钥,需在 Bark APP 中配置相同的密钥")},
"ciphermethod": {"title": tr("加密算法"), "description": tr("可选参数,支持 cbc 或 ecb需与 Bark APP 中配置的算法一致")},
}
},
"smtp": {
"icon": FIF.MAIL,
"display_name": "SMTP",
"description": tr("常用于邮箱提醒"),
"support_image": True,
"params": {
"host": {"title": tr("SMTP 服务器")},
"user": {"title": tr("用户名/邮箱")},
"password": {"title": tr("密码/授权码"), "description": tr("部分邮箱需要填写授权码(如 QQ 邮箱)")},
"From": {"title": tr("发件人"), "description": tr("可选参数,发件人邮箱,默认使用 user")},
"To": {"title": tr("收件人"), "description": tr("可选参数,收件人邮箱,默认使用 user")},
"port": {"title": tr("端口"), "description": tr("可选参数,端口,默认 465")},
"ssl": {"title": tr("启用 SSL"), "description": tr("可选参数,是否启用 SSL"), "type": "bool"},
"starttls": {"title": tr("启用 STARTTLS"), "description": tr("可选参数,是否启用 STARTTLS"), "type": "bool"},
"ssl_unverified": {"title": tr("跳过证书验证"), "description": tr("可选参数,是否跳过 SSL 证书验证"), "type": "bool"},
}
},
"onebot": {
"icon": FIF.ROBOT,
"display_name": "OneBot",
"description": tr("适用于 OneBot 协议"),
"support_image": True,
"params": {
"endpoint": {"title": tr("服务地址"), "description": tr("OneBot 服务端点地址,例如 http://127.0.0.1:3000")},
"token": {"title": tr("访问令牌"), "description": tr("可选参数Access Token")},
"user_id": {"title": tr("私聊用户 ID"), "description": tr("可选参数,私聊接收用户 ID")},
"group_id": {"title": tr("群组 ID"), "description": tr("可选参数,群聊接收群组 ID")},
}
},
"gocqhttp": {
"icon": FIF.ROBOT,
"display_name": "Go-cqhttp",
"description": tr("Go-cqhttp 项目已停止维护"),
"support_image": True,
"params": {
"endpoint": {"title": tr("服务地址")},
"message_type": {"title": tr("消息类型"), "description": tr("消息类型private 或 group")},
"token": {"title": tr("访问令牌"), "description": tr("可选参数Access Token")},
"user_id": {"title": tr("私聊用户 ID"), "description": tr("可选参数,私聊接收用户 ID")},
"group_id": {"title": tr("群组 ID"), "description": tr("可选参数,群聊接收群组 ID")},
}
},
"dingtalk": {
"icon": FIF.MAIL,
"display_name": tr("钉钉"),
"description": tr("钉钉机器人推送"),
"params": {
"token": {"title": tr("机器人令牌")},
"secret": {"title": tr("加签密钥"), "description": tr("可选参数,安全加签密钥")},
}
},
"pushplus": {
"icon": FIF.MAIL,
"display_name": "Pushplus",
"description": tr("Pushplus 通知服务"),
"params": {
"token": {"title": tr("推送令牌")},
"channel": {"title": tr("推送渠道"), "description": tr("可选参数")},
"webhook": {"title": tr("Webhook 地址"), "description": tr("可选参数Webhook URL")},
"callbackUrl": {"title": tr("回调地址"), "description": tr("可选参数,回调 URL")},
}
},
"wechatworkbot": {
"icon": FIF.MAIL,
"display_name": tr("企业微信机器人"),
"description": tr("企业微信机器人消息推送"),
"support_image": True,
"params": {
"key": {"title": tr("机器人 Key")},
"webhook_url": {"title": tr("Webhook 地址"), "description": tr("可选参数,企业微信机器人 Webhook URL")},
}
},
"wechatworkapp": {
"icon": FIF.MAIL,
"display_name": tr("企业微信应用"),
"description": tr("企业微信应用消息推送"),
"support_image": True,
"params": {
"corpid": {"title": tr("企业 ID")},
"corpsecret": {"title": tr("应用密钥")},
"agentid": {"title": tr("应用 AgentId")},
"touser": {"title": tr("接收用户"), "description": tr("可选参数,接收用户,@all 表示全员")},
}
},
"gotify": {
"icon": FIF.MAIL,
"display_name": "Gotify",
"description": tr("Gotify 私有通知服务"),
"params": {
"url": {"title": tr("服务地址"), "description": tr("Gotify 服务器 URL例如 https://gotify.example.com")},
"token": {"title": tr("访问令牌"), "description": tr("Gotify 应用的 Access Token")},
"priority": {"title": tr("优先级"), "description": tr("可选参数,通知优先级,范围 1-10越高优先级越高。1-3:仅图标4-7:图标 + 声音8-10:图标 + 声音 + 震动")},
}
},
"discord": {
"icon": FIF.MAIL,
"display_name": "Discord",
"description": tr("Discord Webhook 推送"),
"params": {
"webhook": {"title": tr("Webhook 地址")},
"username": {"title": tr("显示用户名"), "description": tr("可选参数,显示用户名")},
"avatar_url": {"title": tr("头像地址"), "description": tr("可选参数,头像 URL")},
"color": {"title": tr("消息颜色"), "description": tr("可选参数嵌入消息颜色十六进制颜色值0x3498db")},
}
},
"pushdeer": {
"icon": FIF.MAIL,
"display_name": "Pushdeer",
"description": tr("Pushdeer 通知服务"),
"params": {
"token": {"title": tr("推送令牌"), "description": tr("Pushdeer Token")},
"url": {"title": tr("服务地址"), "description": tr("可选参数,自定义 Pushdeer 服务地址")},
}
},
"lark": {
"icon": FIF.MAIL,
"display_name": tr("飞书"),
"description": tr("飞书机器人推送"),
"support_image": True,
"params": {
"webhook": {"title": tr("Webhook 地址")},
"content": {"title": tr("消息内容")},
"keyword": {"title": tr("关键词"), "description": tr("可选参数,关键词安全校验内容")},
"sign": {"title": tr("签名"), "description": tr("可选参数,签名安全校验参数")},
"imageenable": {"title": tr("启用图片"), "description": tr("是否发送图片"), "type": "bool"},
"appid": {"title": tr("应用 AppId"), "description": tr("发送图片时必填:飞书应用 AppId")},
"secret": {"title": tr("应用 Secret"), "description": tr("发送图片时必填:飞书应用 Secret")},
}
},
"meow": {
"icon": FIF.ROBOT,
"display_name": "MeoW",
"description": tr("适合 鸿蒙NEXT 设备推送"),
"params": {
"nickname": {"title": tr("昵称")},
}
},
"kook": {
"icon": FIF.ROBOT,
"display_name": "KOOK",
"description": tr("KOOK 机器人推送"),
"support_image": True,
"params": {
"token": {"title": tr("机器人令牌"), "description": tr("KOOK 机器人的 Token")},
"target_id": {"title": tr("目标 ID"), "description": tr("接收消息的用户 ID 或频道 ID")},
"chat_type": {"title": tr("聊天类型"), "description": tr("可选参数1 为私聊9 为频道")},
}
},
"webhook": {
"icon": FIF.CODE,
"display_name": "Webhook",
"description": tr("可自定义请求方法、请求头和请求体"),
"support_image": True,
"params": {
"url": {"title": tr("接收地址")},
"method": {"title": tr("请求方法"), "description": tr("可选参数HTTP 方法,默认 POST")},
"headers": {"title": tr("请求头"), "description": tr('可选参数,请求头 JSON 格式字符串,如:{"Authorization": "Bearer token"}')},
"body": {"title": tr("请求体"), "description": tr("可选参数,请求体模板 JSON 格式字符串,支持 {title}/{content}/{image} 占位符")},
}
},
"custom": {
"icon": FIF.CODE,
"display_name": tr("自定义通知"),
"description": tr("自定义 HTTP 请求推送"),
"support_image": True,
"params": {
"url": {"title": tr("请求地址"), "description": tr("请求地址OneBot 可填写 send_msg 接口 URL")},
"method": {"title": tr("请求方法"), "description": tr("请求方法,通常 get 或 post")},
"datatype": {"title": tr("数据类型"), "description": tr("数据类型,通常为 data 或 json")},
"image": {"title": tr("图片模板"), "description": tr("可选参数,图片消息模板,{image} 会替换为 Base64")},
"data": {"title": tr("数据模板"), "description": tr("请求体模板,{message} 会替换为标题和内容")},
}
},
}
self.notifyEnableGroup = []
provider_names = self.__getNotifyProviderNames()
for notifier_name in provider_names:
enable_key = f"notify_{notifier_name}_enable"
provider_meta = self.notifyProviderMeta.get(notifier_name, {})
display_name = provider_meta.get("display_name", notifier_name.capitalize())
support_image = tr("(支持图片)") if provider_meta.get("support_image", False) else ""
provider_description = provider_meta.get("description", "")
has_params = bool(provider_meta.get("params"))
if support_image:
provider_description = f"{provider_description} {support_image}".strip()
if has_params:
notifyEnableCard = ExpandableSwitchSettingCard(
enable_key,
provider_meta.get("icon", FIF.MAIL),
tr('启用 {} 通知').format(display_name),
provider_description
)
notifyEnableCard.switchChanged.connect(self.__refreshNotifiers)
notifyParamCards = self.__createNotifyParamCards(notifier_name)
if notifyParamCards:
notifyEnableCard.addSettingCards(notifyParamCards)
else:
notifyEnableCard = SwitchSettingCard1(
provider_meta.get("icon", FIF.MAIL),
tr('启用 {} 通知').format(display_name),
provider_description,
enable_key,
self
)
notifyEnableCard.switchButton.checkedChanged.connect(self.__refreshNotifiers)
self.notifyEnableGroup.append(notifyEnableCard)
self.MiscGroup = SettingCardGroup(tr("杂项"), self.scrollWidget)
self.autoBattleDetectEnableCard = SwitchSettingCard1(
FIF.ROBOT,
tr('启用自动战斗和二倍速检测'),
tr("游戏启动前通过修改注册表或本地存储开启自动战斗和二倍速,并在清体力、货币战争和逐光捡金场景中检测并保持自动战斗状态"),
"auto_battle_detect_enable"
)
self.ocrGpuAccelerationCard = SwitchSettingCard1(
FIF.SPEED_HIGH,
tr('启用 OCR GPU 加速'),
tr("使用 DirectML 加速 OCR 识别,若 GPU 负载高导致 OCR 过慢会自动关闭(仅 Windows 10 Build 18362 及以上支持)"),
"ocr_gpu_acceleration"
)
self.autoSetResolutionEnableCard = SwitchSettingCard1(
FIF.FULL_SCREEN,
tr('启用自动修改分辨率并关闭自动 HDR'),
tr("通过软件启动游戏会自动修改 1920x1080 分辨率并关闭自动 HDR不影响手动启动游戏支持国服和国际服"),
"auto_set_resolution_enable"
)
self.autoSetGamePathEnableCard = SwitchSettingCard1(
FIF.GAME,
tr('启用自动配置游戏路径'),
tr("通过快捷方式、官方启动器、运行中的游戏进程等方式尝试自动配置游戏路径(支持国服和国际服)"),
"auto_set_game_path_enable"
)
self.useBackgroundScreenshotCard = SwitchSettingCard1(
FIF.CAMERA,
tr('优先使用后台截图'),
tr("默认开启,可以避免悬浮窗等干扰"),
"use_background_screenshot"
)
if sys.platform == 'win32':
self.StartMarch7thAssistantCard = StartMarch7thAssistantSwitchSettingCard(
FIF.GAME,
tr('在用户登录时启动'),
tr("通过任务计划程序在开机后自动执行完整运行模式(可能还需要自行配置电脑无需输入密码自动登录)")
)
self.hotkeyCard = SwitchSettingCardHotkey(
FIF.SETTING,
tr('修改按键'),
tr("配置秘技、地图、跃迁、停止任务等按键设置")
)
self.AboutGroup = SettingCardGroup(tr('关于'), self.scrollWidget)
self.githubCard = PrimaryPushSettingCard(
tr('项目主页'),
FIF.GITHUB,
tr('项目主页'),
"https://github.com/moesnow/March7thAssistant"
)
self.qqGroupCard = PrimaryPushSettingCard(
tr('加入群聊'),
FIF.EXPRESSIVE_INPUT_ENTRY,
tr('QQ群'),
""
)
self.feedbackCard = PrimaryPushSettingCard(
tr('提供反馈'),
FIF.FEEDBACK,
tr('提供反馈'),
tr('帮助我们改进 March7thAssistant')
)
self.aboutCard = PrimaryPushSettingCard(
tr('检查更新'),
FIF.INFO,
tr('关于'),
tr('当前版本:') + " " + cfg.version
)
self.updateSourceCard = ExpandableComboBoxSettingCardUpdateSource(
"update_source",
FIF.SPEED_HIGH,
tr('更新源'),
self.parent,
"",
texts={tr('海外源'): 'GitHub', tr('Mirror 酱'): 'MirrorChyan'}
)
self.checkUpdateCard = SwitchSettingCard1(
FIF.SYNC,
tr('启动时检测更新'),
"",
"check_update"
)
self.updatePrereleaseEnableCard = SwitchSettingCard1(
FIF.TRAIN,
tr('加入预览版更新渠道'),
"",
"update_prerelease_enable"
)
self.updateFullEnableCard = SwitchSettingCard1(
FIF.GLOBE,
tr('更新时下载完整包'),
tr("更新将包含依赖组件,建议保持开启。若关闭此选项,需自行手动更新依赖组件,可能会导致出现不可预期的错误。"),
"update_full_enable"
)
self.mirrorchyanCdkCard = PushSettingCardMirrorchyan(
tr('修改'),
FIF.BOOK_SHELF,
tr("Mirror 酱 CDK"),
self.parent,
"mirrorchyan_cdk"
)
self.languageCard = ComboBoxSettingCardLanguage(
"ui_language",
FIF.LANGUAGE,
'界面语言 / 界面語言 / 인터페이스 언어 / UI Language',
'需要重启程序生效 / 需要重啟程式生效 / 변경 사항을 적용하려면 재시작 필요 / Requires restart to take effect',
texts={'自动': 'auto', '简体中文': 'zh_CN', '繁體中文': 'zh_TW', '한국어': 'ko_KR', 'English': 'en_US'}
)
def __initLayout(self):
self.settingLabel.move(36, 30)
self.pivot.move(40, 80)
# self.title_area.move(36, 80)
# self.vBoxLayout.addWidget(self.pivot, 0, Qt.AlignTop)
self.vBoxLayout.addWidget(self.stackedWidget, 0, Qt.AlignmentFlag.AlignTop)
self.vBoxLayout.setContentsMargins(36, 0, 36, 0)
self.PowerGroup.addSettingCard(self.powerPlanCard)
self.PowerGroup.addSettingCard(self.instanceTypeCard)
# self.PowerGroup.addSettingCard(self.calyxGoldenPreferenceCard)
self.PowerGroup.addSettingCard(self.instanceTypeCard)
self.instanceTypeCard.addSettingCards([
self.instanceTeamEnableCard,
self.tpBeforeInstanceEnableCard,
self.useReservedTrailblazePowerEnableCard,
self.useFuelEnableCard,
self.breakDownLevelFourRelicsetEnableCard,
self.mergeImmersifierEnableCard,
self.instanceNameChallengeCountCard
])
self.PowerGroup.addSettingCard(self.instanceNameCard)
self.PowerGroup.addSettingCard(self.borrowEnableCard)
# 将子卡片添加到 borrowEnableCard 的可展开区域
self.borrowEnableCard.addSettingCards([
self.borrowCharacterEnableCard,
self.borrowFriendsCard,
self.borrowScrollTimesCard
])
# self.PowerGroup.addSettingCard(self.maxCalyxPerRoundNumOfAttempts)
self.PowerGroup.addSettingCard(self.buildTargetEnableCard)
self.buildTargetEnableCard.addSettingCards([
self.buildTargetPlanarOrnamentWeeklyCountCard
])
self.PowerGroup.addSettingCard(self.echoofwarEnableCard)
self.echoofwarEnableCard.addSettingCards([
self.echoofwarRunTimeCard
])
# self.PowerGroup.addSettingCard(self.echoofwarStartDayOfWeekCard)
# self.BorrowGroup.addSettingCard(self.borrowCharacterFromCard)
# self.BorrowGroup.addSettingCard(self.borrowCharacterInfoCard)
# self.BorrowGroup.addSettingCard(self.borrowCharacterCard)
self.DailyGroup.addSettingCard(self.dailyEnableCard)
self.dailyEnableCard.addSettingCards([
self.dailyMaterialEnableCard,
# self.dailyHimekoTryEnableCard,
self.dailyMemoryOneEnableCard,
self.dailyMemoryOneTeamCard,
self.lastRunTimeCard
])
self.DailyGroup.addSettingCard(self.activityEnableCard)
self.activityEnableCard.addSettingCards([
self.activityDailyCheckInEnableCard,
self.activityGardenOfPlentyEnableCard,
self.activityRealmOfTheStrangeEnableCard,
self.activityPlanarFissureEnableCard
])
self.DailyGroup.addSettingCard(self.rewardEnableCard)
self.rewardEnableCard.addSettingCards([
self.dispatchEnableCard,
self.mailEnableCard,
self.assistEnableCard,
self.questEnableCard,
self.srpassEnableCard,
self.redemptionEnableCard,
self.achievementEnableCard
])
self.DailyGroup.addSettingCard(self.assetEnableCard)
self.assetEnableCard.addSettingCards(
[
self.lc3StarSuperimposeEnableCard,
]
)
self.CurrencywarsGroup.addSettingCard(self.currencywarsEnableCard)
self.currencywarsEnableCard.addSettingCards([
self.currencywarsRunTimeCard
])
self.CurrencywarsGroup.addSettingCard(self.currencywarsTypeCard)
self.CurrencywarsGroup.addSettingCard(self.currencywarsBonusEnableCard)
self.UniverseGroup.addSettingCard(self.weeklyDivergentEnableCard)
self.weeklyDivergentEnableCard.addSettingCards([
self.weeklyDivergentRunTimeCard
])
self.UniverseGroup.addSettingCard(self.weeklyDivergentTypeCard)
self.UniverseGroup.addSettingCard(self.weeklyDivergentLevelCard)
self.UniverseGroup.addSettingCard(self.weeklyDivergentBonusEnableCard)
self.UniverseGroup.addSettingCard(self.weeklyDivergentStableModeCard)
self.UniverseGroup.addSettingCard(self.universeEnableCard)
self.universeEnableCard.addSettingCards([
self.universeCategoryCard,
self.divergentTypeCard,
self.universeBonusEnableCard,
self.universeFrequencyCard,
self.universeCountCard,
self.universeFateCard,
self.universeDifficultyCard,
self.universeOperationModeCard,
self.universeEnableGpuCard,
self.universeTimeoutCard,
self.universeRunTimeCard,
])
# self.UniverseGroup.addSettingCard(self.divergentTeamTypeCard)
self.FightGroup.addSettingCard(self.fightEnableCard)
self.fightEnableCard.addSettingCards([
self.fightOperationModeCard,
self.fightTimeoutCard,
self.FightRunTimeCard,
])
self.FightGroup.addSettingCard(self.fightTeamEnableCard)
# self.FightGroup.addSettingCard(self.fightTeamNumberCard)
self.FightGroup.addSettingCard(self.fightAllowMapBuyCard)
self.FightGroup.addSettingCard(self.fightAllowSnackBuyCard)
self.FightGroup.addSettingCard(self.fightMainMapCard)
self.ImmortalGameGroup.addSettingCard(self.forgottenhallEnableCard)
self.forgottenhallEnableCard.addSettingCards([
self.forgottenhallLevelCard,
self.forgottenhallTeamsCard,
self.forgottenhallRunTimeCard
])
self.ImmortalGameGroup.addSettingCard(self.purefictionEnableCard)
self.purefictionEnableCard.addSettingCards([
self.purefictionLevelCard,
self.purefictionTeamsCard,
self.purefictionRunTimeCard
])
self.ImmortalGameGroup.addSettingCard(self.ApocalypticEnableCard)
self.ApocalypticEnableCard.addSettingCards([
self.ApocalypticLevelCard,
self.ApocalypticTeamsCard,
self.ApocalypticRunTimeCard
])
self.CloudGameGroup.addSettingCard(self.cloudGameEnableCard)
self.CloudGameGroup.addSettingCard(self.browserTypeCard)
self.browserTypeCard.addSettingCards([
self.browserDownloadUseMirrorCard,
self.browserPersistentCard,
self.browserScaleCard,
self.browserLaunchArgCard
])
self.CloudGameGroup.addSettingCard(self.cloudGameFullScreenCard)
self.CloudGameGroup.addSettingCard(self.browserHeadlessCard)
self.browserHeadlessCard.addSettingCards([self.browserHeadlessRestartCard])
self.CloudGameGroup.addSettingCard(self.cloudGameMaxQueueTimeCard)
# self.CloudGameGroup.addSettingCard(self.cloudGameVideoQualityCard)
# self.CloudGameGroup.addSettingCard(self.cloudGameSmoothFirstCard)
# self.CloudGameGroup.addSettingCard(self.cloudGameShowStatusCard)
# self.CloudGameGroup.addSettingCard(self.browserCookiesCard)
# self.CloudGameGroup.addSettingCard(self.browserPersistentCard)
# self.CloudGameGroup.addSettingCard(self.browserScaleCard)
# self.CloudGameGroup.addSettingCard(self.browserLaunchArgCard)
self.ProgramGroup.addSettingCard(self.logLevelCard)
self.ProgramGroup.addSettingCard(self.gamePathCard)
self.ProgramGroup.addSettingCard(self.updateViaLauncherEnableCard)
self.updateViaLauncherEnableCard.addSettingCards([
self.launcherPathCard,
self.updateGameTimeoutCard
])
self.ProgramGroup.addSettingCard(self.startGameTimeoutCard)
# self.ProgramGroup.addSettingCard(self.importConfigCard)
self.ProgramGroup.addSettingCard(self.pauseAfterSuccess)
self.ProgramGroup.addSettingCard(self.exitAfterFailure)
self.ProgramGroup.addSettingCard(self.afterFinishCard)
self.afterFinishCard.addSettingCards([
self.loopModeCard,
self.scheduledCard,
self.powerLimitCard,
self.refreshHourEnableCard,
self.ScriptPathCard
])
self.ProgramGroup.addSettingCard(self.playAudioCard)
self.ProgramGroup.addSettingCard(self.closeWindowActionCard)
self.NotifyGroup.addSettingCard(self.notifyMasterEnableCard)
self.notifyMasterEnableCard.addSettingCards([
self.testNotifyCard,
self.notifyLevelCard,
self.notifyMergeCard,
self.notifyImageEnableCard,
self.notifyTemplateCard
])
for value in self.notifyEnableGroup:
self.NotifyGroup.addSettingCard(value)
self.MiscGroup.addSettingCard(self.autoBattleDetectEnableCard)
self.MiscGroup.addSettingCard(self.ocrGpuAccelerationCard)
self.MiscGroup.addSettingCard(self.autoSetResolutionEnableCard)
self.MiscGroup.addSettingCard(self.autoSetGamePathEnableCard)
self.MiscGroup.addSettingCard(self.useBackgroundScreenshotCard)
if sys.platform == 'win32':
self.MiscGroup.addSettingCard(self.StartMarch7thAssistantCard)
self.MiscGroup.addSettingCard(self.hotkeyCard)
self.AboutGroup.addSettingCard(self.githubCard)
self.AboutGroup.addSettingCard(self.qqGroupCard)
self.AboutGroup.addSettingCard(self.feedbackCard)
self.AboutGroup.addSettingCard(self.aboutCard)
self.AboutGroup.addSettingCard(self.updateSourceCard)
self.updateSourceCard.addSettingCards([
self.checkUpdateCard,
self.updatePrereleaseEnableCard,
self.updateFullEnableCard
])
self.AboutGroup.addSettingCard(self.mirrorchyanCdkCard)
self.AboutGroup.addSettingCard(self.languageCard)
if sys.platform != 'win32':
self.gamePathCard.setHidden(True)
self.updateViaLauncherEnableCard.setHidden(True)
self.autoSetResolutionEnableCard.setHidden(True)
self.autoSetGamePathEnableCard.setHidden(True)
self.useBackgroundScreenshotCard.setHidden(True)
self.cloudGameEnableCard.setDisabled(True) # 在配置文件中强制启用,禁止用户修改
self.addSubInterface(self.PowerGroup, 'PowerInterface', tr('体力'))
# self.addSubInterface(self.BorrowGroup, 'BorrowInterface', '支援')
self.addSubInterface(self.DailyGroup, 'DailyInterface', tr('日常'))
self.addSubInterface(self.CurrencywarsGroup, 'CurrencywarsInterface', tr('货币战争'))
if sys.platform == 'win32':
self.addSubInterface(self.UniverseGroup, 'UniverseInterface', tr('差分宇宙'))
self.addSubInterface(self.FightGroup, 'FightInterface', tr('锄大地'))
else:
self.UniverseGroup.setHidden(True)
self.FightGroup.setHidden(True)
self.addSubInterface(self.ImmortalGameGroup, 'ImmortalGameInterface', tr('逐光捡金'))
self.pivot.addItem(
routeKey='verticalBar',
text="|",
onClick=lambda: self.pivot.setCurrentItem(self.stackedWidget.currentWidget().objectName()),
)
self.addSubInterface(self.ProgramGroup, 'programInterface', tr('程序'))
self.addSubInterface(self.CloudGameGroup, "cloudGameInterface", tr('云游戏'))
self.addSubInterface(self.NotifyGroup, 'NotifyInterface', tr('推送'))
self.addSubInterface(self.MiscGroup, 'KeybindingInterface', tr('杂项'))
if sys.platform == 'win32':
self.addSubInterface(
accounts_interface(self.tr, self.scrollWidget),
'AccountsInterface',
tr('账号')
)
self.addSubInterface(self.AboutGroup, 'AboutInterface', tr('关于'))
self.stackedWidget.currentChanged.connect(self.onCurrentIndexChanged)
self.pivot.setCurrentItem(self.stackedWidget.currentWidget().objectName())
self.stackedWidget.setFixedHeight(self.stackedWidget.currentWidget().sizeHint().height())
def __connectSignalToSlot(self):
# self.importConfigCard.clicked.connect(self.__onImportConfigCardClicked)
self.gamePathCard.clicked.connect(self.__onGamePathCardClicked)
self.launcherPathCard.clicked.connect(self.__onLauncherPathCardClicked)
self.ScriptPathCard.clicked.connect(self.__onScriptPathCardClicked)
# self.borrowCharacterInfoCard.clicked.connect(self.__openCharacterFolder())
self.testNotifyCard.clicked.connect(lambda: start_task("notify"))
self.notifyMasterEnableCard.switchChanged.connect(self.__refreshNotifiers)
self.afterFinishCard.expandStateChanged.connect(self.__onExpandableCardStateChanged)
self.githubCard.clicked.connect(self.__openUrl("https://github.com/moesnow/March7thAssistant"))
self.qqGroupCard.clicked.connect(self.__openUrl("https://qm.qq.com/q/C3IryUWCQw"))
self.feedbackCard.clicked.connect(self.__openUrl("https://github.com/moesnow/March7thAssistant/issues"))
self.aboutCard.clicked.connect(lambda: checkUpdate(self.parent))
# 连接可展开卡片的展开状态改变信号,在动画前调整 stackedWidget 高度
self.borrowEnableCard.expandStateChanged.connect(self.__onExpandableCardStateChanged)
self.buildTargetEnableCard.expandStateChanged.connect(self.__onExpandableCardStateChanged)
self.dailyEnableCard.expandStateChanged.connect(self.__onExpandableCardStateChanged)
self.activityEnableCard.expandStateChanged.connect(self.__onExpandableCardStateChanged)
self.rewardEnableCard.expandStateChanged.connect(self.__onExpandableCardStateChanged)
self.assetEnableCard.expandStateChanged.connect(self.__onExpandableCardStateChanged)
self.currencywarsEnableCard.expandStateChanged.connect(self.__onExpandableCardStateChanged)
self.fightEnableCard.expandStateChanged.connect(self.__onExpandableCardStateChanged)
self.weeklyDivergentEnableCard.expandStateChanged.connect(self.__onExpandableCardStateChanged)
self.universeEnableCard.expandStateChanged.connect(self.__onExpandableCardStateChanged)
self.forgottenhallEnableCard.expandStateChanged.connect(self.__onExpandableCardStateChanged)
self.purefictionEnableCard.expandStateChanged.connect(self.__onExpandableCardStateChanged)
self.ApocalypticEnableCard.expandStateChanged.connect(self.__onExpandableCardStateChanged)
self.updateViaLauncherEnableCard.expandStateChanged.connect(self.__onExpandableCardStateChanged)
self.updateSourceCard.expandStateChanged.connect(self.__onExpandableCardStateChanged)
self.notifyMasterEnableCard.expandStateChanged.connect(self.__onExpandableCardStateChanged)
for notify_card in self.notifyEnableGroup:
if hasattr(notify_card, "expandStateChanged"):
notify_card.expandStateChanged.connect(self.__onExpandableCardStateChanged)
self.instanceTypeCard.expandStateChanged.connect(self.__onExpandableCardStateChanged)
self.echoofwarEnableCard.expandStateChanged.connect(self.__onExpandableCardStateChanged)
self.browserTypeCard.expandStateChanged.connect(self.__onExpandableCardStateChanged)
self.browserHeadlessCard.expandStateChanged.connect(self.__onExpandableCardStateChanged)
def __getNotifyProviderNames(self):
provider_names = []
for key in cfg.config.keys():
if key.startswith("notify_") and key.endswith("_enable"):
notifier_name = key[len("notify_"):-len("_enable")]
if sys.platform != 'win32' and notifier_name == 'winotify':
continue
provider_names.append(notifier_name)
order_map = {name: index for index, name in enumerate(self.notifyProviderMeta.keys())}
return sorted(provider_names, key=lambda name: (order_map.get(name, 999), name))
def __createNotifyParamCards(self, notifier_name):
param_cards = []
prefix = f"notify_{notifier_name}_"
enable_key = f"notify_{notifier_name}_enable"
for key in cfg.config.keys():
if not key.startswith(prefix) or key == enable_key:
continue
param_name = key[len(prefix):]
param_meta = self.notifyProviderMeta.get(notifier_name, {}).get("params", {}).get(param_name, {})
if "description" in param_meta:
param_description = param_meta.get("description", "")
elif param_meta:
param_description = ""
else:
param_description = tr("该参数用于配置该通知方式的请求字段")
param_title = param_meta.get("title", param_name)
param_type = param_meta.get("type", "text")
if param_type == "bool":
# self.__normalizeNotifyBoolConfigValue(key)
notify_param_card = SwitchSettingCard1(
FIF.CHECKBOX,
param_title,
param_description,
key,
self
)
notify_param_card.switchButton.checkedChanged.connect(self.__refreshNotifiers)
else:
notify_param_card = CustomPushSettingCard(
tr('修改'),
FIF.EDIT,
param_title,
key,
param_description,
self
)
notify_param_card.button.clicked.connect(
lambda _, card=notify_param_card: self.__onNotifyParamCardClicked(card)
)
param_cards.append(notify_param_card)
return param_cards
def __onNotifyParamCardClicked(self, card):
current_value = cfg.get_value(card.configname)
message_box = MessageBoxEdit(card.title, str(current_value), self.window())
if message_box.exec():
cfg.set_value(card.configname, self.__parseNotifyValue(message_box.getText()))
self.__refreshNotifiers()
def __parseNotifyValue(self, input_text):
try:
return eval(input_text)
except (SyntaxError, NameError, ValueError):
return input_text
def __normalizeNotifyBoolConfigValue(self, configname):
value = cfg.get_value(configname)
if isinstance(value, bool):
return
normalized = False
if isinstance(value, str):
text = value.strip().lower()
if text in {"1", "true", "yes", "on"}:
normalized = True
elif text in {"0", "false", "no", "off", "", "none", "null"}:
normalized = False
else:
normalized = bool(text)
else:
normalized = bool(value)
cfg.set_value(configname, normalized)
def __refreshNotifiers(self, *_):
try:
init_notifiers()
except Exception:
pass
def addSubInterface(self, widget: QLabel, objectName, text):
def remove_spacing(layout):
for i in range(layout.count()):
item = layout.itemAt(i)
if isinstance(item, QSpacerItem):
layout.removeItem(item)
break
remove_spacing(widget.vBoxLayout)
widget.titleLabel.setHidden(True)
widget.setObjectName(objectName)
self.stackedWidget.addWidget(widget)
self.pivot.addItem(
routeKey=objectName,
text=text,
onClick=lambda: self.stackedWidget.setCurrentWidget(widget)
)
def onCurrentIndexChanged(self, index):
widget = self.stackedWidget.widget(index)
self.pivot.setCurrentItem(widget.objectName())
self.verticalScrollBar().setValue(0)
self.stackedWidget.setFixedHeight(self.stackedWidget.currentWidget().sizeHint().height())
# def __onImportConfigCardClicked(self):
# configdir, _ = QFileDialog.getOpenFileName(self, "选取配置文件", "./", "Config Files (*.yaml)")
# if (configdir != ""):
# cfg._load_config(configdir)
# cfg.save_config()
# self.__showRestartTooltip()
def __onGamePathCardClicked(self):
game_path, _ = QFileDialog.getOpenFileName(
self,
tr("选择游戏路径"),
"",
tr("脚本或可执行文件 (*.exe *.bat *.cmd *.ps1)")
)
if not game_path or cfg.game_path == game_path:
return
cfg.set_value("game_path", game_path)
self.gamePathCard.setContent(game_path)
def __onLauncherPathCardClicked(self):
launcher_path, _ = QFileDialog.getOpenFileName(
self,
tr("选择米哈游启动器路径"),
"",
tr("脚本或可执行文件 (*.exe *.bat *.cmd *.ps1)")
)
if not launcher_path or cfg.launcher_path == launcher_path:
return
cfg.set_value("launcher_path", launcher_path)
self.launcherPathCard.setContent(launcher_path)
# def __openCharacterFolder(self):
# return lambda: os.startfile(os.path.abspath("./assets/images/share/character"))
def __openUrl(self, url):
return lambda: QDesktopServices.openUrl(QUrl(url))
# def __showRestartTooltip(self):
# InfoBar.success(
# '更新成功',
# '配置在重启软件后生效',
# duration=1500,
# parent=self
# )
def __onScriptPathCardClicked(self):
script_path, _ = QFileDialog.getOpenFileName(
self,
tr("脚本或程序路径"),
"",
tr("脚本或可执行文件 (*.exe *.bat *.cmd *.ps1)")
)
if not script_path or cfg.script_path == script_path:
return
cfg.set_value("script_path", script_path)
self.ScriptPathCard.setContent(script_path)
def __onExpandableCardStateChanged(self, is_expanding: bool):
"""可展开卡片状态改变时,调整 stackedWidget 高度以包含子卡片"""
# 获取发送信号的卡片对象
sender_card = self.sender()
# 根据展开的卡片获取其 viewLayout 的高度
if sender_card:
card_weight = sender_card.viewLayout.sizeHint().height()
else:
# 如果无法获取发送者,使用默认高度(向后兼容)
card_weight = 0
# 在动画执行前调整 stackedWidget 高度
if is_expanding:
self.stackedWidget.setFixedHeight(self.stackedWidget.currentWidget().sizeHint().height() + card_weight)
else:
self.stackedWidget.setFixedHeight(self.stackedWidget.currentWidget().sizeHint().height())