package service import ( "context" "fmt" "strings" "gorm.io/gorm" "github.com/ShukeBta/MediaStationGo/internal/model" ) // cmdStatus 处理 /status 命令。 func (s *TelegramBotService) cmdStatus(ctx context.Context) (telegramCommandReply, error) { libraryIDs, err := s.activeTelegramStatsLibraryIDs(ctx) if err != nil { return telegramCommandReply{}, err } var mediaCount int64 s.mediaStatsQuery(libraryIDs).Count(&mediaCount) var totalSize int64 if err := s.mediaStatsQuery(libraryIDs).Select("COALESCE(SUM(size_bytes), 0)").Row().Scan(&totalSize); err != nil { return telegramCommandReply{}, err } totalSizeGB := float64(totalSize) / 1024 / 1024 / 1024 return telegramCommandReply{Text: fmt.Sprintf( "系统运行状态\n\n"+ "🎬 媒体总数: %d\n"+ "💾 存储占用: %.1f GB", mediaCount, totalSizeGB, )}, nil } // cmdSearch 处理 /search 命令。 func (s *TelegramBotService) cmdSearch(ctx context.Context, args []string) (telegramCommandReply, error) { if len(args) == 0 { return telegramCommandReply{Text: "请提供搜索关键词\n例: /search 哥斯拉"}, nil } keyword := strings.Join(args, " ") var results []model.Media err := s.repo.DB.Where("title LIKE ?", "%"+keyword+"%"). Order("year DESC").Limit(8). Find(&results).Error if err != nil { return telegramCommandReply{}, err } if len(results) == 0 { return telegramCommandReply{Text: fmt.Sprintf("未找到与 %s 相关的媒体", keyword)}, nil } var sb strings.Builder sb.WriteString(fmt.Sprintf("搜索: %s\n\n", keyword)) for i, m := range results { year := "" if m.Year > 0 { year = fmt.Sprintf(" (%d)", m.Year) } ep := "" if m.SeasonNum > 0 && m.EpisodeNum > 0 { ep = fmt.Sprintf(" S%02dE%02d", m.SeasonNum, m.EpisodeNum) } sb.WriteString(fmt.Sprintf("%d. %s%s%s — %s\n", i+1, m.Title, year, ep, formatSize(m.SizeBytes))) } return telegramCommandReply{Text: sb.String()}, nil } // cmdDownloads 处理 /downloads 命令。 func (s *TelegramBotService) cmdDownloads(ctx context.Context) (telegramCommandReply, error) { type Row struct { Title string Status string } var rows []Row if err := s.repo.DB.Raw( "SELECT COALESCE(NULLIF(title,''),'下载任务') as title, COALESCE(status,'unknown') as status FROM download_tasks ORDER BY created_at DESC LIMIT 8", ).Scan(&rows).Error; err != nil { return telegramCommandReply{}, err } if len(rows) == 0 { return telegramCommandReply{Text: "当前没有下载任务。"}, nil } var sb strings.Builder sb.WriteString(fmt.Sprintf("下载任务 (%d)\n\n", len(rows))) for _, r := range rows { icon := "⏳" switch r.Status { case "completed": icon = "✅" case "downloading": icon = "📥" case "error": icon = "❌" } name := strings.TrimSpace(r.Title) if name == "" { name = "下载任务" } if len(name) > 60 { name = name[:57] + "..." } sb.WriteString(fmt.Sprintf("%s %s\n", icon, name)) } return telegramCommandReply{Text: sb.String()}, nil } // cmdStats 处理 /stats 命令。 func (s *TelegramBotService) cmdStats(ctx context.Context) (telegramCommandReply, error) { libs, err := s.activeTelegramStatsLibraries(ctx) if err != nil { return telegramCommandReply{}, err } libraryIDs := make([]string, 0, len(libs)) for _, lib := range libs { libraryIDs = append(libraryIDs, lib.ID) } var totalMedia int64 s.mediaStatsQuery(libraryIDs).Count(&totalMedia) var totalSize int64 if err := s.mediaStatsQuery(libraryIDs).Select("COALESCE(SUM(size_bytes), 0)").Row().Scan(&totalSize); err != nil { return telegramCommandReply{}, err } type LibStat struct { Name string Type string Count int64 } stats := make([]LibStat, 0, len(libs)) for _, lib := range libs { var count int64 if err := s.repo.DB.WithContext(ctx).Model(&model.Media{}).Where("library_id = ?", lib.ID).Count(&count).Error; err != nil { return telegramCommandReply{}, err } stats = append(stats, LibStat{Name: lib.Name, Type: lib.Type, Count: count}) } var sb strings.Builder sb.WriteString("媒体库统计\n\n") sb.WriteString(fmt.Sprintf("📚 总数: %d\n", totalMedia)) sb.WriteString(fmt.Sprintf("💾 大小: %s\n", formatSize(totalSize))) if len(stats) > 0 { sb.WriteString("\n各库分布:\n") for _, l := range stats { icon := "🎬" switch l.Type { case "tv": icon = "📺" case "anime": icon = "🍥" case "music": icon = "🎵" } sb.WriteString(fmt.Sprintf("%s %s: %d\n", icon, l.Name, l.Count)) } } return telegramCommandReply{Text: sb.String()}, nil } func (s *TelegramBotService) activeTelegramStatsLibraries(ctx context.Context) ([]model.Library, error) { if s == nil || s.repo == nil || s.repo.Library == nil { return nil, nil } libs, err := s.repo.Library.List(ctx) if err != nil { return nil, err } libs = FilterDisplayCloudLibraries(ctx, s.repo, libs) out := libs[:0] for _, lib := range libs { if lib.Enabled { out = append(out, lib) } } return out, nil } func (s *TelegramBotService) activeTelegramStatsLibraryIDs(ctx context.Context) ([]string, error) { libs, err := s.activeTelegramStatsLibraries(ctx) if err != nil { return nil, err } ids := make([]string, 0, len(libs)) for _, lib := range libs { ids = append(ids, lib.ID) } return ids, nil } func (s *TelegramBotService) mediaStatsQuery(libraryIDs []string) *gorm.DB { q := s.repo.DB.Model(&model.Media{}) if len(libraryIDs) == 0 { return q.Where("1 = 0") } return q.Where("library_id IN ?", libraryIDs) } // formatSize 格式化字节数为可读字符串。 func formatSize(bytes int64) string { if bytes <= 0 { return "0 B" } units := []string{"B", "KB", "MB", "GB", "TB"} v := float64(bytes) i := 0 for v >= 1024 && i < len(units)-1 { v /= 1024 i++ } if i == 0 { return fmt.Sprintf("%.0f %s", v, units[i]) } return fmt.Sprintf("%.1f %s", v, units[i]) }