惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Project Zero
Project Zero
WordPress大学
WordPress大学
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
V
Visual Studio Blog
爱范儿
爱范儿
P
Proofpoint News Feed
F
Fortinet All Blogs
雷峰网
雷峰网
小众软件
小众软件
Jina AI
Jina AI
人人都是产品经理
人人都是产品经理
TaoSecurity Blog
TaoSecurity Blog
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
S
Secure Thoughts
Recent Commits to openclaw:main
Recent Commits to openclaw:main
博客园 - 司徒正美
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
Microsoft Azure Blog
Microsoft Azure Blog
IT之家
IT之家
S
Security @ Cisco Blogs
Help Net Security
Help Net Security
GbyAI
GbyAI
Webroot Blog
Webroot Blog
T
Troy Hunt's Blog
B
Blog
MongoDB | Blog
MongoDB | Blog
月光博客
月光博客
H
Heimdal Security Blog
Google Online Security Blog
Google Online Security Blog
S
Security Affairs
云风的 BLOG
云风的 BLOG
Engineering at Meta
Engineering at Meta
www.infosecurity-magazine.com
www.infosecurity-magazine.com
H
Help Net Security
O
OpenAI News
H
Hacker News: Front Page
博客园 - 叶小钗
Last Week in AI
Last Week in AI
S
Schneier on Security
The Last Watchdog
The Last Watchdog
C
Cyber Attacks, Cyber Crime and Cyber Security
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
MyScale Blog
MyScale Blog
Recorded Future
Recorded Future
博客园 - 【当耐特】
V
Vulnerabilities – Threatpost
大猫的无限游戏
大猫的无限游戏
N
News | PayPal Newsroom
The Hacker News
The Hacker News
A
Arctic Wolf

Cyberia

《C(金钱掌控)》观后感 - Cyberia C#在Windows UI开发中的衰落 - Cyberia 存储退潮 字体padding计算器 开源已死 如何写出优雅完整的音频元数据 起夜级家庭网络正在变得越来越重要 优化Powershell的启动时间 无JavaScript其实没有很重要 你不需要一个电纸书阅读器 文件分享的难题 为什么我不敢看都市 某科学的 SSH 算号指南 时代的辉夜姬 为什么 Pixi 是神 关于神椿的过去,当下以及未来,我的一点看法 Tahoe 的图标令人难评 The EVE of PUSHING LIMITS 在 Word 中通过制表符实现居中对齐等操作 编码之殇:前 Unicode 时代的 WAV 处理 sHELL 即地狱 WR1800K AX NAND 路由器刷入 Immortalwrt 一个 PWM 的世界 沉痛悼念复选框同志 字体焕新 独立博客自省问卷15题 答一答 解决 Visual Studio Code 内终端启动报错问题 (1) 简评《鱿鱼游戏》 Sword Art Online,以及它带来了什么 解决 Visual Studio Code 内终端启动报错问题 2024 年度总结 轻小说重度依赖 铃音之后 解决部分应用在 Windows 平台下端口被随机占用的问题 计算机科学中最困难的事:居中 宿舍场景下多人共用路由器下流量分流实践 Extra Decal Pre Processor 自动化处理 Amazon Music 文件 MD5 不一致问题 解决 MultiMC 无 Forge 版本的 Optifine 安装问题
自动化EAC音频抓取
Nullpinter · 2026-05-06 · via Cyberia

; Copyright (c) 2026 Nullpinter

; This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.

; If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.

748 collapsed lines

Persistent

SetTitleMatchMode 2

DetectHiddenWindows false

global EAC_WIN := "ahk_exe EAC.exe"

global current_step := 1

global is_running := false

global abort_flag := false

global ui := 0

global title_text := 0

global status_text := 0

global next_text := 0

global detail_text := 0

global progress_bar := 0

global next_btn := 0

global auto_btn := 0

global skip_btn := 0

global reset_btn := 0

global exit_btn := 0

InitUi()

InitUi() {

global ui, title_text, status_text, next_text, detail_text

global progress_bar, next_btn, auto_btn, skip_btn, reset_btn, exit_btn

ui := Gui("+AlwaysOnTop +ToolWindow", "EAC 自动化控制")

ui.MarginX := 16

ui.MarginY := 14

ui.SetFont("s10", "Microsoft YaHei UI")

title_text := ui.AddText("w620 h28", "EAC 自动化控制")

status_text := ui.AddText("w620 h32", "")

next_text := ui.AddText("w620 h32", "")

progress_bar := ui.AddProgress("w620 h16 Range0-100", 0)

detail_text := ui.AddEdit("w620 h150 ReadOnly -Wrap", "")

next_btn := ui.AddButton("xm w120 h34", "执行下一步")

auto_btn := ui.AddButton("x+8 w120 h34", "全自动模式")

skip_btn := ui.AddButton("x+8 w110 h34", "跳过当前步")

reset_btn := ui.AddButton("x+8 w100 h34", "重置流程")

exit_btn := ui.AddButton("x+8 w80 h34", "退出")

next_btn.OnEvent("Click", (*) => RunNextStep())

auto_btn.OnEvent("Click", (*) => RunAutoMode())

skip_btn.OnEvent("Click", (*) => SkipCurrentStep())

reset_btn.OnEvent("Click", (*) => ResetFlow())

exit_btn.OnEvent("Click", (*) => ExitApp())

ui.OnEvent("Close", (*) => ExitApp())

RefreshUi("等待操作", "请点击“执行下一步”,或点击“全自动模式”。", 0)

ui.Show("AutoSize Center")

}

RunNextStep() {

global current_step, is_running, abort_flag

global next_btn, auto_btn, skip_btn, reset_btn

if is_running

return

if current_step > 5 {

ExitApp()

return

}

if !WinExist(EAC_WIN) {

RefreshUi("错误", "未找到 EAC 进程。请先启动 Exact Audio Copy。", 0)

return

}

is_running := true

abort_flag := false

next_btn.Enabled := false

auto_btn.Enabled := false

skip_btn.Enabled := false

reset_btn.Enabled := false

step_name := StepName(current_step)

RefreshUi("正在执行第 " current_step " 步", step_name, StepStartPercent(current_step))

try {

DoStep(current_step)

finished_step := current_step

current_step += 1

if current_step <= 5 {

RefreshUi(

"第 " finished_step " 步完成",

"已暂停。下一步:" StepName(current_step),

StepDonePercent(finished_step)

)

} else {

RefreshUi(

"全部步骤完成",

"EAC 自动化流程已完成。",

100

)

}

} catch as e {

RefreshUi(

"第 " current_step " 步失败或中止",

e.Message,

StepStartPercent(current_step)

)

}

is_running := false

reset_btn.Enabled := true

auto_btn.Enabled := true

if current_step <= 5 {

next_btn.Text := "执行下一步"

next_btn.Enabled := true

skip_btn.Enabled := true

} else {

next_btn.Text := "关闭"

next_btn.Enabled := true

skip_btn.Enabled := false

}

}

RunAutoMode() {

global current_step, is_running, abort_flag

global next_btn, auto_btn, skip_btn, reset_btn

if is_running

return

if !WinExist(EAC_WIN) {

RefreshUi("错误", "未找到 EAC 进程。请先启动 Exact Audio Copy。", 0)

return

}

is_running := true

abort_flag := false

next_btn.Enabled := false

auto_btn.Enabled := false

skip_btn.Enabled := false

reset_btn.Enabled := false

current_step := 1

try {

RefreshUi("全自动模式:第 1 步", StepName(1), StepStartPercent(1))

AutoStep1()

current_step := 2

RefreshUi("全自动模式:第 2 步", StepName(2), StepStartPercent(2))

AutoStep2()

current_step := 3

RefreshUi("全自动模式:第 3 步", StepName(3), StepStartPercent(3))

AutoStep3()

current_step := 4

RefreshUi("全自动模式:第 4 步", StepName(4), StepStartPercent(4))

AutoStep4()

current_step := 6

RefreshUi(

"全自动模式完成",

"已完成第 1 到第 4 步。`r`n第 5 步不执行任何实际操作。",

100

)

} catch as e {

RefreshUi(

"全自动模式失败或中止",

e.Message,

StepStartPercent(current_step)

)

}

is_running := false

reset_btn.Enabled := true

auto_btn.Enabled := true

if current_step <= 5 {

next_btn.Text := "执行下一步"

next_btn.Enabled := true

skip_btn.Enabled := true

} else {

next_btn.Text := "关闭"

next_btn.Enabled := true

skip_btn.Enabled := false

}

}

DoStep(step) {

switch step {

case 1:

StepDetail("发送菜单命令:操作 > 检测间隙")

SendStepMenu(1)

StepDetail("已发送“检测间隙”命令。`r`n按钮将保持禁用 3 秒。")

Sleep 3000

case 2:

StepDetail("发送菜单命令:操作 > 检测静音间隙")

SendStepMenu(2)

StepDetail("已发送“检测静音间隙”命令。`r`n按钮将保持禁用 3 秒。")

Sleep 3000

case 3:

StepDetail("发送菜单命令:操作 > 创建 CUE 目录文件 > 多个带间隙的 WAV 文件...(非规则)")

SendStepMenu(3)

StepDetail("已发送“创建多个带间隙的 WAV 文件”命令。`r`n按钮将保持禁用 3 秒。")

Sleep 3000

case 4:

StepDetail("发送菜单命令:操作 > 测试并抓取所选音轨 > 已压缩...")

SendStepMenu(4)

StepDetail("已发送“测试并抓取,已压缩”命令。`r`n脚本不会等待抓取完成。`r`n按钮将保持禁用 3 秒。")

Sleep 3000

case 5:

StepDetail("第 5 步不执行任何实际操作。`r`n流程到此结束。")

Sleep 500

}

}

AutoStep1() {

StepDetail("全自动第 1 步:发送“检测间隙”命令。")

SendStepMenu(1)

StepDetail("全自动第 1 步:等待 EAC 的“正在分析”弹窗出现。")

WaitAnalyzeDialogAppearThenDisappear("检测间隙")

StepDetail("全自动第 1 步完成:“正在分析”弹窗已消失。")

}

AutoStep2() {

StepDetail("全自动第 2 步:发送“检测静音间隙”命令。")

SendStepMenu(2)

StepDetail("全自动第 2 步:等待标题为“正在分析”且文本包含“测试静音中的间隙”的弹窗。")

WaitSilentGapDialogAndClickOk()

StepDetail("全自动第 2 步完成:已在按钮变为“确定”后点击。")

}

AutoStep3() {

StepDetail("全自动第 3 步:发送“创建多个带间隙的 WAV 文件(非规则)”命令。")

SendStepMenu(3)

StepDetail("全自动第 3 步:等待 EAC 的“正在分析”弹窗出现。")

WaitAnalyzeDialogAppearThenDisappear("创建多个带间隙的 WAV 文件,非规则")

StepDetail("全自动第 3 步完成:“正在分析”弹窗已消失。")

}

AutoStep4() {

StepDetail("全自动第 4 步:发送“测试并抓取所选音轨,已压缩”命令。")

SendStepMenu(4)

StepDetail("全自动第 4 步:等待 EAC 抓取或压缩相关窗口出现后消失。`r`n本步骤不设置等待超时。")

WaitAnyEacDialogAppearThenDisappearNoTimeout("测试并抓取,已压缩")

StepDetail("全自动第 4 步完成:EAC 相关窗口已消失。")

}

SendStepMenu(step) {

switch step {

case 1:

SelectEacMenuWithRetry(60000,

["操作(&A)", "检测间隙(&D)"],

["操作(A)", "检测间隙(D)"],

["操作", "检测间隙"]

)

case 2:

SelectEacMenuWithRetry(60000,

["操作(&A)", "检测静音间隙(&G)"],

["操作(A)", "检测静音间隙(G)"],

["操作", "检测静音间隙"]

)

case 3:

SelectEacMenuWithRetry(60000,

["操作(&A)", "创建 CUE 目录文件(&S)", "4&"],

["操作(A)", "创建 CUE 目录文件(S)", "4&"],

["操作", "创建 CUE 目录文件", "4&"],

)

case 4:

SelectEacMenuWithRetry(60000,

["操作(&A)", "测试并抓取所选音轨(&O)", "已压缩..."],

["操作(A)", "测试并抓取所选音轨(O)", "已压缩..."],

["操作", "测试并抓取所选音轨", "已压缩..."]

)

default:

throw Error("未知步骤:" step)

}

}

SelectEacMenuWithRetry(timeout_ms, menu_paths*) {

global EAC_WIN

deadline := A_TickCount + timeout_ms

last_error := ""

while A_TickCount < deadline {

CheckAbort()

for path in menu_paths {

try {

WinActivate(EAC_WIN)

WinWaitActive(EAC_WIN, , 2)

MenuSelect(EAC_WIN, "", path*)

Sleep 500

return true

} catch as e {

last_error := e.Message

}

}

Sleep 800

}

throw Error("菜单项执行失败。最后错误:" last_error)

}

WaitAnalyzeDialogAppearThenDisappear(label) {

hwnd := WaitEacDialog("正在分析", "", 60000, label)

StepDetail(label ":已检测到“正在分析”弹窗。`r`n正在等待该弹窗消失。")

WaitWindowGone(hwnd, 0, label)

}

WaitSilentGapDialogAndClickOk() {

seen_target := false

last_info := ""

StepDetail("检测静音间隙:等待 EAC 的“正在分析”弹窗。`r`n不再要求先检测到“取消”。")

loop {

CheckAbort()

hwnds := []

try hwnds := WinGetList("ahk_class #32770 ahk_exe EAC.exe")

catch {

hwnds := []

}

target_hwnd := 0

target_title := ""

target_text := ""

target_btn_text := ""

for hwnd in hwnds {

title := ""

text := ""

btn_text := ""

try title := WinGetTitle("ahk_id " hwnd)

catch {

continue

}

if !InStr(title, "正在分析")

continue

try text := WinGetText("ahk_id " hwnd)

catch {

text := ""

}

if !InStr(text, "测试静音中的间隙")

continue

try btn_text := ControlGetText("Button1", "ahk_id " hwnd)

catch {

btn_text := ""

}

target_hwnd := hwnd

target_title := title

target_text := text

target_btn_text := btn_text

break

}

if target_hwnd {

seen_target := true

btn_norm := NormalizeButtonText(target_btn_text)

last_info := "窗口标题:" target_title "`r`n"

. "Button1 文本:" target_btn_text "`r`n"

. "正在等待 Button1 变为“确定”。"

StepDetail("检测静音间隙进行中。`r`n" last_info)

if btn_norm = "确定" || btn_norm = "OK" {

Sleep 500

try {

ControlClick("Button1", "ahk_id " target_hwnd)

} catch as e {

try {

WinActivate("ahk_id " target_hwnd)

WinWaitActive("ahk_id " target_hwnd, , 2)

Send "{Enter}"

} catch as e2 {

throw Error("点击 Button1 失败:" e.Message ";发送 Enter 也失败:" e2.Message)

}

}

WaitWindowGone(target_hwnd, 0, "检测静音间隙确认弹窗")

return true

}

} else {

if seen_target {

StepDetail(

"检测静音间隙:目标弹窗暂时未找到。`r`n"

"可能正在刷新窗口状态,继续等待。`r`n`r`n"

last_info

)

} else {

StepDetail("检测静音间隙:尚未检测到目标“正在分析”弹窗。")

}

}

Sleep 100

}

}

WaitAnyEacDialogAppearThenDisappearNoTimeout(label) {

hwnd := WaitAnyEacRelatedWindow(0, label)

title := ""

text := ""

try title := WinGetTitle("ahk_id " hwnd)

try text := WinGetText("ahk_id " hwnd)

text := CleanText(text)

if StrLen(text) > 500

text := SubStr(text, 1, 500) "..."

StepDetail(

label ":已检测到 EAC 相关窗口。`r`n"

"窗口标题:" title "`r`n`r`n"

text "`r`n`r`n"

"正在等待该窗口消失。`r`n"

"本步骤不设置等待超时。"

)

WaitWindowGone(hwnd, 0, label)

}

WaitEacDialog(title_contains, text_contains := "", timeout_ms := 60000, label := "") {

deadline := timeout_ms > 0 ? A_TickCount + timeout_ms : 0

loop {

CheckAbort()

if timeout_ms > 0 && A_TickCount > deadline {

if text_contains != ""

throw Error("等待弹窗超时:" label "。标题包含:" title_contains ",文本包含:" text_contains)

else

throw Error("等待弹窗超时:" label "。标题包含:" title_contains)

}

hwnd := FindEacDialog(title_contains, text_contains)

if hwnd

return hwnd

Sleep 250

}

}

FindEacDialog(title_contains := "", text_contains := "") {

hwnds := []

try hwnds := WinGetList("ahk_class #32770 ahk_exe EAC.exe")

catch {

return 0

}

for hwnd in hwnds {

title := ""

text := ""

try title := WinGetTitle("ahk_id " hwnd)

catch {

continue

}

if title_contains != "" && !InStr(title, title_contains)

continue

if text_contains != "" {

try text := WinGetText("ahk_id " hwnd)

catch {

continue

}

if !InStr(text, text_contains)

continue

}

return hwnd

}

return 0

}

WaitAnyEacRelatedWindow(timeout_ms := 0, label := "") {

deadline := timeout_ms > 0 ? A_TickCount + timeout_ms : 0

loop {

CheckAbort()

if timeout_ms > 0 && A_TickCount > deadline

throw Error("等待 EAC 相关弹窗超时:" label)

hwnds := []

try hwnds := WinGetList("ahk_class #32770 ahk_exe EAC.exe")

catch {

hwnds := []

}

for hwnd in hwnds {

title := ""

text := ""

try title := WinGetTitle("ahk_id " hwnd)

try text := WinGetText("ahk_id " hwnd)

if title != "" || text != ""

return hwnd

}

Sleep 500

}

}

WaitWindowGone(hwnd, timeout_ms := 0, label := "") {

deadline := timeout_ms > 0 ? A_TickCount + timeout_ms : 0

loop {

CheckAbort()

if !WinExist("ahk_id " hwnd)

return true

if timeout_ms > 0 && A_TickCount > deadline

throw Error("等待窗口消失超时:" label)

Sleep 250

}

}

NormalizeButtonText(s) {

s := StrReplace(s, "&", "")

s := RegExReplace(s, "\([A-Za-z]\)", "")

s := RegExReplace(s, "([A-Za-z])", "")

return Trim(s)

}

CleanText(s) {

s := StrReplace(s, "`r", "")

s := RegExReplace(s, "`n{3,}", "`n`n")

return Trim(s)

}

SkipCurrentStep() {

global current_step, is_running

global next_btn, auto_btn, skip_btn, reset_btn

if is_running

return

if current_step > 5 {

ExitApp()

return

}

skipped_step := current_step

skipped_name := StepName(skipped_step)

current_step += 1

if current_step <= 5 {

RefreshUi(

"已跳过第 " skipped_step " 步",

"未执行:" skipped_name "`r`n下一步:" StepName(current_step),

StepDonePercent(skipped_step)

)

next_btn.Text := "执行下一步"

next_btn.Enabled := true

auto_btn.Enabled := true

skip_btn.Enabled := true

reset_btn.Enabled := true

} else {

RefreshUi(

"全部步骤完成",

"已跳过第 " skipped_step " 步:" skipped_name "`r`nEAC 自动化流程已完成。",

100

)

next_btn.Text := "关闭"

next_btn.Enabled := true

auto_btn.Enabled := true

skip_btn.Enabled := false

reset_btn.Enabled := true

}

}

ResetFlow() {

global current_step, is_running

global next_btn, auto_btn, skip_btn, reset_btn

if is_running

return

current_step := 1

next_btn.Text := "执行下一步"

next_btn.Enabled := true

auto_btn.Enabled := true

skip_btn.Enabled := true

reset_btn.Enabled := true

RefreshUi("已重置", "请点击“执行下一步”,或点击“全自动模式”。", 0)

}

CheckAbort() {

global abort_flag

if abort_flag

throw Error("用户通过 UI 中止。")

}

RefreshUi(status, detail, percent) {

global current_step

global title_text, status_text, next_text, detail_text, progress_bar, next_btn

title_text.Text := "EAC 自动化控制"

status_text.Text := "状态:" status

detail_text.Value := detail

progress_bar.Value := percent

if current_step <= 5 {

next_text.Text := "下一步:" current_step "/5," StepName(current_step)

next_btn.Text := "执行下一步"

} else {

next_text.Text := "下一步:无,流程已完成"

next_btn.Text := "关闭"

}

}

StepDetail(text) {

global detail_text

if IsObject(detail_text)

detail_text.Value := text

}

StepName(step) {

switch step {

case 1:

return "检测间隙"

case 2:

return "检测静音间隙"

case 3:

return "创建多个带间隙的 WAV 文件,非规则"

case 4:

return "测试并抓取,已压缩"

case 5:

return "抓取完成后确定"

default:

return "完成"

}

}

StepStartPercent(step) {

switch step {

case 1:

return 0

case 2:

return 20

case 3:

return 40

case 4:

return 60

case 5:

return 80

default:

return 100

}

}

StepDonePercent(step) {

switch step {

case 1:

return 20

case 2:

return 40

case 3:

return 60

case 4:

return 80

case 5:

return 100

default:

return 100

}

}