def sell_card(targetQQ: str, cards_to_send: List[str]) -> str:
    cards_to_send = [
        name for name in cards_to_send if name != CARD_PLACEHOLDER
    ]
    original_cards = [*cards_to_send]

    # 读取配置信息
    load_config("config.toml", "config.toml.local")
    cfg = config()

    # 12.30 送卡片次数(re:好像送给别人没有上限?)
    indexes = list(range(len(cfg.account_configs), 0, -1))

    card_info_map = parse_card_group_info_map(zzconfig())
    for name in cards_to_send:
        if name not in card_info_map:
            return f"{name}不是本期卡片名称,有效的卡片名称为: {list(card_info_map.keys())}"

    success_send_list = []

    for idx in indexes:  # 从1开始,第i个
        account_config = cfg.account_configs[idx - 1]
        show_head_line(f"开始处理第{idx}个账户[{account_config.name}]",
                       color("fg_bold_yellow"))

        djcHelper = DjcHelper(account_config, cfg.common)
        lr = djcHelper.fetch_pskey()
        djcHelper.check_skey_expired()
        djcHelper.get_bind_role_list()

        remaining_cards = []
        for name in cards_to_send:
            res = djcHelper.send_card_by_name(name, targetQQ)
            retCode = int(res["13333"]["ret"])
            if retCode == 0:
                success_send_list.append(name)
            else:
                remaining_cards.append(name)

                if len(original_cards) == 1:
                    if retCode == 10017:
                        return "该账号今日已被赠送过四次"

        cards_to_send = remaining_cards
        if len(cards_to_send) == 0:
            break

    msg = ""
    if len(success_send_list) != 0:
        msg += f"\n成功发送以下卡片:{success_send_list}"
    if len(cards_to_send) != 0:
        msg += f"\n无法发送以下卡片:{cards_to_send},是否已达到赠送上限或者这个卡卖完了?"
    if len(success_send_list) != 0:
        msg += f"\n请使用手机打开集卡页面确认是否到账~ 若到账请按1元每张的价格主动扫码转账哦~(不自觉的坏孩子会被tjjtds哦<_<)"
    msg += "\n"

    return msg
def init_venv_and_requirements(venv_path=".venv",
                               requirements_path="requirements.txt",
                               disable_douban=False,
                               enable_proxy=False):
    if not enable_proxy:
        logger.info("当前已无视系统代理")
        bypass_proxy()

    # 初始化相关路径变量
    pyscript_path = os.path.join(venv_path, "Scripts")
    py_path = os.path.join(pyscript_path, "python")
    pip_path = os.path.join(pyscript_path, "pip")

    show_head_line(f"尝试初始化venv环境", color("bold_yellow"))

    subprocess.call([
        "python",
        "-m",
        "venv",
        venv_path,
    ])

    logger.info("尝试更新pip setuptools wheel")
    douban_op = ["-i", "https://pypi.doubanio.com/simple"]
    if disable_douban:
        douban_op = []
    subprocess.call([
        py_path,
        "-m",
        "pip",
        "install",
        *douban_op,
        "--upgrade",
        "pip",
        "setuptools",
        "wheel",
    ])

    logger.info("尝试安装依赖库和pyinstaller")
    subprocess.call([
        pip_path,
        "install",
        *douban_op,
        "-r",
        requirements_path,
        "--upgrade",
        "wheel",
        "pyinstaller",
    ])

    logger.info("安装pywin32_postinstall")
    subprocess.call([
        py_path,
        os.path.join(pyscript_path, "pywin32_postinstall.py"),
        "-install",
    ])
Exemple #3
0
def clear_github_artifact(dir_all_release, dir_github_action_artifact):
    old_cwd = os.getcwd()

    show_head_line("清空旧版本github artifact目录", color("bold_yellow"))

    if not os.path.isdir(dir_all_release):
        os.mkdir(dir_all_release)

    os.chdir(dir_all_release)

    shutil.rmtree(dir_github_action_artifact, ignore_errors=True)
    os.mkdir(dir_github_action_artifact)

    os.chdir(old_cwd)
Exemple #4
0
def show_usage():
    show_head_line("从2020-10-26至今小助手使用情况概览", color("fg_bold_yellow"))

    last_n_days = get_last_n_days(14)
    extra_time_periods = [*time_periods, *last_n_days]
    extra_time_periods_desc = [*time_periods_desc, *last_n_days]

    heads = ["计数对象", *extra_time_periods_desc]
    colSizes = [20, *[8 for _ in extra_time_periods_desc]]
    rows = [
        [
            "本机使用次数", *[
                get_count(my_usage_counter_name, period)
                for period in extra_time_periods
            ]
        ],
        # ["当前版本总计使用数", *[get_count(this_version_global_usage_counter_name, period) for period in extra_time_periods]],
        # ["所有版本总计使用数", *[get_count(global_usage_counter_name, period) for period in extra_time_periods]],
        # ["当前版本活跃用户数", *[get_record_count_name_start_with(this_version_user_usage_prefix, period) for period in extra_time_periods]],
        [
            "活跃用户数",
            *[
                get_record_count_name_start_with(
                    user_usage_counter_name_prefix, period)
                for period in extra_time_periods
            ],
        ],
        # ["DLC用户数", *[get_record_count_name_start_with(auto_updater_usage_counter_name_prefix, period) for period in extra_time_periods]],
        [
            "按月付费用户数",
            *[
                get_record_count_name_start_with(
                    active_monthly_pay_user_usage_counter_name_prefix, period)
                for period in extra_time_periods
            ],
        ],
    ]

    logger.info(tableify(heads, colSizes))
    for row in rows:
        logger.info(color("fg_bold_cyan") + tableify(row, colSizes))
Exemple #5
0
prompt = f"如需直接使用默认版本号:{now_version} 请直接按回车\n或手动输入版本号后按回车:"
version = input(prompt) or now_version

version_reg = r"\d+\.\d+\.\d+"

if re.match(version_reg, version) is None:
    logger.info(f"版本号格式有误,正确的格式类似:1.0.0 ,而不是 {version}")
    exit(-1)

# 最大化窗口
change_console_window_mode_async(disable_min_console=True)

version = 'v' + version

run_start_time = datetime.now()
show_head_line(f"开始发布版本 {version}", color("bold_yellow"))

set_title_cmd = f"title 发布 {version}"
os.system(set_title_cmd)

# 先声明一些需要用到的目录的地址
dir_src = os.path.realpath('.')
dir_all_release = os.path.realpath(os.path.join("releases"))
release_dir_name = f"DNF蚊子腿小助手_{version}_by风之凌殇"
release_7z_name = f'{release_dir_name}.7z'
dir_github_action_artifact = "_github_action_artifact"

# ---------------构建
# 调用构建脚本
os.chdir(dir_src)
build()
Exemple #6
0
from config import load_config, config
from djc_helper import DjcHelper
from log import color
from util import show_head_line

if __name__ == '__main__':
    # 读取配置信息
    load_config("config.toml", "config.toml.local")
    cfg = config()

    # 12.30 送卡片次数(re:好像送给别人没有上限?)
    indexes = [4]

    for idx in indexes:  # 从1开始,第i个
        account_config = cfg.account_configs[idx - 1]
        show_head_line("开始处理第{}个账户[{}]".format(idx, account_config.name),
                       color("fg_bold_yellow"))

        djcHelper = DjcHelper(account_config, cfg.common)
        djcHelper.check_skey_expired()
        djcHelper.get_bind_role_list()

        lr = djcHelper.fetch_pskey()

        # re: 先填QQ
        # undone: 然后填写卡片
        targetQQ = "XXXXXXXXXXX"
        cards_to_send = [
            ("XXXXXXXXXXX", 1),
            ("XXXXXXXXXXX", 1),
            ("XXXXXXXXXXX", 1),
            ("XXXXXXXXXXX", 1),
Exemple #7
0
def release():
    # ---------------准备工作
    prompt = f"如需直接使用默认版本号:{now_version} 请直接按回车\n或手动输入版本号后按回车:"
    version = input(prompt) or now_version

    version_reg = r"\d+\.\d+\.\d+"

    if re.match(version_reg, version) is None:
        logger.info(f"版本号格式有误,正确的格式类似:1.0.0 ,而不是 {version}")
        pause_and_exit(-1)

    # 最大化窗口
    change_console_window_mode_async(disable_min_console=True)

    version = "v" + version

    run_start_time = datetime.now()
    show_head_line(f"开始发布版本 {version}", color("bold_yellow"))

    set_title_cmd = f"title 发布 {version}"
    os.system(set_title_cmd)

    # 先声明一些需要用到的目录的地址
    dir_src = os.path.realpath(".")
    dir_all_release = os.path.realpath(os.path.join("releases"))
    release_dir_name = f"DNF蚊子腿小助手_{version}_by风之凌殇"
    release_7z_name = f"{release_dir_name}.7z"
    dir_github_action_artifact = "_github_action_artifact"

    # ---------------构建
    # 调用构建脚本
    os.chdir(dir_src)
    build()

    # ---------------清除一些历史数据
    make_sure_dir_exists(dir_all_release)
    os.chdir(dir_all_release)
    clear_github_artifact(dir_all_release, dir_github_action_artifact)

    # ---------------打包
    os.chdir(dir_src)
    package(dir_src, dir_all_release, release_dir_name, release_7z_name, dir_github_action_artifact)

    # ---------------构建增量补丁
    create_patch_for_latest_n_version = 3

    # ---------------构建增量包
    os.chdir(dir_all_release)
    show_head_line(f"开始构建增量包,最多包含过去{create_patch_for_latest_n_version}个版本到最新版本的补丁", color("bold_yellow"))
    create_patch(dir_src, dir_all_release, create_patch_for_latest_n_version, dir_github_action_artifact)

    # ---------------获取补丁地址(分开方便调试)
    os.chdir(dir_all_release)
    patch_file_name = create_patch(
        dir_src,
        dir_all_release,
        create_patch_for_latest_n_version,
        dir_github_action_artifact,
        get_final_patch_path_only=True,
    )

    # ---------------标记新版本
    show_head_line("提交版本和版本变更说明,并同步到docs目录,用于生成github pages", color("bold_yellow"))
    os.chdir(dir_src)
    commit_new_version()

    # ---------------上传到蓝奏云
    show_head_line("开始上传到蓝奏云", color("bold_yellow"))
    os.chdir(dir_src)
    with open("upload_cookie.json") as fp:
        cookie = json.load(fp)
    os.chdir(dir_all_release)
    uploader = Uploader()
    uploader.login(cookie)
    if uploader.login_ok:
        logger.info("蓝奏云登录成功,开始上传压缩包")

        def path_in_src(filepath_relative_to_src: str) -> str:
            return os.path.realpath(os.path.join(dir_src, filepath_relative_to_src))

        realpath = os.path.realpath

        upload_info_list = [
            (
                uploader.folder_djc_helper,
                [
                    (realpath(release_7z_name), uploader.history_version_prefix),
                    (path_in_src("utils/auto_updater.exe"), ""),
                    (path_in_src("使用教程/使用文档.docx"), ""),
                    (path_in_src("使用教程/视频教程.txt"), ""),
                    (path_in_src("付费指引/付费指引.docx"), ""),
                    (path_in_src("utils/不要下载增量更新文件_这个是给自动更新工具使用的.txt"), ""),
                    (realpath(patch_file_name), uploader.history_patches_prefix),
                ],
            ),
            (
                uploader.folder_dnf_calc,
                [
                    (realpath(release_7z_name), uploader.history_version_prefix),
                ],
            ),
        ]

        logger.info(color("bold_green") + "具体上传列表如下:")
        for upload_folder, upload_list in upload_info_list:
            logger.info(color("bold_cyan") + f"\t{upload_folder.name}:")
            for local_filepath, _history_file_prefix in upload_list:
                logger.info(f"\t\t{local_filepath}")

            logger.info("\n")

        for upload_folder, upload_list in upload_info_list:
            for local_filepath, history_file_prefix in reversed(upload_list):
                # 逆序遍历,确保同一个网盘目录中,列在前面的最后才上传,从而在网盘显示时显示在最前方
                total_try_count = 1
                for try_index in range_from_one(total_try_count):
                    upload_ok = uploader.upload_to_lanzouyun(
                        local_filepath, upload_folder, history_file_prefix=history_file_prefix
                    )
                    if upload_ok:
                        break

                    logger.warning(f"第{try_index}/{total_try_count}次尝试上传{local_filepath}失败,等待一会后重试")
                    if try_index < total_try_count:
                        count_down("上传到网盘", 5 * try_index)

    else:
        logger.error("蓝奏云登录失败")

    # ---------------推送版本到github
    # 打包完成后git添加标签
    os.chdir(dir_src)
    show_head_line("开始推送到github", color("bold_yellow"))
    push_github(version)

    # ---------------结束
    logger.info("+" * 40)
    logger.info(color("bold_yellow") + f"{version} 发布完成,共用时{datetime.now() - run_start_time},请检查上传至蓝奏云流程是否OK")
    logger.info("+" * 40)

    os.system("PAUSE")
Exemple #8
0
def build(disable_douban=False):
    # 初始化相关路径变量
    venv_path = ".venv"
    pyinstaller_path = os.path.join(venv_path, "Scripts", "pyinstaller")

    # 初始化venv和依赖
    init_venv_and_requirements(".venv", disable_douban)

    show_head_line(f"将使用.venv环境进行编译", color("bold_yellow"))

    build_configs = [
        ("main.py", "DNF蚊子腿小助手.exe", "utils/icons/DNF蚊子腿小助手.ico", ".",
         ["PyQt5"], []),
        ("auto_updater.py", "auto_updater.exe", "", "utils", ["PyQt5"], []),
        ("ark_lottery_special_version.py", "DNF蚊子腿小助手_集卡特别版.exe",
         "utils/icons/ark_lottery_special_version.ico", ".", ["PyQt5"], []),
        ("config_ui.py", "DNF蚊子腿小助手配置工具.exe", "utils/icons/config_ui.ico", ".",
         [], ["--noconsole"]),
    ]

    for idx, config in enumerate(build_configs):
        prefix = f"{idx + 1}/{len(build_configs)}"

        src_path, exe_name, icon_path, target_dir, exclude_modules, extra_args = config
        logger.info(color("bold_yellow") + f"{prefix} 开始编译 {exe_name}")

        cmd_build = [
            pyinstaller_path,
            '--name',
            exe_name,
            '-F',
            src_path,
        ]
        if icon_path != "":
            cmd_build.extend(['--icon', icon_path])
        for module in exclude_modules:
            cmd_build.extend(['--exclude-module', module])
        cmd_build.extend(extra_args)

        logger.info(f"{prefix} 开始编译 {exe_name},命令为:{' '.join(cmd_build)}")
        subprocess.call(cmd_build)

        logger.info(f"编译结束,进行善后操作")

        # 复制二进制
        logger.info(f"复制{exe_name}到目标目录{target_dir}")
        if not os.path.isdir(target_dir):
            os.mkdir(target_dir)
        target_path = os.path.join(target_dir, exe_name)
        shutil.copyfile(os.path.join("dist", exe_name), target_path)

        # 删除临时文件
        logger.info("删除临时文件")
        for directory in ["build", "dist", "__pycache__"]:
            shutil.rmtree(directory, ignore_errors=True)
        os.remove(f"{exe_name}.spec")

        filesize = os.path.getsize(target_path)
        logger.info(
            color("bold_green") +
            f"{prefix} 编译{exe_name}结束,最终大小为{human_readable_size(filesize)}")

    logger.info("done")
Exemple #9
0
def package(dir_src, dir_all_release, release_dir_name, release_7z_name, dir_github_action_artifact):
    old_cwd = os.getcwd()

    show_head_line(f"开始打包 {release_dir_name} 所需内容", color("bold_yellow"))

    # 确保发布根目录存在
    if not os.path.isdir(dir_all_release):
        os.mkdir(dir_all_release)
    # 并清空当前的发布版本目录
    dir_current_release = os.path.realpath(os.path.join(dir_all_release, release_dir_name))
    shutil.rmtree(dir_current_release, ignore_errors=True)
    os.mkdir(dir_current_release)

    logger.info(color("bold_yellow") + f"将部分内容从 {dir_src} 复制到 {dir_current_release} ")
    # 需要复制的文件与目录
    files_to_copy = []
    # 基于正则确定初始复制范围
    reg_wantted_file = r'.*\.(toml|md|txt|png|jpg|docx|url)$'
    for file in os.listdir('.'):
        if not re.search(reg_wantted_file, file, flags=re.IGNORECASE):
            continue
        files_to_copy.append(file)
    # 额外补充一些文件和目录
    files_to_copy.extend([
        "config.example.toml",
        "DNF蚊子腿小助手.exe",
        "DNF蚊子腿小助手配置工具.exe",
        "DNF蚊子腿小助手配置文件.bat",

        "使用教程",
        "付费指引",
        "相关信息",
        "utils",
    ])
    # 按顺序复制
    files_to_copy = sorted(files_to_copy)
    # 复制文件与目录过去
    for filename in files_to_copy:
        source = os.path.join(dir_src, filename)
        destination = os.path.join(dir_current_release, filename)
        if os.path.isdir(filename):
            logger.info(f"拷贝目录 {filename}")
            shutil.copytree(source, destination)
        else:
            logger.info(f"拷贝文件 {filename}")
            shutil.copyfile(source, destination)

    logger.info(color("bold_yellow") + "移动部分文件的位置和名称")
    files_to_move = [
        ("utils/auto_updater.exe", "utils/auto_updater_latest.exe"),
        ("CHANGELOG.MD", "相关信息/CHANGELOG.MD"),
        ("README.MD", "相关信息/README.MD"),
    ]
    for src_file, dst_file in files_to_move:
        src_file = os.path.join(dir_current_release, src_file)
        dst_file = os.path.join(dir_current_release, dst_file)

        logger.info(f"移动{src_file}到{dst_file}")
        shutil.move(src_file, dst_file)

    logger.info(color("bold_yellow") + "清除一些无需发布的内容")
    dir_to_filenames_need_remove = {
        ".": [
            *list(path.name for path in pathlib.Path(".").glob('requirements*.txt')),

            "config.toml.local",
            *list(path.name for path in pathlib.Path(".").glob('config.toml.github_action*')),
        ],
        "utils": [
            "logs", ".db", ".cached", ".first_run", ".log.filename",
            "buy_auto_updater_users.txt", "user_monthly_pay_info.txt", "notices.txt",

            *list(path.name for path in pathlib.Path("utils").glob('chrome_portable_*')),

            "upx.exe",
        ],
    }
    for dir_path, filenames in dir_to_filenames_need_remove.items():
        for filename in filenames:
            filepath = os.path.join(dir_current_release, f"{dir_path}/{filename}")
            if not os.path.exists(filepath):
                continue

            if os.path.isdir(filepath):
                logger.info(f"移除目录 {filepath}")
                shutil.rmtree(filepath, ignore_errors=True)
            else:
                logger.info(f"移除文件 {filepath}")
                os.remove(filepath)

    # 压缩打包
    os.chdir(dir_all_release)
    logger.info(color("bold_yellow") + "开始压缩打包")
    compress_dir_with_bandizip(release_dir_name, release_7z_name, dir_src)

    # 额外备份一份最新的供github action 使用
    shutil.copyfile(release_7z_name, os.path.join(dir_github_action_artifact, 'djc_helper.7z'))

    os.chdir(old_cwd)
Exemple #10
0
def sell_card(targetQQ: str, cards_to_send: List[str]) -> str:
    cards_to_send = [name for name in cards_to_send if name != CARD_PLACEHOLDER]
    original_cards = [*cards_to_send]

    # 读取配置信息
    cfg = config()

    # 12.30 送卡片次数(re:好像送给别人没有上限?)
    indexes = list(range(len(cfg.account_configs), 0, -1))

    if not is_new_version_ark_lottery():
        card_info_map = parse_card_group_info_map(zzconfig())
        for name in cards_to_send:
            if name not in card_info_map:
                return f"{name}不是本期卡片名称,有效的卡片名称为: {list(card_info_map.keys())}"

    success_send_list = []

    for idx in indexes:  # 从1开始,第i个
        account_config = cfg.account_configs[idx - 1]
        show_head_line(f"开始处理第{idx}个账户[{account_config.name}]", color("fg_bold_yellow"))
        if not account_config.function_switches.get_ark_lottery or not account_config.is_enabled():
            continue

        djcHelper = DjcHelper(account_config, cfg.common)
        djcHelper.fetch_pskey()
        djcHelper.check_skey_expired()
        djcHelper.get_bind_role_list()

        remaining_cards = []
        for name in cards_to_send:
            send_ok = False

            if is_new_version_ark_lottery():
                send_ok = djcHelper.dnf_ark_lottery_send_card(name, targetQQ)
            else:
                res = djcHelper.send_card_by_name(name, targetQQ)
                retCode = int(res["13333"]["ret"])

                if retCode == 0:
                    send_ok = True
                else:
                    if len(original_cards) == 1:
                        if retCode == 10017:
                            return "该账号今日已被赠送过四次"

            if send_ok:
                success_send_list.append(name)
            else:
                remaining_cards.append(name)

        cards_to_send = remaining_cards
        if len(cards_to_send) == 0:
            break

    msg = ""
    if len(success_send_list) != 0:
        msg += f"\n成功发送以下卡片:{success_send_list}"
    if len(cards_to_send) != 0:
        msg += f"\n无法发送以下卡片:{cards_to_send},是否已达到赠送上限或者这个卡卖完了?"
    if len(success_send_list) != 0:
        msg += "\n请使用手机打开集卡页面确认是否到账~ 若到账请按1元每张的价格主动扫码转账哦~(不定期我会核查的,如果买了不付款的话就加入本工具黑名单~)"
    msg += "\n"

    return msg
Exemple #11
0
from config import load_config, config
from djc_helper import DjcHelper
from log import color
from util import show_head_line

if __name__ == '__main__':
    # 读取配置信息
    load_config("config.toml", "config.toml.local")
    cfg = config()

    # 12.30 送卡片次数(re:好像送给别人没有上限?)
    indexes = [4]

    for idx in indexes:  # 从1开始,第i个
        account_config = cfg.account_configs[idx - 1]
        show_head_line(f"开始处理第{idx}个账户[{account_config.name}]",
                       color("fg_bold_yellow"))

        djcHelper = DjcHelper(account_config, cfg.common)
        lr = djcHelper.fetch_pskey()
        djcHelper.check_skey_expired()
        djcHelper.get_bind_role_list()

        # re: 先填QQ undone: 然后填写卡片
        targetQQ = "XXXXXXXXXXX"
        cards_to_send = [
            ("XXXXXXXXXXX", 1),
            ("XXXXXXXXXXX", 1),
            ("XXXXXXXXXXX", 1),
            ("XXXXXXXXXXX", 1),
        ]
        for name, count in cards_to_send:
Exemple #12
0
def main():
    increase_counter(name="run/begin", ga_type=ga.GA_REPORT_TYPE_PAGE_VIEW)

    prepare_env()

    # 启动时检查是否需要同步本机数据目录备份的旧版本配置
    try_load_old_version_configs_from_user_data_dir()

    change_title()

    print_update_message_on_first_run_new_version()

    logger.warning(
        f"开始运行DNF蚊子腿小助手,ver={now_version} {ver_time},powered by {author}")
    logger.warning(
        color("fg_bold_cyan") +
        "如果觉得我的小工具对你有所帮助,想要支持一下我的话,可以帮忙宣传一下或打开付费指引/支持一下.png,扫码打赏哦~")

    # 读取配置信息
    load_config("config.toml", "config.toml.local")
    cfg = config()

    if len(cfg.account_configs) == 0:
        raise Exception("未找到有效的账号配置,请检查是否正确配置。ps:多账号版本配置与旧版本不匹配,请重新配置")

    notify_manual_check_update_on_release_too_long(cfg.common)

    check_proxy(cfg)

    try_report_usage_info(cfg)

    if cfg.common.disable_cmd_quick_edit:
        disable_quick_edit_mode()

    show_notices()

    if cfg.common.allow_only_one_instance:
        logger.info("当前仅允许单个实例运行,将尝试干掉其他实例~")
        async_call(kill_other_instance_on_start)
    else:
        logger.info("当前允许多个实例同时运行~")

    init_pool(cfg.get_pool_size())

    change_title(multiprocessing_pool_size=cfg.get_pool_size(),
                 enable_super_fast_mode=cfg.common.enable_super_fast_mode)

    show_multiprocessing_info(cfg)

    account_names = []
    for account_cfg in cfg.account_configs:
        account_names.append(account_cfg.name)

    logger.info(f"当前共配置{len(account_names)}个账号,具体如下:{account_names}")

    clean_dir_to_size(log_directory, cfg.common.max_logs_size * MiB,
                      cfg.common.keep_logs_size * MiB)
    clean_dir_to_size(f"utils/{log_directory}", cfg.common.max_logs_size * MiB,
                      cfg.common.keep_logs_size * MiB)

    show_ask_message_box(cfg)

    check_all_skey_and_pskey(cfg)

    check_djc_role_binding()

    # 确保道聚城绑定OK后在活动运行同时进行异步的弹窗提示
    check_first_run_async(cfg)

    # 挪到所有账号都登陆后再尝试自动更新,从而能够判定是否已购买DLC
    try_auto_update(cfg)

    # 检查是否有更新,用于提示未购买自动更新的朋友去手动更新~
    if cfg.common.check_update_on_start:
        check_update(cfg)

    # 查询付费信息供后面使用
    show_head_line("查询付费信息")
    logger.warning("开始查询付费信息,请稍候~")
    user_buy_info = get_user_buy_info(cfg.get_qq_accounts())
    show_buy_info(user_buy_info, cfg, need_show_message_box=False)

    sas(cfg, "启动时展示账号概览", user_buy_info)

    # 预先尝试创建和加入固定队伍,从而每周第一次操作的心悦任务也能加到队伍积分中
    try_join_xinyue_team(cfg, user_buy_info)

    # 正式进行流程
    run(cfg, user_buy_info)

    # 尝试领取心悦组队奖励
    try_take_xinyue_team_award(cfg, user_buy_info)

    # # 尝试派赛利亚出去打工
    # try_xinyue_sailiyam_start_work(cfg)

    # 活动开启关闭时调这个开关即可
    enable_card_lottery = False

    if enable_card_lottery:
        auto_send_cards(cfg)

    show_extra_infos(cfg)
    sas(cfg, "运行完毕展示账号概览", user_buy_info)

    if enable_card_lottery:
        show_lottery_status("卡片赠送完毕后展示各账号抽卡卡片以及各礼包剩余可领取信息",
                            cfg,
                            need_show_tips=True)

    show_pay_info(cfg)

    # 显示小助手的使用概览
    if cfg.common._show_usage:
        show_usage()

    # 运行结束展示下多进程信息
    show_multiprocessing_info(cfg)

    # 检查是否有更新,用于提示未购买自动更新的朋友去手动更新~
    if cfg.common.check_update_on_end:
        check_update(cfg)

    # 运行完毕备份配置到本机数据目录
    try_save_configs_to_user_data_dir()

    increase_counter(name="run/end", ga_type=ga.GA_REPORT_TYPE_PAGE_VIEW)

    show_head_line("运行完毕")
Exemple #13
0
def build(disable_douban=False, enable_proxy=False, use_upx=True):
    # 初始化相关路径变量
    venv_path = ".venv"
    pyinstaller_path = os.path.join(venv_path, "Scripts", "pyinstaller")

    # 初始化venv和依赖
    init_venv_and_requirements(".venv", "requirements.txt", disable_douban,
                               enable_proxy)

    show_head_line(f"将使用.venv环境进行编译", color("bold_yellow"))

    temp_remove_file_dir = os.path.join(".cached", "build_temp_remove_files")
    site_packages_path = os.path.join(venv_path, "Lib", "site-packages")
    dep_files_to_remove_during_build = {
        "PyQt5/Qt5": [
            "Translations",
        ],
        "PyQt5/Qt5/bin": [
            "opengl32sw.dll",
            "libEGL.dll",
            "libGLESV2.dll",
            "Qt5Svg.dll",
            "Qt5Network.dll",
            "Qt5Qml.dll",
            "Qt5QmlModels.dll",
            "Qt5Quick.dll",
            "Qt5WebSockets.dll",
            "d3dcompiler_47.dll",
        ],
        "PyQt5/Qt5/plugins": [
            "iconengines/qsvgicon.dll",
            "imageformats/qsvg.dll",
            "imageformats/qwebp.dll",
            "platforms/qwebgl.dll",
        ]
    }
    logger.info(
        color("bold_green") +
        f"开始编译前先尝试移动这些确定用不到的库文件到临时目录 {temp_remove_file_dir},从而尽可能减少最终编译的大小")
    for parent_directory, file_or_directory_name_list in dep_files_to_remove_during_build.items(
    ):
        for file_or_directory_name in file_or_directory_name_list:
            path = os.path.join(site_packages_path, parent_directory,
                                file_or_directory_name)
            backup_path = os.path.join(temp_remove_file_dir, parent_directory,
                                       file_or_directory_name)

            if not os.path.exists(path):
                logger.warning(f"\t{path} 不存在,将跳过")
                continue

            # 将文件移动到备份目录
            logger.info(f"\t开始移动 {path}")
            make_sure_dir_exists(os.path.dirname(backup_path))
            shutil.move(path, backup_path)

    # 实际编译流程
    build_configs = [
        ("main.py", "DNF蚊子腿小助手.exe", "utils/icons/DNF蚊子腿小助手.ico", ".",
         ["PyQt5"], []),
        ("auto_updater.py", "auto_updater.exe", "", "utils", ["PyQt5"], []),
        ("ark_lottery_special_version.py", "DNF蚊子腿小助手_集卡特别版.exe",
         "utils/icons/ark_lottery_special_version.ico", ".", ["PyQt5"], []),
        ("config_ui.py", "DNF蚊子腿小助手配置工具.exe", "utils/icons/config_ui.ico", ".",
         [], ["--noconsole"]),
    ]

    for idx, config in enumerate(build_configs):
        prefix = f"{idx + 1}/{len(build_configs)}"

        src_path, exe_name, icon_path, target_dir, exclude_modules, extra_args = config
        logger.info(color("bold_yellow") + f"{prefix} 开始编译 {exe_name}")

        cmd_build = [
            pyinstaller_path,
            '--name',
            exe_name,
            '-F',
            src_path,
        ]
        if icon_path != "":
            cmd_build.extend(['--icon', icon_path])
        for module in exclude_modules:
            cmd_build.extend(['--exclude-module', module])
        if use_upx:
            cmd_build.extend(['--upx-dir', "utils"])
        cmd_build.extend(extra_args)

        logger.info(f"{prefix} 开始编译 {exe_name},命令为:{' '.join(cmd_build)}")
        subprocess.call(cmd_build)

        logger.info(f"编译结束,进行善后操作")

        # 复制二进制
        logger.info(f"复制{exe_name}到目标目录{target_dir}")
        if not os.path.isdir(target_dir):
            os.mkdir(target_dir)
        target_path = os.path.join(target_dir, exe_name)
        shutil.copyfile(os.path.join("dist", exe_name), target_path)

        # 删除临时文件
        logger.info("删除临时文件")
        for directory in ["build", "dist", "__pycache__"]:
            shutil.rmtree(directory, ignore_errors=True)
        os.remove(f"{exe_name}.spec")

        filesize = os.path.getsize(target_path)
        logger.info(
            color("bold_green") +
            f"{prefix} 编译{exe_name}结束,最终大小为{human_readable_size(filesize)}")

    logger.info(color("bold_green") + f"编译完毕将库文件移动回来 - {site_packages_path}")
    for parent_directory, file_or_directory_name_list in dep_files_to_remove_during_build.items(
    ):
        for file_or_directory_name in file_or_directory_name_list:
            path = os.path.join(site_packages_path, parent_directory,
                                file_or_directory_name)
            backup_path = os.path.join(temp_remove_file_dir, parent_directory,
                                       file_or_directory_name)

            if not os.path.exists(backup_path):
                logger.warning(f"\t备份文件 {backup_path} 不存在,将跳过")
                continue

            # 将文件移动到备份目录
            logger.info(f"开始还原备份文件/目录 {backup_path}")
            make_sure_dir_exists(os.path.dirname(path))
            shutil.move(backup_path, path)

    logger.info("done")
Exemple #14
0
def cui():
    # 读取配置信息
    load_config("config.toml", "config.toml.local")
    cfg = config()

    from main_def import check_proxy

    check_proxy(cfg)

    # note: 以下内容修改为自己的配置
    # 大号的账号序号(从1开始)
    dahao_indexes = [1]
    # 三个小号的序号
    xiaohao_indexes = [6, 7, 8]
    # 三个小号的QQ号
    xiaohao_qq_list = ["3036079506", "1470237902", "1276170371"]

    # re: 流程:
    #   1. send_to_xiaohao设为True,大号发送宝箱链接给三个小号
    #   2. 电脑上,大号QQ里点开三个小号对话的宝箱链接,替换Scode到scode_list里面
    #   3. send_to_xiaohao设为False,让小号开启各个宝箱

    # --------------- 每次只需要按流程修改下面几行 ---------------------

    send_to_xiaohao = True
    # send_to_xiaohao = False

    scode_list = [
        "MDJKQ0t5dDJYazlMVmMrc2ZXV0tVT0xsZitZMi9YOXZUUFgxMW1PcnQ2Yz0=",
        "UFgxa1lQZ3RBZERCMTU0N3dSWmcwZUxsZitZMi9YOXZUUFgxMW1PcnQ2Yz0=",
        "cXNpZTIrY2dRYk1GL2E4UjlGQzBkdUxsZitZMi9YOXZUUFgxMW1PcnQ2Yz0=",
    ]

    if len(xiaohao_qq_list) != scode_list:
        message_box("配置的小号数目与scode数目不一致,请确保两者一致", "出错了")
        sys.exit()

    # --------------- 每次只需要按流程修改上面几行 ---------------------

    # 登录相应账号
    if send_to_xiaohao:
        indexes = dahao_indexes
    else:
        indexes = xiaohao_indexes

    for idx in indexes:  # 从1开始,第i个
        account_config = cfg.account_configs[idx - 1]

        show_head_line(f"预先获取第{idx}个账户[{account_config.name}]的skey",
                       color("fg_bold_yellow"))

        if not account_config.is_enabled():
            logger.warning("账号被禁用,将跳过")
            continue

        djcHelper = DjcHelper(account_config, cfg.common)
        djcHelper.fetch_pskey()
        djcHelper.check_skey_expired()

    # 执行对应逻辑
    for order_index, account_index in enumerate(indexes):  # 从1开始,第i个
        account_config = cfg.account_configs[account_index - 1]

        show_head_line(f"开始处理第{account_index}个账户[{account_config.name}]",
                       color("fg_bold_yellow"))

        if not account_config.is_enabled():
            logger.warning("账号被禁用,将跳过")
            continue

        djcHelper = DjcHelper(account_config, cfg.common)

        djcHelper.fetch_pskey()
        djcHelper.check_skey_expired()
        djcHelper.get_bind_role_list()

        if send_to_xiaohao:
            logger.info(
                color("bold_green") + f"发送宝箱链接给小号QQ: {xiaohao_qq_list}")

            djcHelper.majieluo_send_to_xiaohao(xiaohao_qq_list)

            msg = (
                "1. 请在电脑登录大号QQ,依次点击各个小号的对话框里刚刚发送的宝箱链接,在浏览器中复制其链接中sCode的值到scode_list对应位置\n"
                "2. 请修改send_to_xiaohao为False后再次运行")
            message_box(msg, "后续流程")
        else:
            scode = scode_list[order_index]
            logger.info(
                f"第{order_index + 1}个小号领取刚刚运行后填写的Scode列表中第{order_index + 1}个scode - {scode}"
            )

            res = djcHelper.majieluo_open_box(scode)
            if res.sOutValue1 == 0:
                logger.info(color("bold_green") + "领取成功")
            else:
                code_to_message = {
                    "1": "无效的赠送链接",
                    "2": "不能打开自己的礼盒~",
                    "3": "该礼盒已经被开启",
                    "4": "好友今天的礼盒已经被全部打开了哦~",
                    "5": "一天只可以打开3次礼盒哦~",
                    "6": "该礼盒已经被开启",
                    "7": "该礼盒已经被开启",
                }
                message = "系统繁忙,请稍后再试~"
                if res.sOutValue1 in code_to_message:
                    message = code_to_message[res.sOutValue1]

                logger.error(message)

            time.sleep(1)

    # 第二次执行完毕提示修改send_to_xiaohao
    if not send_to_xiaohao:
        message_box("已领取完毕,请修改send_to_xiaohao为True,方便明天继续从头用", "提示")