implemennted downloader
This commit is contained in:
103
internal/processor/track.go
Normal file
103
internal/processor/track.go
Normal file
@@ -0,0 +1,103 @@
|
||||
package processor
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"os"
|
||||
|
||||
"gitea.mrixs.me/Mrixs/yamusic-bot/internal/interfaces"
|
||||
"gitea.mrixs.me/Mrixs/yamusic-bot/internal/model"
|
||||
"gitea.mrixs.me/Mrixs/yamusic-bot/internal/storage"
|
||||
)
|
||||
|
||||
// TrackProcessor инкапсулирует всю логику обработки одного трека.
|
||||
type TrackProcessor struct {
|
||||
storage interfaces.TrackStorage
|
||||
yandex interfaces.YandexMusicClient
|
||||
downloader interfaces.FileDownloader
|
||||
tagger interfaces.Tagger
|
||||
telegram interfaces.TelegramClient
|
||||
}
|
||||
|
||||
// NewTrackProcessor создает новый процессор.
|
||||
func NewTrackProcessor(
|
||||
storage interfaces.TrackStorage,
|
||||
yandex interfaces.YandexMusicClient,
|
||||
downloader interfaces.FileDownloader,
|
||||
tagger interfaces.Tagger,
|
||||
telegram interfaces.TelegramClient,
|
||||
) *TrackProcessor {
|
||||
return &TrackProcessor{
|
||||
storage: storage,
|
||||
yandex: yandex,
|
||||
downloader: downloader,
|
||||
tagger: tagger,
|
||||
telegram: telegram,
|
||||
}
|
||||
}
|
||||
|
||||
// Process получает информацию о треке, обрабатывает его (если нужно) и возвращает Telegram File ID.
|
||||
func (p *TrackProcessor) Process(ctx context.Context, trackInfo *model.TrackInfo) (string, error) {
|
||||
const op = "processor.TrackProcessor.Process"
|
||||
|
||||
// 1. Проверяем кэш в БД
|
||||
fileID, err := p.storage.Get(ctx, trackInfo.YandexTrackID)
|
||||
if err == nil {
|
||||
slog.Info("Cache hit", "track_id", trackInfo.YandexTrackID, "title", trackInfo.Title)
|
||||
return fileID, nil
|
||||
}
|
||||
|
||||
// Если ошибка - это не "не найдено", то это проблема
|
||||
if !errors.Is(err, storage.ErrNotFound) {
|
||||
return "", fmt.Errorf("%s: failed to get from storage: %w", op, err)
|
||||
}
|
||||
|
||||
// 2. Cache Miss: начинаем полный цикл обработки
|
||||
slog.Info("Cache miss, processing track", "track_id", trackInfo.YandexTrackID, "title", trackInfo.Title)
|
||||
|
||||
// 2a. Получаем URL для скачивания
|
||||
downloadURL, err := p.yandex.GetDownloadURL(ctx, trackInfo.YandexTrackID)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("%s: failed to get download url: %w", op, err)
|
||||
}
|
||||
trackInfo.DownloadURL = downloadURL
|
||||
|
||||
// 2b. Скачиваем аудиофайл и обложку
|
||||
audioPath, err := p.downloader.Download(ctx, trackInfo.DownloadURL)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("%s: failed to download audio: %w", op, err)
|
||||
}
|
||||
defer os.Remove(audioPath) // Гарантированное удаление временного аудиофайла
|
||||
|
||||
var coverPath string
|
||||
if trackInfo.CoverURL != "" {
|
||||
coverPath, err = p.downloader.Download(ctx, trackInfo.CoverURL)
|
||||
if err != nil {
|
||||
slog.Warn("Failed to download cover, proceeding without it", "url", trackInfo.CoverURL, "error", err)
|
||||
} else {
|
||||
defer os.Remove(coverPath) // Гарантированное удаление временной обложки
|
||||
}
|
||||
}
|
||||
|
||||
// 2c. Записываем теги
|
||||
if err := p.tagger.WriteTags(audioPath, coverPath, trackInfo); err != nil {
|
||||
// Не фатальная ошибка, просто логируем и продолжаем
|
||||
slog.Warn("Failed to write tags, proceeding without them", "track_id", trackInfo.YandexTrackID, "error", err)
|
||||
}
|
||||
|
||||
// 2d. Загружаем в Telegram (в кэш-канал)
|
||||
newFileID, err := p.telegram.SendAudioToCacheChannel(ctx, audioPath, trackInfo.Title, trackInfo.Artist)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("%s: failed to upload to telegram: %w", op, err)
|
||||
}
|
||||
|
||||
// 2e. Сохраняем в нашу БД
|
||||
if err := p.storage.Set(ctx, trackInfo.YandexTrackID, newFileID); err != nil {
|
||||
// Не фатальная ошибка для пользователя, но критичная для нас. Логируем как ошибку.
|
||||
slog.Error("Failed to save track to cache storage", "track_id", trackInfo.YandexTrackID, "error", err)
|
||||
}
|
||||
|
||||
return newFileID, nil
|
||||
}
|
||||
Reference in New Issue
Block a user