feat(admin): add cache warming from local directory via /warm --from-dir
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
@@ -4,6 +4,9 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"gitea.mrixs.me/Mrixs/yamusic-bot/internal/interfaces"
|
||||
@@ -56,7 +59,8 @@ func (h *Handler) handleHelp(ctx context.Context, chatID int64) {
|
||||
"/help - Показать это сообщение\n" +
|
||||
"/stats - Показать статистику бота\n" +
|
||||
"/find <yandex_track_id> - Найти трек в кэше по ID\n" +
|
||||
"/warm <URL> - \"Прогреть\" кэш для альбома или исполнителя (в разработке)"
|
||||
"/warm <URL> - \"Прогреть\" кэш для альбома или исполнителя (в разработке)\n" +
|
||||
"/warm --from-dir <path> - Прогреть кэш из локальной директории внутри контейнера"
|
||||
|
||||
if err := h.telegram.SendMessage(ctx, chatID, helpText); err != nil {
|
||||
slog.Error("Failed to send help message", "error", err, "chat_id", chatID)
|
||||
@@ -110,8 +114,93 @@ func (h *Handler) handleFind(ctx context.Context, chatID int64, trackID string)
|
||||
}
|
||||
}
|
||||
|
||||
func (h *Handler) handleWarm(ctx context.Context, chatID int64, url string) {
|
||||
if err := h.telegram.SendMessage(ctx, chatID, "Команда /warm находится в разработке."); err != nil {
|
||||
func (h *Handler) handleWarm(ctx context.Context, chatID int64, args string) {
|
||||
const fromDirPrefix = "--from-dir "
|
||||
if strings.HasPrefix(args, fromDirPrefix) {
|
||||
dirPath := strings.TrimPrefix(args, fromDirPrefix)
|
||||
h.handleWarmFromDir(ctx, chatID, dirPath)
|
||||
return
|
||||
}
|
||||
|
||||
// Здесь будет логика для прогрева по URL
|
||||
if err := h.telegram.SendMessage(ctx, chatID, "Прогрев по URL находится в разработке."); err != nil {
|
||||
slog.Error("Failed to send 'warm in development' message", "error", err, "chat_id", chatID)
|
||||
}
|
||||
}
|
||||
|
||||
// handleWarmFromDir запускает фоновую задачу прогрева кэша из локальной директории.
|
||||
func (h *Handler) handleWarmFromDir(ctx context.Context, chatID int64, dirPath string) {
|
||||
msg := fmt.Sprintf("Принято в обработку. Начинаю прогрев кэша из директории: `%s`", dirPath)
|
||||
if err := h.telegram.SendMessage(ctx, chatID, msg); err != nil {
|
||||
slog.Error("Failed to send 'warm from dir started' message", "error", err, "chat_id", chatID)
|
||||
return
|
||||
}
|
||||
|
||||
go func() {
|
||||
slog.Info("Starting cache warming from directory", "path", dirPath)
|
||||
files, err := os.ReadDir(dirPath)
|
||||
if err != nil {
|
||||
slog.Error("Failed to read directory for warming", "path", dirPath, "error", err)
|
||||
errMsg := fmt.Sprintf("Ошибка: не удалось прочитать директорию `%s`. Убедитесь, что она существует и доступна.", dirPath)
|
||||
_ = h.telegram.SendMessage(context.Background(), chatID, errMsg)
|
||||
return
|
||||
}
|
||||
|
||||
var addedCount, skippedCount, errorCount int
|
||||
totalFiles := len(files)
|
||||
|
||||
for i, file := range files {
|
||||
if file.IsDir() || !strings.HasSuffix(file.Name(), ".mp3") {
|
||||
continue
|
||||
}
|
||||
|
||||
trackID := strings.TrimSuffix(file.Name(), ".mp3")
|
||||
fullPath := filepath.Join(dirPath, file.Name())
|
||||
|
||||
// 1. Проверяем, есть ли трек в кэше
|
||||
_, err := h.storage.Get(ctx, trackID)
|
||||
if err == nil {
|
||||
slog.Debug("Skipping already cached track", "track_id", trackID)
|
||||
skippedCount++
|
||||
continue
|
||||
}
|
||||
|
||||
// 2. Загружаем в Telegram
|
||||
// Поскольку метатеги уже вшиты, для отображения в кэш-канале можно использовать простые title/performer
|
||||
slog.Debug("Uploading track to cache channel", "track_id", trackID, "path", fullPath)
|
||||
fileID, err := h.telegram.SendAudioToCacheChannel(ctx, fullPath, trackID, "Pre-cached")
|
||||
if err != nil {
|
||||
slog.Error("Failed to upload pre-cached file", "track_id", trackID, "error", err)
|
||||
errorCount++
|
||||
continue
|
||||
}
|
||||
|
||||
// 3. Сохраняем в БД
|
||||
err = h.storage.Set(ctx, trackID, fileID)
|
||||
if err != nil {
|
||||
slog.Error("Failed to save pre-cached file to storage", "track_id", trackID, "error", err)
|
||||
errorCount++
|
||||
continue
|
||||
}
|
||||
|
||||
addedCount++
|
||||
slog.Info("Successfully cached track from local file", "track_id", trackID, "file_id", fileID)
|
||||
|
||||
// Опционально: отправляем прогресс каждые N файлов
|
||||
if (i+1)%1000 == 0 {
|
||||
progressMsg := fmt.Sprintf("Прогресс: обработано %d из %d файлов...", i+1, totalFiles)
|
||||
_ = h.telegram.SendMessage(context.Background(), chatID, progressMsg)
|
||||
}
|
||||
}
|
||||
|
||||
finalMsg := fmt.Sprintf(
|
||||
"✅ Прогрев кэша из директории `%s` завершен.\n\n"+
|
||||
"Новых треков добавлено: %d\n"+
|
||||
"Треков пропущено (уже в кэше): %d\n"+
|
||||
"Ошибок при обработке: %d",
|
||||
dirPath, addedCount, skippedCount, errorCount,
|
||||
)
|
||||
_ = h.telegram.SendMessage(context.Background(), chatID, finalMsg)
|
||||
slog.Info("Finished cache warming from directory", "path", dirPath, "added", addedCount, "skipped", skippedCount, "errors", errorCount)
|
||||
}()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user