diff --git a/go.mod b/go.mod index fb8a94a..e966ed4 100644 --- a/go.mod +++ b/go.mod @@ -2,4 +2,9 @@ module gitea.mrixs.me/Mrixs/yamusic-bot go 1.24 -require github.com/caarlos0/env/v10 v10.0.0 +require ( + github.com/bogem/id3v2 v1.2.0 + github.com/caarlos0/env/v10 v10.0.0 +) + +require golang.org/x/text v0.3.2 // indirect diff --git a/go.sum b/go.sum index ac2ad93..32c849b 100644 --- a/go.sum +++ b/go.sum @@ -1,2 +1,7 @@ +github.com/bogem/id3v2 v1.2.0 h1:hKDF+F1gOgQ5r1QmBCEZUk4MveJbKxCeIDSBU7CQ4oI= +github.com/bogem/id3v2 v1.2.0/go.mod h1:t78PK5AQ56Q47kizpYiV6gtjj3jfxlz87oFpty8DYs8= github.com/caarlos0/env/v10 v10.0.0 h1:yIHUBZGsyqCnpTkbjk8asUlx6RFhhEs+h7TOBdgdzXA= github.com/caarlos0/env/v10 v10.0.0/go.mod h1:ZfulV76NvVPw3tm591U4SwL3Xx9ldzBP9aGxzeN7G18= +golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= diff --git a/pkg/logging/logger.go b/pkg/logging/logger.go new file mode 100644 index 0000000..83178ab --- /dev/null +++ b/pkg/logging/logger.go @@ -0,0 +1,30 @@ +package logging + +import ( + "log/slog" + "os" +) + +// NewLogger создает и настраивает новый экземпляр slog.Logger. +func NewLogger(logLevel string) *slog.Logger { + var level slog.Level + switch logLevel { + case "debug": + level = slog.LevelDebug + case "info": + level = slog.LevelInfo + case "warn": + level = slog.LevelWarn + case "error": + level = slog.LevelError + default: + level = slog.LevelInfo + } + + opts := &slog.HandlerOptions{ + Level: level, + } + + handler := slog.NewTextHandler(os.Stdout, opts) + return slog.New(handler) +} diff --git a/pkg/tagger/id3.go b/pkg/tagger/id3.go new file mode 100644 index 0000000..7fbbfea --- /dev/null +++ b/pkg/tagger/id3.go @@ -0,0 +1,61 @@ +package tagger + +import ( + "fmt" + "os" + "strconv" + + "gitea.mrixs.me/Mrixs/yamusic-bot/internal/model" + "github.com/bogem/id3v2" +) + +// ID3Tagger реализует интерфейс interfaces.Tagger для работы с ID3-тегами. +type ID3Tagger struct{} + +// NewID3Tagger создает новый экземпляр теггера. +func NewID3Tagger() *ID3Tagger { + return &ID3Tagger{} +} + +// WriteTags записывает метаданные и обложку в указанный аудиофайл. +func (t *ID3Tagger) WriteTags(filePath string, coverPath string, info *model.TrackInfo) error { + tag, err := id3v2.Open(filePath, id3v2.Options{Parse: true}) + if err != nil { + return fmt.Errorf("failed to open mp3 file for tagging: %w", err) + } + defer tag.Close() + + tag.SetTitle(info.Title) + tag.SetArtist(info.Artist) + tag.SetAlbum(info.Album) + tag.SetYear(strconv.Itoa(info.Year)) + tag.SetGenre(info.Genre) + + // Добавляем номер трека, если он есть + if info.TrackPosition > 0 { + tag.AddTextFrame(tag.CommonID("Track number/Position in set"), id3v2.EncodingUTF8, strconv.Itoa(info.TrackPosition)) + } + + // Встраиваем обложку + if coverPath != "" { + artwork, err := os.ReadFile(coverPath) + if err != nil { + return fmt.Errorf("failed to read cover file: %w", err) + } + + pic := id3v2.PictureFrame{ + Encoding: id3v2.EncodingUTF8, + MimeType: "image/jpeg", + PictureType: id3v2.PTFrontCover, + Description: "Front Cover", + Picture: artwork, + } + tag.AddAttachedPicture(pic) + } + + if err = tag.Save(); err != nil { + return fmt.Errorf("failed to save id3 tags: %w", err) + } + + return nil +}