contracts and models
This commit is contained in:
56
internal/config/config.go
Normal file
56
internal/config/config.go
Normal file
@@ -0,0 +1,56 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"strings"
|
||||
|
||||
"github.com/caarlos0/env/v10"
|
||||
)
|
||||
|
||||
// Config содержит всю конфигурацию приложения, получаемую из переменных окружения.
|
||||
type Config struct {
|
||||
TelegramBotToken string `env:"TELEGRAM_BOT_TOKEN,required"`
|
||||
TelegramAdminIDsRaw string `env:"TELEGRAM_ADMIN_IDS,required"`
|
||||
TelegramCacheChatID int64 `env:"TELEGRAM_CACHE_CHAT_ID,required"`
|
||||
YandexMusicToken string `env:"YANDEX_MUSIC_TOKEN"`
|
||||
DatabasePath string `env:"DATABASE_PATH" envDefault:"/data/bot.db"`
|
||||
LogLevel string `env:"LOG_LEVEL" envDefault:"info"`
|
||||
ProcessorWorkers int `env:"PROCESSOR_WORKERS" envDefault:"4"`
|
||||
YandexAPIRateLimit int `env:"YANDEX_API_RATE_LIMIT" envDefault:"5"`
|
||||
TelegramAdminIDs []int64 `env:"-"` // Это поле будет заполнено после парсинга
|
||||
}
|
||||
|
||||
// New загружает конфигурацию из переменных окружения и парсит необходимые поля.
|
||||
func New() *Config {
|
||||
cfg := &Config{}
|
||||
if err := env.Parse(cfg); err != nil {
|
||||
log.Fatalf("failed to parse config: %+v", err)
|
||||
}
|
||||
|
||||
// Парсим ID администраторов из строки
|
||||
if cfg.TelegramAdminIDsRaw != "" {
|
||||
ids := strings.Split(cfg.TelegramAdminIDsRaw, ",")
|
||||
cfg.TelegramAdminIDs = make([]int64, 0, len(ids))
|
||||
for _, idStr := range ids {
|
||||
var id int64
|
||||
if _, err := Sscanf(strings.TrimSpace(idStr), "%d", &id); err == nil {
|
||||
cfg.TelegramAdminIDs = append(cfg.TelegramAdminIDs, id)
|
||||
} else {
|
||||
log.Printf("warning: could not parse admin ID: %s", idStr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(cfg.TelegramAdminIDs) == 0 {
|
||||
log.Fatalf("no valid admin IDs provided in TELEGRAM_ADMIN_IDS")
|
||||
}
|
||||
|
||||
return cfg
|
||||
}
|
||||
|
||||
// Sscanf - простая реализация для парсинга, чтобы избежать лишних зависимостей.
|
||||
// В стандартной библиотеке fmt.Sscanf требует, чтобы вся строка была разобрана.
|
||||
func Sscanf(str, format string, a ...interface{}) (int, error) {
|
||||
return fmt.Sscanf(str, format, a...)
|
||||
}
|
||||
42
internal/interfaces/interfaces.go
Normal file
42
internal/interfaces/interfaces.go
Normal file
@@ -0,0 +1,42 @@
|
||||
package interfaces
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"gitea.mrixs.me/Mrixs/yamusic-bot/internal/model"
|
||||
)
|
||||
|
||||
// YandexMusicClient определяет методы для взаимодействия с API Yandex.Music.
|
||||
type YandexMusicClient interface {
|
||||
GetTrackInfo(ctx context.Context, trackID string) (*model.TrackInfo, error)
|
||||
GetAlbumTrackInfos(ctx context.Context, albumID string) ([]*model.TrackInfo, error)
|
||||
GetArtistTrackInfos(ctx context.Context, artistID string) ([]*model.TrackInfo, error)
|
||||
GetDownloadURL(ctx context.Context, trackID string) (string, error)
|
||||
}
|
||||
|
||||
// TrackStorage определяет методы для работы с постоянным кэшем.
|
||||
type TrackStorage interface {
|
||||
Get(ctx context.Context, yandexTrackID string) (telegramFileID string, err error)
|
||||
Set(ctx context.Context, yandexTrackID, telegramFileID string) error
|
||||
Count(ctx context.Context) (int, error)
|
||||
Close() error
|
||||
}
|
||||
|
||||
// TelegramClient определяет методы для взаимодействия с Telegram Bot API.
|
||||
// Мы определяем свой интерфейс, чтобы не зависеть напрямую от библиотеки
|
||||
// и упростить тестирование.
|
||||
type TelegramClient interface {
|
||||
SendAudioToCacheChannel(ctx context.Context, audioPath, title, performer string) (string, error)
|
||||
AnswerInlineQuery(ctx context.Context, queryID string, results []interface{}) error
|
||||
SendMessage(ctx context.Context, chatID int64, text string) error
|
||||
}
|
||||
|
||||
// Tagger определяет методы для работы с метаданными аудиофайлов.
|
||||
type Tagger interface {
|
||||
WriteTags(filePath string, coverPath string, info *model.TrackInfo) error
|
||||
}
|
||||
|
||||
// FileDownloader определяет метод для скачивания файла.
|
||||
type FileDownloader interface {
|
||||
Download(ctx context.Context, url string) (filePath string, err error)
|
||||
}
|
||||
15
internal/model/model.go
Normal file
15
internal/model/model.go
Normal file
@@ -0,0 +1,15 @@
|
||||
package model
|
||||
|
||||
// TrackInfo содержит всю необходимую информацию о треке для его обработки и тегирования.
|
||||
type TrackInfo struct {
|
||||
YandexTrackID string
|
||||
YandexAlbumID string
|
||||
Title string
|
||||
Album string
|
||||
Artist string
|
||||
Year int
|
||||
Genre string
|
||||
TrackPosition int
|
||||
CoverURL string
|
||||
DownloadURL string
|
||||
}
|
||||
Reference in New Issue
Block a user