185 lines
3.8 KiB
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
|
|
}
|