METANOIA/metadata/lyrics.go

172 lines
3.6 KiB
Go

package metadata
import (
"github.com/oriser/regroup"
"strconv"
"strings"
"time"
)
type LyricsFormat string
const (
ASS LyricsFormat = "ASS"
LRC LyricsFormat = "LRC"
WebVTT LyricsFormat = "WebVTT"
SubRip LyricsFormat = "SubRip"
Text LyricsFormat = "Text"
)
type LyricGetter func() []Lyrics
type Lyrics interface {
GetFormat() LyricsFormat
GetIdentifiers() []Name
GetLanguage() string
GetContent() string
}
type TextLyrics struct {
Language string
Identifiers []Name
Entries []string
}
func (l *TextLyrics) GetLanguage() string {
return l.Language
}
func (l *TextLyrics) GetFormat() LyricsFormat {
return Text
}
func (l *TextLyrics) GetIdentifiers() []Name {
return l.Identifiers
}
func (l *TextLyrics) GetContent() string {
return strings.Join(l.Entries, "\n")
}
type LRCLyrics struct {
Language string
Identifiers []Name
Entries []LRCLyricTextEntry
}
type LRCLyricTextEntry struct {
Start time.Duration
End time.Duration
Content string
}
func (l *LRCLyrics) GetLanguage() string {
return l.Language
}
func (l *LRCLyrics) GetFormat() LyricsFormat {
return LRC
}
func (l *LRCLyrics) GetIdentifiers() []Name {
return l.Identifiers
}
func (l *LRCLyrics) GetContent() string {
var result []string
//TODO
return strings.Join(result, "\n")
}
func NewLRCLyrics(body, language string, identifiers []Name) *LRCLyrics {
var lineRE = regroup.MustCompile(`(?m)^\[(?P<time_minutes>[0-9]+):(?P<time_seconds>[0-9]+)\.(?P<time_decimals>[0-9]+)\](?P<line>.*)$`)
var lineMetaRE = regroup.MustCompile(`(?m)^\[(?P<kind>(ti|al|ar|re)):(?P<line>.*)\]$`)
type LineMatch struct {
TimeMinutes int `regroup:"time_minutes"`
TimeSeconds int `regroup:"time_seconds"`
TimeDecimals string `regroup:"time_decimals"`
Line string `regroup:"line"`
}
type LineMetaMatch struct {
Kind string `regroup:"kind"`
Line string `regroup:"line"`
}
m := &LineMatch{}
rets, err := lineRE.MatchAllToTarget(body, -1, m)
if err == nil {
lyrics := &LRCLyrics{
Language: language,
Identifiers: identifiers,
}
m2 := &LineMetaMatch{}
rets2, _ := lineMetaRE.MatchAllToTarget(body, -1, m2)
for _, elem2 := range rets2 {
match2 := elem2.(*LineMetaMatch)
switch match2.Kind {
case "ti":
lyrics.Identifiers = append(lyrics.Identifiers, Name{
Kind: "title",
Name: strings.TrimSpace(match2.Line),
})
case "al":
lyrics.Identifiers = append(lyrics.Identifiers, Name{
Kind: "album",
Name: strings.TrimSpace(match2.Line),
})
case "ar":
lyrics.Identifiers = append(lyrics.Identifiers, Name{
Kind: "artist",
Name: strings.TrimSpace(match2.Line),
})
}
}
for _, elem := range rets {
match := elem.(*LineMatch)
var last *LRCLyricTextEntry
if len(lyrics.Entries) > 0 {
last = &lyrics.Entries[len(lyrics.Entries)-1]
}
start := time.Minute*time.Duration(match.TimeMinutes) + time.Second*time.Duration(match.TimeSeconds)
if len(match.TimeDecimals) == 1 {
d, _ := strconv.Atoi(match.TimeDecimals)
start += time.Millisecond * time.Duration(d) * 100
} else if len(match.TimeDecimals) == 2 {
d, _ := strconv.Atoi(match.TimeDecimals)
start += time.Millisecond * time.Duration(d) * 10
} else if len(match.TimeDecimals) == 3 {
d, _ := strconv.Atoi(match.TimeDecimals)
start += time.Millisecond * time.Duration(d)
} else {
//TODO
}
if last != nil {
last.End = start
}
line := strings.TrimSpace(match.Line)
if len(line) > 0 {
lyrics.Entries = append(lyrics.Entries, LRCLyricTextEntry{
Start: start,
End: -1,
Content: line,
})
}
}
return lyrics
}
return nil
}