From ee5e7d2586893f8e6bae10d891d5bfe0cd804ce2 Mon Sep 17 00:00:00 2001 From: hicccc77 <98377878+hicccc77@users.noreply.github.com> Date: Sun, 29 Mar 2026 16:07:09 +0800 Subject: [PATCH 1/2] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E5=BE=AE=E4=BF=A1?= =?UTF-8?q?=E9=87=8D=E8=A3=85=E5=90=8E=20openMessageCursor=20=E8=BF=94?= =?UTF-8?q?=E5=9B=9E=20-3=20(no=20message=20db)=20=E7=9A=84=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 forceReopen() 方法:清空路径缓存后强制重新初始化账号连接 - openMessageCursor 在 result=-3 时自动触发 forceReopen 并重试一次 - 改善 -3 错误的提示文案,引导用户重新指定数据目录 修复 #591 --- electron/services/wcdbCore.ts | 49 +++++++++++++++++++++++++++++++++-- 1 file changed, 47 insertions(+), 2 deletions(-) diff --git a/electron/services/wcdbCore.ts b/electron/services/wcdbCore.ts index df535fa..4f0d97b 100644 --- a/electron/services/wcdbCore.ts +++ b/electron/services/wcdbCore.ts @@ -2596,13 +2596,34 @@ export class WcdbCore { } } + /** + * 强制重新打开账号连接(绕过路径缓存),用于微信重装后消息数据库刷新失败时的自动恢复。 + * 返回重新打开是否成功。 + */ + private async forceReopen(): Promise { + if (!this.currentPath || !this.currentKey || !this.currentWxid) return false + const path = this.currentPath + const key = this.currentKey + const wxid = this.currentWxid + this.writeLog('forceReopen: clearing cached handle and reopening...', true) + // 清空缓存状态,让 open() 真正重新打开 + try { this.wcdbShutdown() } catch { } + this.handle = null + this.currentPath = null + this.currentKey = null + this.currentWxid = null + this.currentDbStoragePath = null + this.initialized = false + return this.open(path, key, wxid) + } + async openMessageCursor(sessionId: string, batchSize: number, ascending: boolean, beginTimestamp: number, endTimestamp: number): Promise<{ success: boolean; cursor?: number; error?: string }> { if (!this.ensureReady()) { return { success: false, error: 'WCDB 未连接' } } try { const outCursor = [0] - const result = this.wcdbOpenMessageCursor( + let result = this.wcdbOpenMessageCursor( this.handle, sessionId, batchSize, @@ -2611,13 +2632,37 @@ export class WcdbCore { endTimestamp, outCursor ) + // result=-3 表示 WCDB_STATUS_NO_MESSAGE_DB:消息数据库缓存为空(常见于微信重装后) + // 自动强制重连并重试一次 + if (result === -3 && outCursor[0] <= 0) { + this.writeLog('openMessageCursor: result=-3 (no message db), attempting forceReopen...', true) + const reopened = await this.forceReopen() + if (reopened && this.handle !== null) { + outCursor[0] = 0 + result = this.wcdbOpenMessageCursor( + this.handle, + sessionId, + batchSize, + ascending ? 1 : 0, + beginTimestamp, + endTimestamp, + outCursor + ) + this.writeLog(`openMessageCursor retry after forceReopen: result=${result} cursor=${outCursor[0]}`, true) + } else { + this.writeLog('openMessageCursor forceReopen failed, giving up', true) + } + } if (result !== 0 || outCursor[0] <= 0) { await this.printLogs(true) this.writeLog( `openMessageCursor failed: sessionId=${sessionId} batchSize=${batchSize} ascending=${ascending ? 1 : 0} begin=${beginTimestamp} end=${endTimestamp} result=${result} cursor=${outCursor[0]}`, true ) - return { success: false, error: `创建游标失败: ${result},请查看日志` } + const hint = result === -3 + ? `创建游标失败: ${result}(消息数据库未找到)。如果你最近重装过微信,请尝试重新指定数据目录后重试` + : `创建游标失败: ${result},请查看日志` + return { success: false, error: hint } } return { success: true, cursor: outCursor[0] } } catch (e) { From 93b55fe370e4a9ba017c155dca6a1be659f145b5 Mon Sep 17 00:00:00 2001 From: hicccc77 <98377878+hicccc77@users.noreply.github.com> Date: Sun, 29 Mar 2026 23:18:24 +0800 Subject: [PATCH 2/2] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=20anti-spam=20wo?= =?UTF-8?q?rkflow=EF=BC=8C=E8=87=AA=E5=8A=A8=E6=A3=80=E6=B5=8B=E5=B9=B6?= =?UTF-8?q?=E5=85=B3=E9=97=AD=E5=9E=83=E5=9C=BE=20issue?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/anti-spam.yml | 134 ++++++++++++++++++++++++++++++++ 1 file changed, 134 insertions(+) create mode 100644 .github/workflows/anti-spam.yml diff --git a/.github/workflows/anti-spam.yml b/.github/workflows/anti-spam.yml new file mode 100644 index 0000000..5fdd21c --- /dev/null +++ b/.github/workflows/anti-spam.yml @@ -0,0 +1,134 @@ +name: Anti-Spam + +on: + issues: + types: [opened, edited] + +permissions: + issues: write + +jobs: + check-spam: + runs-on: ubuntu-latest + steps: + - name: Check for spam + uses: actions/github-script@v7 + with: + script: | + const issue = context.payload.issue; + const title = (issue.title || '').toLowerCase(); + const body = (issue.body || '').toLowerCase(); + const text = title + ' ' + body; + + // 博彩/赌球类 + const gamblingPatterns = [ + /世界杯.*买球/, /买球.*世界杯/, + /世界杯.*下注/, /世界杯.*竞猜/, + /世界杯.*投注/, /世界杯.*押注/, + /世界杯.*彩票/, /世界杯.*平台/, + /世界杯.*app/, /世界杯.*软件/, + /世界杯.*网站/, /世界杯.*网址/, + /足球.*买球/, /买球.*足球/, + /足球.*投注/, /足球.*押注/, + /足球.*竞猜/, /足球.*平台/, + /篮球.*买球/, /篮球.*投注/, + /体育.*投注/, /体育.*竞猜/, + /体育.*买球/, /体育.*押注/, + /赌球/, /赌博.*网站/, /赌博.*平台/, + /博彩/, /博彩.*网站/, /博彩.*平台/, + /正规.*买球/, /官方.*买球/, + /买球.*网站/, /买球.*app/, + /买球.*软件/, /买球.*网址/, + /买球.*平台/, /买球.*技巧/, + /投注.*网站/, /投注.*平台/, + /押注.*网站/, /押注.*平台/, + /竞猜.*网站/, /竞猜.*平台/, + /彩票.*网站/, /彩票.*平台/, + /欧洲杯.*买球/, /欧冠.*买球/, + /nba.*买球/, /nba.*投注/, + ]; + + // 色情/交友类 + const adultPatterns = [ + /约炮/, /一夜情/, /外围/, + /包养/, /援交/, /陪聊/, + /成人.*网站/, /成人.*视频/, + /av.*网站/, /黄色.*网站/, + ]; + + // 贷款/金融诈骗类 + const financePatterns = [ + /秒到账.*贷款/, /无抵押.*贷款/, + /征信.*贷款/, /黑户.*贷款/, + /快速.*放款/, /私人.*放贷/, + /刷单/, /兼职.*日入/, /兼职.*月入/, + /网赚/, /躺赚/, /被动收入.*平台/, + /虚拟货币.*投资/, /usdt.*投资/, + /炒币.*平台/, /数字货币.*平台/, + ]; + + // 垃圾推广类 + const spamPromoPatterns = [ + /代刷/, /粉丝.*购买/, /涨粉/, + /seo.*优化/, /快速排名/, + /微商/, /代理.*招募/, + ]; + + // 账号特征检测(新账号 + 无 contribution) + const allPatterns = [ + ...gamblingPatterns, + ...adultPatterns, + ...financePatterns, + ...spamPromoPatterns, + ]; + + const isSpam = allPatterns.some(pattern => pattern.test(text)); + + // 额外检测:标题超短且含可疑关键词(常见于批量刷单) + const suspiciousShort = title.length < 10 && /(买球|投注|博彩|赌博|下注|押注)/.test(title); + + if (isSpam || suspiciousShort) { + // 确保 spam label 存在 + try { + await github.rest.issues.createLabel({ + owner: context.repo.owner, + repo: context.repo.repo, + name: 'spam', + color: 'e4e669', + description: 'Spam issue' + }); + } catch (e) { + // label 已存在,忽略 + } + + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: issue.number, + body: '此 issue 已被自动识别为垃圾内容并关闭。\n\nThis issue has been automatically identified as spam and closed.' + }); + + await github.rest.issues.addLabels({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: issue.number, + labels: ['spam'] + }); + + await github.rest.issues.update({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: issue.number, + state: 'closed', + state_reason: 'not_planned' + }); + + await github.rest.issues.lock({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: issue.number, + lock_reason: 'spam' + }); + + console.log(`Closed spam issue #${issue.number}: ${issue.title}`); + }