From b43ee0a039b40e4835bb05e1f686a1a10cc64860 Mon Sep 17 00:00:00 2001 From: reiqr <93467189+reiqr@users.noreply.github.com> Date: Fri, 3 Jul 2026 18:45:23 +0800 Subject: [PATCH] =?UTF-8?q?=E6=94=B9=E8=BF=9B=E8=84=9A=E6=9C=AC=E5=90=AF?= =?UTF-8?q?=E5=8A=A8=E8=B7=AF=E5=BE=84=E3=80=81=E9=94=99=E8=AF=AF=E6=8F=90?= =?UTF-8?q?=E7=A4=BA=E5=92=8C=E6=8F=90=E7=A4=BA=E9=9F=B3=E6=96=87=E4=BB=B6?= =?UTF-8?q?=E5=90=8D=E5=8C=B9=E9=85=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...Notification-Sound-Modification-Script.ps1 | 180 ++++++++++++++---- 1 file changed, 139 insertions(+), 41 deletions(-) diff --git a/Windows-Notification-Sound-Modification-Script.ps1 b/Windows-Notification-Sound-Modification-Script.ps1 index fdb4202..f7f3950 100644 --- a/Windows-Notification-Sound-Modification-Script.ps1 +++ b/Windows-Notification-Sound-Modification-Script.ps1 @@ -1,14 +1,45 @@ -<# +<# Author: AkagawaTsurunaki #> +function NormalizeEventName { + param ( + [string]$eventName + ) + + if ($null -eq $eventName) { + return '' + } + + return ($eventName.Trim().ToLowerInvariant() -replace '[\s ]', '') +} + +function GetToneFileNameCandidates { + param ( + [string]$toneFileName + ) + + $candidates = [System.Collections.Generic.List[string]]::new() + $baseName = $toneFileName.Trim() + $nameWithoutAnnotation = ($baseName -replace '[((].*?[))]', '').Trim() + $nameBeforeAnnotation = ($baseName -split '[((]', 2)[0].Trim() + + foreach ($candidate in @($baseName, $nameWithoutAnnotation, $nameBeforeAnnotation)) { + if (![string]::IsNullOrWhiteSpace($candidate) -and !$candidates.Contains($candidate)) { + $candidates.Add($candidate) + } + } + + return $candidates +} + function ReadEventLabelsFromJsonFile { param () - $eventLabelsJsonFilePath = '.\EventLabels.json' - if (Test-Path $eventLabelsJsonFilePath) { - return Get-Content -Path $eventLabelsJsonFilePath -Raw -Encoding UTF8 | ConvertFrom-Json + $eventLabelsJsonFilePath = Join-Path $PSScriptRoot 'EventLabels.json' + if (Test-Path -LiteralPath $eventLabelsJsonFilePath) { + return Get-Content -LiteralPath $eventLabelsJsonFilePath -Raw -Encoding UTF8 | ConvertFrom-Json } else { - throw [System.IO.FileNotFoundException] "$eventLabelsJsonFilePath not found." + throw [System.IO.FileNotFoundException]::new("未找到事件标签配置文件:$eventLabelsJsonFilePath") } } @@ -17,7 +48,7 @@ function GetAllToneFilesInfo { [string]$toneFolderPath ) $fileHashTable = @{} - $toneFiles = Get-ChildItem -Path $toneFolderPath -Filter *.wav + $toneFiles = Get-ChildItem -LiteralPath $toneFolderPath -Filter *.wav -File foreach ($toneFile in $toneFiles) { $toneFileNameWithoutExtension = [System.IO.Path]::GetFileNameWithoutExtension($toneFile.Name) $toneFileAbsPath = $toneFile.FullName @@ -26,21 +57,38 @@ function GetAllToneFilesInfo { return $fileHashTable } -function GetEventLabel { +function NewEventLabelLookup { param ( - [string]$lang, - [string]$eventLabel, $eventLabels ) + + $lookup = @{} foreach ($app in $eventLabels) { foreach ($label in $app.EventLabels) { - if ($lang -eq 'EN' -and $label.EN -eq $eventLabel) { - return @{App=$app.App; id=$label.ID} - } elseif ($lang -eq 'ZH' -and $label.ZH -eq $eventLabel) { - return @{App=$app.App; id=$label.ID} + foreach ($name in @($label.ZH, $label.EN, $label.ID)) { + $key = NormalizeEventName -eventName $name + if (![string]::IsNullOrWhiteSpace($key) -and !$lookup.ContainsKey($key)) { + $lookup[$key] = @{ App = $app.App; id = $label.ID; ZH = $label.ZH; EN = $label.EN } + } } } - } + } + + return $lookup +} + +function GetEventLabel { + param ( + [string]$toneFileName, + $eventLabelLookup + ) + + foreach ($candidate in (GetToneFileNameCandidates -toneFileName $toneFileName)) { + $key = NormalizeEventName -eventName $candidate + if ($eventLabelLookup.ContainsKey($key)) { + return $eventLabelLookup[$key] + } + } } function CreateAppEventsSchemesNamesByPackageName { @@ -59,51 +107,101 @@ function CreateAppEventsSchemesNamesByPackageName { $path = "HKCU:\AppEvents\Schemes\Names\$pkgId" $i = $i + 1 } while ( - Test-Path $path + Test-Path -LiteralPath $path ) - $pkgId - New-Item -Path $path - New-ItemProperty -Path $path -Name "(Default)" -Value $tonePackageName -PropertyType "String" - return + New-Item -Path $path -Force | Out-Null + New-ItemProperty -Path $path -Name "(Default)" -Value $tonePackageName -PropertyType "String" -Force | Out-Null + return $pkgId } function SetTone { param ( [string]$registryItem, + [string]$currentRegistryItem, [string]$toneFilePath ) - if (!(Test-Path $registryItem)) { - New-Item -Path $registryItem + if (!(Test-Path -LiteralPath $registryItem)) { + New-Item -Path $registryItem -Force | Out-Null + } + if (!(Test-Path -LiteralPath $currentRegistryItem)) { + New-Item -Path $currentRegistryItem -Force | Out-Null } + Set-ItemProperty -Path $registryItem -Name "(Default)" -Value $toneFilePath - return Test-Path $registryItem + Set-ItemProperty -Path $currentRegistryItem -Name "(Default)" -Value $toneFilePath + return (Test-Path -LiteralPath $registryItem) -and (Test-Path -LiteralPath $currentRegistryItem) } -$eventLabels = ReadEventLabelsFromJsonFile +try { + $eventLabels = ReadEventLabelsFromJsonFile + $eventLabelLookup = NewEventLabelLookup -eventLabels $eventLabels + + do { + $toneFolderPath = Read-Host -Prompt "请输入存放提示音 .wav 文件的文件夹路径" + $toneFolderPath = $toneFolderPath.Trim('"') + if ([string]::IsNullOrWhiteSpace($toneFolderPath)) { + Write-Host "路径不能为空,请重新输入。" -ForegroundColor Yellow + continue + } + if (!(Test-Path -LiteralPath $toneFolderPath -PathType Container)) { + Write-Host "未找到该文件夹:$toneFolderPath" -ForegroundColor Yellow + continue + } + break + } while ($true) + + $tonePackageName = Split-Path $toneFolderPath -Leaf + Write-Host "已找到提示音包:$tonePackageName" + + $TonePackageId = CreateAppEventsSchemesNamesByPackageName -tonePackageName $tonePackageName + + $allToneFilesInfo = GetAllToneFilesInfo -toneFolderPath $toneFolderPath + Write-Host "已找到 $($allToneFilesInfo.Keys.Count) 个 .wav 提示音文件。" -$toneFolderPath = Read-Host -Prompt "Please enter the path of the folder that stores notification sounds" + if ($allToneFilesInfo.Keys.Count -eq 0) { + throw "指定文件夹中没有 .wav 文件,请检查后重新运行。" + } -$tonePackageName = Split-Path $toneFolderPath -Leaf -Write-Host "Tone package" $tonePackageName "found" + $setCount = 0 + $skippedCount = 0 + $unmatchedCount = 0 + $matchedRegistryItems = @{} -$TonePackageId = CreateAppEventsSchemesNamesByPackageName -tonePackageName $tonePackageName -$TonePackageId = $TonePackageId[0] + foreach ($toneFileName in ($allToneFilesInfo.Keys | Sort-Object)) { + $eventLabel = GetEventLabel -toneFileName $toneFileName -eventLabelLookup $eventLabelLookup + if ($eventLabel) { + $registryItem = 'HKCU:\AppEvents\Schemes\Apps\{0}\{1}\{2}' -f $eventLabel.App, $eventLabel.id, $TonePackageId + $currentRegistryItem = 'HKCU:\AppEvents\Schemes\Apps\{0}\{1}\.Current' -f $eventLabel.App, $eventLabel.id -$allToneFilesInfo = GetAllToneFilesInfo -toneFolderPath $toneFolderPath -Write-Host $allToneFilesInfo.Keys.Count "tone file(s) found" + if ($matchedRegistryItems.ContainsKey($currentRegistryItem)) { + Write-Host "已跳过:$toneFileName 与已设置的 $($matchedRegistryItems[$currentRegistryItem]) 对应同一个系统事件。" -ForegroundColor DarkYellow + $skippedCount++ + continue + } -foreach ($toneFileName in $allToneFilesInfo.Keys) { - $eventLabel = GetEventLabel -lang 'ZH' -eventLabel $toneFileName -eventLabels $eventLabels - if ($eventLabel) { - $registryItem = "HKCU:\AppEvents\Schemes\Apps\" + $eventLabel.App +"\" + $eventLabel.ID + "\" + $TonePackageId - $toneFilePath = $allToneFilesInfo[$toneFileName] - if (SetTone -registryItem $registryItem -toneFilePath $toneFilePath) { - Write-Host "Set $registryItem to $toneFilePath" + $toneFilePath = $allToneFilesInfo[$toneFileName] + if (SetTone -registryItem $registryItem -currentRegistryItem $currentRegistryItem -toneFilePath $toneFilePath) { + Write-Host "已设置:$($eventLabel.ZH) -> $toneFilePath" + $matchedRegistryItems[$currentRegistryItem] = $toneFileName + $setCount++ + } + } else { + Write-Host "未匹配:$toneFileName" -ForegroundColor DarkYellow + $unmatchedCount++ } } -} -Write-Host "Notification sound package $tonePackageName has been registered in your system successfully" -Write-Host "Note: You need to REBOOT your computer to make effect." -Read-Host "Press any key to exit..." \ No newline at end of file + if ($setCount -eq 0) { + Write-Host "没有匹配到可设置的系统事件。请确认 .wav 文件名与 EventLabels.json 中的事件名称一致。" -ForegroundColor Yellow + } else { + Write-Host "提示音包 $tonePackageName 已成功注册到系统,并已写入当前声音设置。" + Write-Host "已设置 $setCount 个事件,跳过 $skippedCount 个重复事件,未匹配 $unmatchedCount 个文件。" + Write-Host "提示:如果控制面板没有立刻刷新,请关闭并重新打开“声音”设置;必要时注销或重启后生效。" + } +} catch { + Write-Host "运行失败:$($_.Exception.Message)" -ForegroundColor Red + Write-Host "窗口不会自动关闭,请根据上面的提示检查文件或路径。" -ForegroundColor Yellow +} finally { + Read-Host "按 Enter 键退出" +}