package common import ( "crypto/md5" "fmt" "io" "path/filepath" "slices" "strings" "time" "suruatoel.xyz/mcg/internal/i18n" ) type Album struct { title string songs []*Song artists []string pathes []string dates []string length uint64 lastModified time.Time } func NewAlbum(title string) *Album { album := Album{ title: title, } return &album } func (a *Album) Title() string { return a.title } func (a *Album) AddSong(song *Song) { a.songs = append(a.songs, song) a.length += song.Length() for _, artist := range song.AlbumArtists() { if !slices.Contains(a.artists, artist) { a.artists = append(a.artists, artist) } } if !slices.Contains(a.dates, song.Date()) { a.dates = append(a.dates, song.Date()) } path := filepath.Base(song.File()) if !slices.Contains(a.pathes, path) { a.pathes = append(a.pathes, path) } if !song.LastModified().After(a.lastModified) { a.lastModified = song.LastModified() } } func (a *Album) Songs() []*Song { return a.songs } func (a *Album) Artists() []string { return a.artists } func (a *Album) Dates() []string { return a.dates } func (a *Album) Length() uint64 { return a.length } func (a *Album) LastModified() time.Time { return a.lastModified } func (a *Album) ID() string { return generateAlbumId(a.title) } func (a *Album) Tooltip() string { artists := strings.Join(a.Artists(), ", ") dates := strings.Join(a.dates, ", ") minutes := a.length / 60 seconds := a.length - minutes*60 length := fmt.Sprintf(i18n.T("%d:%d minutes"), minutes, seconds) return strings.Join( []string{ a.title, dates, artists, length, }, "\n", ) } type PlaylistAlbum struct { *Album songs []*PlaylistSong length uint64 } func NewPlaylistAlbum(album *Album) *PlaylistAlbum { playlistAlbum := PlaylistAlbum{ Album: album, } return &playlistAlbum } func (a *PlaylistAlbum) AddSong(playlistSong *PlaylistSong) { a.songs = append(a.songs, playlistSong) song := playlistSong.Song a.length += song.Length() for _, artist := range song.AlbumArtists() { if !slices.Contains(a.artists, artist) { a.artists = append(a.artists, artist) } } if !slices.Contains(a.dates, song.Date()) { a.dates = append(a.dates, song.Date()) } path := filepath.Base(song.File()) if !slices.Contains(a.pathes, path) { a.pathes = append(a.pathes, path) } } func (a *PlaylistAlbum) Songs() []*PlaylistSong { return a.songs } func (a *PlaylistAlbum) Length() uint64 { return a.length } func (a *Album) IsMatch(query string) bool { if query == "" { return true } for keyword := range strings.SplitSeq(query, " ") { if !a.isKeywordMatch(keyword) { return false } } return true } func (a *Album) isKeywordMatch(keyword string) bool { if strings.Contains(strings.ToLower(a.title), keyword) { return true } for _, artist := range a.artists { if strings.Contains(strings.ToLower(artist), keyword) { return true } } for _, song := range a.songs { if strings.Contains(strings.ToLower(song.Title()), keyword) { return true } if strings.Contains(strings.ToLower(song.File()), keyword) { return true } } return false } func generateAlbumId(values ...string) string { h := md5.New() for _, value := range values { io.WriteString(h, value) } return fmt.Sprintf("%x", h.Sum(nil)) }