SnowCat 雪猫底层全源码:NapCat 4.18.28 底座 + SnowLuma 能力移植 + V8 通道适配 9.9.37
26 包 monorepo(TS 全源码): - snowcat-core: NT 内核 API 封装 + listener(含 9.9.37 六回调适配)+ Packet 发包 - snowcat-onebot: OneBot v11 全动作 + MCP Streamable HTTP 适配器 + 稳定线 - snowcat-webui-frontend/backend: 雪猫控制台(React+HeroUI) - snowcat-shell: 单文件 bundle 出口(vite inlineDynamicImports) - snowcat-native: napi2native / MoeHoo / ffmpeg / pty 运行时 - 56 项 SnowLuma 独门动作移植(qzone 全家桶/群相册/装扮/闪照/收藏) - 工具件: 解包器/启动器/便携制作器/doctor GitHub 关联已全量指向 DandanLLab/SnowCatQQ
This commit is contained in:
commit
b9655a5ab1
1048 files changed
+130851
No files matched your search
@@ -0,0 +1,187 @@
|
||||
# SnowCat 雪猫 · 稳定线启动器(PowerShell)
|
||||
#
|
||||
# 零硬改设计(对照 start-tongling.ps1 的三处硬改,全部自动化):
|
||||
# ① 自动发现 QQ:注册表 → 常见路径 → D:/OneKey 便携 → 找不到给一键安装提示
|
||||
# ② 自动读真实版本:versions/*/resources/app/package.json(废手工 qqnt.json 钉版)
|
||||
# ③ 自动生成 qqnt.json + loadNapCat.js 到运行时目录
|
||||
# 用法: .\snowcat-launch.ps1 [-Account 3430961870] [-NapcatDir C:\dsh\.tmp\napcat-shell] [-QQPath 自定义QQ.exe]
|
||||
# 2026-11-11 立项 · SnowCat Project
|
||||
|
||||
param(
|
||||
[string]$Account = '3430961870',
|
||||
[string]$NapcatDir = 'C:\dsh\.tmp\napcat-shell',
|
||||
[string]$QQPath = '',
|
||||
[switch]$InstallIfMissing
|
||||
)
|
||||
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
# ─────────────── ① QQ 自动发现 ───────────────
|
||||
|
||||
function Find-QQInstall {
|
||||
param([string]$Override)
|
||||
|
||||
if ($Override -and (Test-Path $Override)) {
|
||||
return @{ Path = $Override; Source = 'param' }
|
||||
}
|
||||
|
||||
# 1) 注册表(标准安装版)
|
||||
try {
|
||||
$reg = Get-ItemProperty 'HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\QQ' -ErrorAction SilentlyContinue
|
||||
if ($reg -and $reg.UninstallString) {
|
||||
$dir = Split-Path $reg.UninstallString.Trim('"') -Parent
|
||||
$qq = Join-Path $dir 'QQ.exe'
|
||||
if (Test-Path $qq) { return @{ Path = $qq; Source = 'registry' } }
|
||||
}
|
||||
} catch {}
|
||||
|
||||
# 2) 常见安装路径
|
||||
foreach ($p in @(
|
||||
"$env:ProgramFiles\Tencent\QQNT\QQ.exe",
|
||||
"${env:ProgramFiles(x86)}\Tencent\QQNT\QQ.exe",
|
||||
"$env:LOCALAPPDATA\Programs\Tencent\QQNT\QQ.exe"
|
||||
)) {
|
||||
if (Test-Path $p) { return @{ Path = $p; Source = 'common-path' } }
|
||||
}
|
||||
|
||||
# 3) OneKey 便携包
|
||||
$onekey = Get-ChildItem 'D:\NapCat.Shell.Windows.OneKey\*\QQ.exe' -ErrorAction SilentlyContinue | Select-Object -First 1
|
||||
if ($onekey) { return @{ Path = $onekey.FullName; Source = 'onekey-portable' } }
|
||||
|
||||
return $null
|
||||
}
|
||||
|
||||
# ─────────────── ② 真实版本探测 ───────────────
|
||||
|
||||
function Get-QQRealVersion {
|
||||
param([string]$QQExe)
|
||||
|
||||
$root = Split-Path $QQExe -Parent
|
||||
# 权威源:versions/*/resources/app/package.json(便携版)
|
||||
$versions = Join-Path $root 'versions'
|
||||
if (Test-Path $versions) {
|
||||
$app = Get-ChildItem $versions -Directory | ForEach-Object {
|
||||
$pj = Join-Path $_.FullName 'resources\app\package.json'
|
||||
if (Test-Path $pj) { Get-Content $pj -Raw | ConvertFrom-Json }
|
||||
} | Sort-Object { [version]($_.version -replace '-.*', '') } -Descending | Select-Object -First 1
|
||||
if ($app) {
|
||||
return @{ version = $app.version; json = $app; dir = $root }
|
||||
}
|
||||
}
|
||||
# 标准安装版:QQ.exe 版本资源
|
||||
$vi = (Get-Item $QQExe).VersionInfo
|
||||
return @{ version = "$($vi.ProductVersion)"; json = $null; dir = $root }
|
||||
}
|
||||
|
||||
# ─────────────── 主流程 ───────────────
|
||||
|
||||
Write-Host '== SnowCat 雪猫启动器 ==' -ForegroundColor Cyan
|
||||
|
||||
$found = Find-QQInstall -Override $QQPath
|
||||
if (-not $found) {
|
||||
if ($InstallIfMissing) {
|
||||
Write-Host '[!] 未发现 QQ。请从 https://im.qq.com 安装最新 QQNT,或下载 OneKey 便携包后重跑。' -ForegroundColor Yellow
|
||||
Write-Host ' (一键下载安装线待后续批次接入安装器)' -ForegroundColor Gray
|
||||
} else {
|
||||
Write-Host '[X] 未发现 QQ 安装。用 -InstallIfMissing 查看安装指引,或 -QQPath 指定。' -ForegroundColor Red
|
||||
}
|
||||
exit 1
|
||||
}
|
||||
|
||||
$ver = Get-QQRealVersion -QQExe $found.Path
|
||||
Write-Host ("[✓] QQ: {0} ({1})" -f $found.Path, $found.Source) -ForegroundColor Green
|
||||
Write-Host ("[✓] 版本: {0}" -f $ver.version) -ForegroundColor Green
|
||||
|
||||
# ─────────────── ③ 自动生成 qqnt.json(不钉版,写实况) ───────────────
|
||||
|
||||
$qqnt = [ordered]@{
|
||||
name = 'qq-chat'
|
||||
verHash = ''
|
||||
version = $ver.version
|
||||
linuxVersion = ''
|
||||
linuxVerHash = ''
|
||||
private = $true
|
||||
description = 'QQ'
|
||||
productName = 'QQ'
|
||||
author = @{ name = 'Tencent'; email = 'QQ-Team@tencent.com' }
|
||||
homepage = 'https://im.qq.com'
|
||||
sideEffects = $true
|
||||
bin = @{ qd = 'externals/devtools/cli/index.js' }
|
||||
main = './loadNapCat.js'
|
||||
# buildVersion 取版本号 '-' 后段(52892 形态);无则 0
|
||||
buildVersion = if ($ver.version -match '-(\d+)$') { $Matches[1] } else { '0' }
|
||||
isPureShell = $true
|
||||
isByteCodeShell = $true
|
||||
platform = 'win32'
|
||||
eleArch = 'x64'
|
||||
}
|
||||
$qqntPath = Join-Path $NapcatDir 'qqnt.json'
|
||||
[IO.File]::WriteAllText($qqntPath, ($qqnt | ConvertTo-Json -Depth 4), (New-Object System.Text.UTF8Encoding($false)))
|
||||
Write-Host "[✓] qqnt.json 已自动生成($qqntPath),版本=实况 $($ver.version)" -ForegroundColor Green
|
||||
|
||||
# loadNapCat.js 每次启动重新生成(官方 launcher 语义)
|
||||
$mainJs = (Join-Path $NapcatDir 'napcat.mjs').Replace('\', '/')
|
||||
|
||||
# ─────────────── ④ 判定注入目标(versions 分包结构 / 扁平结构) ───────────────
|
||||
# 9.9.27+ 的 OneKey 便携版把真正的 Electron 程序放进了 versions\<ver>\resources\app\,
|
||||
# 根目录不再有 resources\app\package.json。此前把 NAPCAT_PATCH_PACKAGE 固定指到根目录
|
||||
# qqnt.json,导致新版 QQ 读到的仍是原始入口,loadNapCat.js 从不执行(进程能起、插件不加载)。
|
||||
|
||||
$patchTarget = $qqntPath # 兜底:扁平结构,patch 根目录 qqnt.json
|
||||
$loadJs = Join-Path $NapcatDir 'loadNapCat.js'
|
||||
$layout = 'flat'
|
||||
|
||||
$versionsDir = Join-Path $NapcatDir 'versions'
|
||||
if (Test-Path $versionsDir) {
|
||||
$candidates = @()
|
||||
# 优先用实况版本号精确匹配,再退到 versions\config.json 的 curVersion
|
||||
if ($ver.version) { $candidates += (Join-Path $versionsDir "$($ver.version)\resources\app") }
|
||||
$cfgPath = Join-Path $versionsDir 'config.json'
|
||||
if (Test-Path $cfgPath) {
|
||||
try {
|
||||
$cur = (Get-Content $cfgPath -Raw | ConvertFrom-Json).curVersion
|
||||
if ($cur) { $candidates += (Join-Path $versionsDir "$cur\resources\app") }
|
||||
} catch {}
|
||||
}
|
||||
# 最后按目录名兜底(取版本号最大的一个)
|
||||
Get-ChildItem $versionsDir -Directory -ErrorAction SilentlyContinue |
|
||||
Sort-Object Name -Descending |
|
||||
ForEach-Object { $candidates += (Join-Path $_.FullName 'resources\app') }
|
||||
|
||||
foreach ($cand in ($candidates | Select-Object -Unique)) {
|
||||
$pkg = Join-Path $cand 'package.json'
|
||||
if (Test-Path $pkg) {
|
||||
$patchTarget = $pkg
|
||||
# loadNapCat.js 放到目标目录:main 里的相对路径 ./loadNapCat.js 才能解析
|
||||
$loadJs = Join-Path $cand 'loadNapCat.js'
|
||||
$layout = 'versions'
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# 首次接管真实 package.json 时留一份原始备份,便于回滚
|
||||
if ($layout -eq 'versions') {
|
||||
$orig = "$patchTarget.orig"
|
||||
if (-not (Test-Path $orig)) {
|
||||
Copy-Item $patchTarget $orig -Force
|
||||
Write-Host "[✓] 已备份原始 package.json → $orig" -ForegroundColor DarkGray
|
||||
}
|
||||
}
|
||||
|
||||
Set-Content $loadJs -Value "(async () => {await import(`"file:///$mainJs`")})()" -Encoding ASCII
|
||||
Write-Host ("[✓] 注入目标: {0}({1} 结构)" -f $patchTarget, $layout) -ForegroundColor Green
|
||||
|
||||
# ─────────────── 注入启动 ───────────────
|
||||
|
||||
$bootMain = Join-Path $NapcatDir 'NapCatWinBootMain.exe'
|
||||
$hook = Join-Path $NapcatDir 'NapCatWinBootHook.dll'
|
||||
if (-not (Test-Path $bootMain)) { Write-Host "[X] 缺 $bootMain" -ForegroundColor Red; exit 1 }
|
||||
|
||||
$env:NAPCAT_PATCH_PACKAGE = $patchTarget
|
||||
$env:NAPCAT_LOAD_PATH = $loadJs
|
||||
$env:NAPCAT_INJECT_PATH = $hook
|
||||
$env:NAPCAT_MAIN_PATH = $mainJs
|
||||
|
||||
Write-Host "[▶] 注入启动: NapCatWinBootMain → QQ -q$Account" -ForegroundColor Cyan
|
||||
& $bootMain $found.Path $hook "-q$Account"
|
||||
Reference in new issue
Block a user