189 lines
3.3 KiB
Go
189 lines
3.3 KiB
Go
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))
|
|
}
|