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:
8
example.env
Normal file
8
example.env
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
TELEGRAM_BOT_TOKEN=aaa:bbb
|
||||||
|
TELEGRAM_ADMIN_IDS=ccc
|
||||||
|
TELEGRAM_CACHE_CHAT_ID=ddd
|
||||||
|
YANDEX_MUSIC_TOKEN=eee
|
||||||
|
DATABASE_PATH="/data/bot.db"
|
||||||
|
LOG_LEVEL="info"
|
||||||
|
PROCESSOR_WORKERS=4
|
||||||
|
YANDEX_API_RATE_LIMIT=5
|
||||||
@@ -4,6 +4,9 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log/slog"
|
"log/slog"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"gitea.mrixs.me/Mrixs/yamusic-bot/internal/interfaces"
|
"gitea.mrixs.me/Mrixs/yamusic-bot/internal/interfaces"
|
||||||
@@ -56,7 +59,8 @@ func (h *Handler) handleHelp(ctx context.Context, chatID int64) {
|
|||||||
"/help - Показать это сообщение\n" +
|
"/help - Показать это сообщение\n" +
|
||||||
"/stats - Показать статистику бота\n" +
|
"/stats - Показать статистику бота\n" +
|
||||||
"/find <yandex_track_id> - Найти трек в кэше по ID\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 {
|
if err := h.telegram.SendMessage(ctx, chatID, helpText); err != nil {
|
||||||
slog.Error("Failed to send help message", "error", err, "chat_id", chatID)
|
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) {
|
func (h *Handler) handleWarm(ctx context.Context, chatID int64, args string) {
|
||||||
if err := h.telegram.SendMessage(ctx, chatID, "Команда /warm находится в разработке."); err != nil {
|
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)
|
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