v0.1.0: 新增CK管理功能
功能: - 新增CK管理页面,支持复验抢购结果和整理账号文件 - 复验功能:查询斗鱼真实兑换记录,统计已抢到/未抢到的账号 - 整理CK功能:分离已抢到的账号到新文件,原文件只保留未抢到的 - 导出文件名优化:使用中文商品名+日期时间格式(如:user_已抢到_雪国2号_20260626_150405.txt) - 复用左侧商品选择,统一数据源 接口: - VerifyAndExport: 复验并统计 - ExportAccountsWithProduct: 导出账号(自动命名) - OrganizeAccounts: 整理账号文件 版本: 0.1.0
This commit is contained in:
@@ -1,9 +1,13 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
@@ -286,6 +290,247 @@ func (a *App) VerifyAllExchange() map[string]any {
|
||||
return results
|
||||
}
|
||||
|
||||
// VerifyAndExport 复验并导出结果。
|
||||
func (a *App) VerifyAndExport(commodityID string) map[string]any {
|
||||
accounts := a.scheduler.AccountSnapshot()
|
||||
results := make(map[string]any)
|
||||
hitAccounts := make([]string, 0)
|
||||
missAccounts := make([]string, 0)
|
||||
|
||||
for i, account := range accounts {
|
||||
if i > 0 {
|
||||
time.Sleep(200 * time.Millisecond)
|
||||
}
|
||||
|
||||
if account.Cookie == "" {
|
||||
missAccounts = append(missAccounts, account.Name)
|
||||
results[account.Name] = map[string]any{
|
||||
"success": false,
|
||||
"error": "Cookie 为空",
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
records, err := a.client.ExchangeList(account.Cookie)
|
||||
if err != nil {
|
||||
missAccounts = append(missAccounts, account.Name)
|
||||
results[account.Name] = map[string]any{
|
||||
"success": false,
|
||||
"error": "查询失败: " + err.Error(),
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
// 检查是否抢到了指定商品
|
||||
hit := false
|
||||
for _, r := range records {
|
||||
if r.CommodityID == commodityID {
|
||||
hit = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if hit {
|
||||
hitAccounts = append(hitAccounts, account.Name)
|
||||
results[account.Name] = map[string]any{
|
||||
"success": true,
|
||||
"hit": true,
|
||||
}
|
||||
} else {
|
||||
missAccounts = append(missAccounts, account.Name)
|
||||
results[account.Name] = map[string]any{
|
||||
"success": true,
|
||||
"hit": false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return map[string]any{
|
||||
"success": true,
|
||||
"hitCount": len(hitAccounts),
|
||||
"missCount": len(missAccounts),
|
||||
"hitAccounts": hitAccounts,
|
||||
"missAccounts": missAccounts,
|
||||
"details": results,
|
||||
}
|
||||
}
|
||||
|
||||
// ExportAccounts 导出指定账号到文件。
|
||||
func (a *App) ExportAccounts(accountNames []string, filename string) map[string]any {
|
||||
if len(accountNames) == 0 {
|
||||
return map[string]any{"success": false, "error": "没有要导出的账号"}
|
||||
}
|
||||
|
||||
// 读取原账号文件
|
||||
accountFile := a.scheduler.AccountFilePath()
|
||||
lines, err := os.ReadFile(accountFile)
|
||||
if err != nil {
|
||||
return map[string]any{"success": false, "error": "读取账号文件失败: " + err.Error()}
|
||||
}
|
||||
|
||||
// 解析账号行
|
||||
nameSet := make(map[string]bool)
|
||||
for _, name := range accountNames {
|
||||
nameSet[name] = true
|
||||
}
|
||||
|
||||
var matchedLines []string
|
||||
scanner := bufio.NewScanner(strings.NewReader(string(lines)))
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
trimmed := strings.TrimSpace(line)
|
||||
if trimmed == "" || strings.HasPrefix(trimmed, "#") {
|
||||
continue
|
||||
}
|
||||
parts := strings.SplitN(trimmed, "----", 3)
|
||||
if len(parts) >= 1 {
|
||||
name := strings.TrimSpace(parts[0])
|
||||
if nameSet[name] {
|
||||
matchedLines = append(matchedLines, line)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(matchedLines) == 0 {
|
||||
return map[string]any{"success": false, "error": "没有找到匹配的账号行"}
|
||||
}
|
||||
|
||||
// 生成导出文件路径
|
||||
exportPath := filepath.Join(filepath.Dir(accountFile), filename)
|
||||
content := strings.Join(matchedLines, "\n") + "\n"
|
||||
|
||||
if err := os.WriteFile(exportPath, []byte(content), 0644); err != nil {
|
||||
return map[string]any{"success": false, "error": "写入文件失败: " + err.Error()}
|
||||
}
|
||||
|
||||
logger.LogEvent("导出", "success", "已导出 %d 个账号到: %s", len(matchedLines), exportPath)
|
||||
|
||||
return map[string]any{
|
||||
"success": true,
|
||||
"count": len(matchedLines),
|
||||
"filePath": exportPath,
|
||||
}
|
||||
}
|
||||
|
||||
// ExportAccountsWithProduct 导出指定账号到文件,自动使用中文商品名和时间戳命名。
|
||||
func (a *App) ExportAccountsWithProduct(accountNames []string, commodityID, commodityName string) map[string]any {
|
||||
// 生成文件名: user_已抢到_商品中文名_20260626_150405.txt
|
||||
now := time.Now()
|
||||
timestamp := now.Format("20060102_150405")
|
||||
// 清理商品名中的特殊字符
|
||||
safeName := strings.ReplaceAll(commodityName, "/", "_")
|
||||
safeName = strings.ReplaceAll(safeName, "\\", "_")
|
||||
safeName = strings.ReplaceAll(safeName, ":", "_")
|
||||
safeName = strings.ReplaceAll(safeName, "*", "_")
|
||||
safeName = strings.ReplaceAll(safeName, "?", "_")
|
||||
safeName = strings.ReplaceAll(safeName, "\"", "_")
|
||||
safeName = strings.ReplaceAll(safeName, "<", "_")
|
||||
safeName = strings.ReplaceAll(safeName, ">", "_")
|
||||
safeName = strings.ReplaceAll(safeName, "|", "_")
|
||||
filename := fmt.Sprintf("user_已抢到_%s_%s.txt", safeName, timestamp)
|
||||
|
||||
return a.ExportAccounts(accountNames, filename)
|
||||
}
|
||||
|
||||
// OrganizeAccounts 整理账号,把已抢到指定商品的账号分离出来。
|
||||
func (a *App) OrganizeAccounts(commodityID, commodityName string, startTime, endTime int64) map[string]any {
|
||||
accounts := a.scheduler.AccountSnapshot()
|
||||
hitAccounts := make([]string, 0)
|
||||
missAccounts := make([]string, 0)
|
||||
|
||||
for i, account := range accounts {
|
||||
if i > 0 {
|
||||
time.Sleep(200 * time.Millisecond)
|
||||
}
|
||||
|
||||
if account.Cookie == "" {
|
||||
missAccounts = append(missAccounts, account.Name)
|
||||
continue
|
||||
}
|
||||
|
||||
records, err := a.client.ExchangeList(account.Cookie)
|
||||
if err != nil {
|
||||
missAccounts = append(missAccounts, account.Name)
|
||||
continue
|
||||
}
|
||||
|
||||
// 检查是否在指定时间段内抢到了指定商品
|
||||
hit := false
|
||||
for _, r := range records {
|
||||
if r.CommodityID == commodityID {
|
||||
// 检查时间范围
|
||||
recordTime, _ := strconv.ParseInt(r.Time, 10, 64)
|
||||
if startTime == 0 || (recordTime >= startTime && recordTime <= endTime) {
|
||||
hit = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if hit {
|
||||
hitAccounts = append(hitAccounts, account.Name)
|
||||
} else {
|
||||
missAccounts = append(missAccounts, account.Name)
|
||||
}
|
||||
}
|
||||
|
||||
// 导出已抢到的账号
|
||||
var exportResult map[string]any
|
||||
if len(hitAccounts) > 0 {
|
||||
exportResult = a.ExportAccountsWithProduct(hitAccounts, commodityID, commodityName)
|
||||
}
|
||||
|
||||
// 更新原文件,只保留未抢到的
|
||||
accountFile := a.scheduler.AccountFilePath()
|
||||
lines, err := os.ReadFile(accountFile)
|
||||
if err != nil {
|
||||
return map[string]any{"success": false, "error": "读取账号文件失败: " + err.Error()}
|
||||
}
|
||||
|
||||
missSet := make(map[string]bool)
|
||||
for _, name := range missAccounts {
|
||||
missSet[name] = true
|
||||
}
|
||||
|
||||
var keepLines []string
|
||||
scanner := bufio.NewScanner(strings.NewReader(string(lines)))
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
trimmed := strings.TrimSpace(line)
|
||||
if trimmed == "" || strings.HasPrefix(trimmed, "#") {
|
||||
keepLines = append(keepLines, line)
|
||||
continue
|
||||
}
|
||||
parts := strings.SplitN(trimmed, "----", 3)
|
||||
if len(parts) >= 1 {
|
||||
name := strings.TrimSpace(parts[0])
|
||||
if missSet[name] {
|
||||
keepLines = append(keepLines, line)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 写回原文件
|
||||
newContent := strings.Join(keepLines, "\n") + "\n"
|
||||
if err := os.WriteFile(accountFile, []byte(newContent), 0644); err != nil {
|
||||
return map[string]any{"success": false, "error": "更新账号文件失败: " + err.Error()}
|
||||
}
|
||||
|
||||
// 重新加载账号
|
||||
a.scheduler.LoadAccounts()
|
||||
|
||||
logger.LogEvent("整理", "success", "整理完成: 已抢到=%d, 未抢到=%d", len(hitAccounts), len(missAccounts))
|
||||
|
||||
return map[string]any{
|
||||
"success": true,
|
||||
"hitCount": len(hitAccounts),
|
||||
"missCount": len(missAccounts),
|
||||
"hitAccounts": hitAccounts,
|
||||
"missAccounts": missAccounts,
|
||||
"exportResult": exportResult,
|
||||
}
|
||||
}
|
||||
|
||||
// GetVersion 返回应用版本号。
|
||||
func (a *App) GetVersion() string {
|
||||
return constants.Version
|
||||
|
||||
Reference in New Issue
Block a user