MeteorLight/queue/track/track.go

185 lines
3.8 KiB
Go

package track
import (
"errors"
"fmt"
"git.gammaspectra.live/S.O.N.G/Kirika/audio"
"git.gammaspectra.live/S.O.N.G/Kirika/audio/format/guess"
"git.gammaspectra.live/S.O.N.G/Kirika/audio/queue"
"git.gammaspectra.live/S.O.N.G/MeteorLight/util"
"github.com/dhowden/tag"
"io"
"os"
"path"
"runtime"
"strconv"
"strings"
)
type Entry struct {
Identifier queue.Identifier
Path string
Metadata struct {
Title interface{} `json:"title"`
Album interface{} `json:"album"`
Artist interface{} `json:"artist"`
Art string `json:"art"`
ReplayGain struct {
TrackPeak float64 `json:"track_peak"`
TrackGain float64 `json:"track_gain"`
AlbumPeak float64 `json:"album_peak"`
AlbumGain float64 `json:"album_gain"`
} `json:"replay_gain,omitempty"`
}
reader io.ReadSeekCloser
source audio.Source
Original map[string]interface{}
}
func (e *Entry) Title() string {
if strVal, ok := e.Metadata.Title.(string); ok {
return strVal
} else if intVal, ok := e.Metadata.Title.(int); ok {
return strconv.Itoa(intVal)
}
return ""
}
func (e *Entry) Album() string {
if strVal, ok := e.Metadata.Album.(string); ok {
return strVal
} else if intVal, ok := e.Metadata.Album.(int); ok {
return strconv.Itoa(intVal)
}
return ""
}
func (e *Entry) Artist() string {
if strVal, ok := e.Metadata.Artist.(string); ok {
return strVal
} else if intVal, ok := e.Metadata.Artist.(int); ok {
return strconv.Itoa(intVal)
}
return ""
}
func (e *Entry) Source() audio.Source {
return e.source
}
func (e *Entry) Close() error {
if e.reader != nil {
return e.reader.Close()
}
return nil
}
func (e *Entry) Load() error {
if e.source != nil {
return nil
}
fileName := path.Base(e.Path)
if len(e.Path) > 4 && e.Path[:4] == "http" {
s, err := util.NewRangeReadSeekCloser(e.Path)
if err != nil {
return err
}
fileName = s.GetFileName()
runtime.SetFinalizer(s, (*util.RangeReadSeekCloser).Close)
e.reader = s
} else {
f, err := os.Open(e.Path)
if err != nil {
return err
}
runtime.SetFinalizer(f, (*os.File).Close)
e.reader = f
}
if e.reader == nil {
return errors.New("could not find stream opener")
}
meta, err := tag.ReadFrom(e.reader)
if err != nil {
err = nil
}
if _, err = e.reader.Seek(0, io.SeekStart); err != nil {
return err
}
decoders, err := guess.GetDecoders(e.reader, fileName)
if err != nil {
return err
}
source, err := guess.Open(e.reader, decoders)
if err != nil {
return err
}
if source == nil {
return fmt.Errorf("could not find decoder for %s", e.Path)
}
e.source = source
//apply tags found on file
if meta != nil {
if e.Title() == "" {
e.Metadata.Title = meta.Title()
}
if e.Album() == "" {
e.Metadata.Album = meta.Album()
}
if e.Artist() == "" {
e.Metadata.Artist = meta.Artist()
}
if e.Artist() == "" {
e.Metadata.Artist = meta.AlbumArtist()
}
tags := meta.Raw()
var strValue string
var value interface{}
var ok bool
getDb := func(strValue string) (ret float64) {
ret, _ = strconv.ParseFloat(strings.TrimSpace(strings.TrimSuffix(strings.ToLower(strValue), "db")), 64)
return
}
if e.Metadata.ReplayGain.TrackPeak == 0 {
if value, ok = tags["replaygain_track_gain"]; ok {
if strValue, ok = value.(string); ok {
e.Metadata.ReplayGain.TrackGain = getDb(strValue)
}
}
if value, ok = tags["replaygain_track_peak"]; ok {
if strValue, ok = value.(string); ok {
e.Metadata.ReplayGain.TrackPeak = getDb(strValue)
}
}
if value, ok = tags["replaygain_album_gain"]; ok {
if strValue, ok = value.(string); ok {
e.Metadata.ReplayGain.AlbumGain = getDb(strValue)
}
}
if value, ok = tags["replaygain_album_peak"]; ok {
if strValue, ok = value.(string); ok {
e.Metadata.ReplayGain.AlbumPeak = getDb(strValue)
}
}
}
}
return nil
}