202 lines
6.5 KiB
Go
202 lines
6.5 KiB
Go
package app
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
|
|
"douyu_go/internal/logger"
|
|
"douyu_go/internal/types"
|
|
)
|
|
|
|
// ImportAccounts 将剪贴板中的账号行追加到账号文件。每行格式必须为
|
|
// 账号名----密码----Cookie,账号名不能与已有账号重复。
|
|
func (a *App) ImportAccounts(content string) types.AccountMutationResult {
|
|
entries, err := parseAccountImport(content)
|
|
if err != nil {
|
|
return types.AccountMutationResult{Error: err.Error()}
|
|
}
|
|
|
|
a.accountsMu.Lock()
|
|
defer a.accountsMu.Unlock()
|
|
|
|
accountFile := a.scheduler.AccountFilePath()
|
|
lines, err := parseAccountFile(accountFile)
|
|
if err != nil {
|
|
return types.AccountMutationResult{Error: "读取账号文件失败: " + err.Error()}
|
|
}
|
|
|
|
existingNames := make(map[string]struct{}, len(lines))
|
|
for _, line := range lines {
|
|
if line.Name != "" {
|
|
existingNames[line.Name] = struct{}{}
|
|
}
|
|
}
|
|
for _, entry := range entries {
|
|
if _, exists := existingNames[entry.Name]; exists {
|
|
return types.AccountMutationResult{Error: fmt.Sprintf("账号 %q 已存在", entry.Name)}
|
|
}
|
|
existingNames[entry.Name] = struct{}{}
|
|
lines = append(lines, entry)
|
|
}
|
|
|
|
if err := a.saveAccountLines(accountFile, lines); err != nil {
|
|
return types.AccountMutationResult{Error: err.Error()}
|
|
}
|
|
logger.LogEvent("账号", "success", "已从剪贴板导入 %d 个账号", len(entries))
|
|
return types.AccountMutationResult{Success: true, Count: len(entries)}
|
|
}
|
|
|
|
// UpdateAccount 更新账号名或 Cookie。newCookie 留空时保留文件中的原 Cookie。
|
|
func (a *App) UpdateAccount(originalName, newName, newCookie string) types.AccountMutationResult {
|
|
originalName = strings.TrimSpace(originalName)
|
|
newName = strings.TrimSpace(newName)
|
|
newCookie = strings.TrimSpace(newCookie)
|
|
if originalName == "" || newName == "" {
|
|
return types.AccountMutationResult{Error: "账号名不能为空"}
|
|
}
|
|
if invalidAccountField(newName) || strings.ContainsAny(newCookie, "\r\n") {
|
|
return types.AccountMutationResult{Error: "账号名或 Cookie 包含无效字符"}
|
|
}
|
|
|
|
a.accountsMu.Lock()
|
|
defer a.accountsMu.Unlock()
|
|
|
|
accountFile := a.scheduler.AccountFilePath()
|
|
lines, err := parseAccountFile(accountFile)
|
|
if err != nil {
|
|
return types.AccountMutationResult{Error: "读取账号文件失败: " + err.Error()}
|
|
}
|
|
|
|
targetIndex := -1
|
|
nameCount := 0
|
|
for i, line := range lines {
|
|
if line.Name == originalName {
|
|
targetIndex = i
|
|
nameCount++
|
|
}
|
|
if line.Name == newName && newName != originalName {
|
|
return types.AccountMutationResult{Error: fmt.Sprintf("账号 %q 已存在", newName)}
|
|
}
|
|
}
|
|
if targetIndex < 0 {
|
|
return types.AccountMutationResult{Error: "未找到要编辑的账号"}
|
|
}
|
|
if nameCount > 1 {
|
|
return types.AccountMutationResult{Error: "账号名重复,请先删除重复账号后再编辑"}
|
|
}
|
|
|
|
parts := strings.SplitN(strings.TrimSpace(lines[targetIndex].Raw), "----", 3)
|
|
if len(parts) != 3 {
|
|
return types.AccountMutationResult{Error: "原账号格式不正确,无法保留密码段"}
|
|
}
|
|
oldCookie := strings.TrimSpace(parts[2])
|
|
if newCookie == "" {
|
|
newCookie = oldCookie
|
|
}
|
|
if newCookie == "" {
|
|
return types.AccountMutationResult{Error: "Cookie 不能为空"}
|
|
}
|
|
lines[targetIndex] = accountLine{
|
|
Raw: newName + "----" + strings.TrimSpace(parts[1]) + "----" + newCookie,
|
|
Name: newName,
|
|
}
|
|
|
|
if err := a.saveAccountLines(accountFile, lines); err != nil {
|
|
return types.AccountMutationResult{Error: err.Error()}
|
|
}
|
|
logger.LogEvent("账号", "success", "账号已更新: %s", newName)
|
|
return types.AccountMutationResult{Success: true, Count: 1}
|
|
}
|
|
|
|
// DeleteAccounts 从账号文件中删除指定账号,可一次删除多个账号。
|
|
func (a *App) DeleteAccounts(accountNames []string) types.AccountMutationResult {
|
|
nameSet := make(map[string]struct{}, len(accountNames))
|
|
for _, name := range accountNames {
|
|
if trimmed := strings.TrimSpace(name); trimmed != "" {
|
|
nameSet[trimmed] = struct{}{}
|
|
}
|
|
}
|
|
if len(nameSet) == 0 {
|
|
return types.AccountMutationResult{Error: "请选择要删除的账号"}
|
|
}
|
|
|
|
a.accountsMu.Lock()
|
|
defer a.accountsMu.Unlock()
|
|
|
|
accountFile := a.scheduler.AccountFilePath()
|
|
lines, err := parseAccountFile(accountFile)
|
|
if err != nil {
|
|
return types.AccountMutationResult{Error: "读取账号文件失败: " + err.Error()}
|
|
}
|
|
kept := make([]accountLine, 0, len(lines))
|
|
deleted := 0
|
|
for _, line := range lines {
|
|
if _, remove := nameSet[line.Name]; remove && !line.Comment {
|
|
deleted++
|
|
continue
|
|
}
|
|
kept = append(kept, line)
|
|
}
|
|
if deleted == 0 {
|
|
return types.AccountMutationResult{Error: "未找到要删除的账号"}
|
|
}
|
|
|
|
if err := a.saveAccountLines(accountFile, kept); err != nil {
|
|
return types.AccountMutationResult{Error: err.Error()}
|
|
}
|
|
logger.LogEvent("账号", "success", "已删除 %d 个账号", deleted)
|
|
return types.AccountMutationResult{Success: true, Count: deleted}
|
|
}
|
|
|
|
func parseAccountImport(content string) ([]accountLine, error) {
|
|
content = strings.ReplaceAll(content, "\r\n", "\n")
|
|
content = strings.ReplaceAll(content, "\r", "\n")
|
|
entries := make([]accountLine, 0)
|
|
names := make(map[string]struct{})
|
|
for index, raw := range strings.Split(content, "\n") {
|
|
trimmed := strings.TrimSpace(raw)
|
|
if trimmed == "" || strings.HasPrefix(trimmed, "#") {
|
|
continue
|
|
}
|
|
parts := strings.SplitN(trimmed, "----", 3)
|
|
if len(parts) != 3 {
|
|
return nil, fmt.Errorf("第 %d 行格式不正确,应为 账号名----密码----Cookie", index+1)
|
|
}
|
|
name := strings.TrimSpace(parts[0])
|
|
password := strings.TrimSpace(parts[1])
|
|
cookie := strings.TrimSpace(parts[2])
|
|
if name == "" || cookie == "" || invalidAccountField(name) || strings.ContainsAny(cookie, "\r\n") {
|
|
return nil, fmt.Errorf("第 %d 行账号名或 Cookie 无效", index+1)
|
|
}
|
|
if _, exists := names[name]; exists {
|
|
return nil, fmt.Errorf("剪贴板中账号 %q 重复", name)
|
|
}
|
|
names[name] = struct{}{}
|
|
entries = append(entries, accountLine{Raw: name + "----" + password + "----" + cookie, Name: name})
|
|
}
|
|
if len(entries) == 0 {
|
|
return nil, fmt.Errorf("未识别到可导入的账号")
|
|
}
|
|
return entries, nil
|
|
}
|
|
|
|
func invalidAccountField(value string) bool {
|
|
return strings.ContainsAny(value, "\r\n") || strings.Contains(value, "----")
|
|
}
|
|
|
|
func (a *App) saveAccountLines(accountFile string, lines []accountLine) error {
|
|
rawLines := make([]string, 0, len(lines))
|
|
for _, line := range lines {
|
|
rawLines = append(rawLines, line.Raw)
|
|
}
|
|
content := strings.Join(rawLines, "\r\n")
|
|
if content != "" {
|
|
content += "\r\n"
|
|
}
|
|
if _, err := writeFileWithBackup(accountFile, []byte(content)); err != nil {
|
|
return fmt.Errorf("更新账号文件失败: %w", err)
|
|
}
|
|
a.scheduler.LoadAccounts()
|
|
return nil
|
|
}
|