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 }