mirror of
https://github.com/navidrome/navidrome.git
synced 2025-04-04 13:07:36 +03:00
Add sampleRate to the DB
This commit is contained in:
parent
472324e280
commit
f3bb022238
5 changed files with 91 additions and 56 deletions
29
db/migrations/20240511210036_add_sample_rate.go
Normal file
29
db/migrations/20240511210036_add_sample_rate.go
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
package migrations
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"database/sql"
|
||||||
|
|
||||||
|
"github.com/pressly/goose/v3"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
goose.AddMigrationContext(upAddSampleRate, downAddSampleRate)
|
||||||
|
}
|
||||||
|
|
||||||
|
func upAddSampleRate(ctx context.Context, tx *sql.Tx) error {
|
||||||
|
_, err := tx.ExecContext(ctx, `
|
||||||
|
alter table media_file
|
||||||
|
add sample_rate integer not null default 0;
|
||||||
|
|
||||||
|
create index if not exists media_file_sample_rate
|
||||||
|
on media_file (sample_rate);
|
||||||
|
`)
|
||||||
|
notice(tx, "A full rescan should be performed to pick up additional tags")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func downAddSampleRate(ctx context.Context, tx *sql.Tx) error {
|
||||||
|
_, err := tx.ExecContext(ctx, `alter table media_file drop sample_rate;`)
|
||||||
|
return err
|
||||||
|
}
|
|
@ -43,6 +43,7 @@ type MediaFile struct {
|
||||||
Suffix string `structs:"suffix" json:"suffix"`
|
Suffix string `structs:"suffix" json:"suffix"`
|
||||||
Duration float32 `structs:"duration" json:"duration"`
|
Duration float32 `structs:"duration" json:"duration"`
|
||||||
BitRate int `structs:"bit_rate" json:"bitRate"`
|
BitRate int `structs:"bit_rate" json:"bitRate"`
|
||||||
|
SampleRate int `structs:"sample_rate" json:"sampleRate"`
|
||||||
Channels int `structs:"channels" json:"channels"`
|
Channels int `structs:"channels" json:"channels"`
|
||||||
Genre string `structs:"genre" json:"genre"`
|
Genre string `structs:"genre" json:"genre"`
|
||||||
Genres Genres `structs:"-" json:"genres"`
|
Genres Genres `structs:"-" json:"genres"`
|
||||||
|
|
|
@ -46,6 +46,7 @@ func (s MediaFileMapper) ToMediaFile(md metadata.Tags) model.MediaFile {
|
||||||
mf.DiscSubtitle = md.DiscSubtitle()
|
mf.DiscSubtitle = md.DiscSubtitle()
|
||||||
mf.Duration = md.Duration()
|
mf.Duration = md.Duration()
|
||||||
mf.BitRate = md.BitRate()
|
mf.BitRate = md.BitRate()
|
||||||
|
mf.SampleRate = md.SampleRate()
|
||||||
mf.Channels = md.Channels()
|
mf.Channels = md.Channels()
|
||||||
mf.Path = md.FilePath()
|
mf.Path = md.FilePath()
|
||||||
mf.Suffix = md.Suffix()
|
mf.Suffix = md.Suffix()
|
||||||
|
|
|
@ -139,6 +139,63 @@ func (t Tags) Date() (int, string) { return t.getDate("date") }
|
||||||
func (t Tags) OriginalDate() (int, string) { return t.getDate("originaldate") }
|
func (t Tags) OriginalDate() (int, string) { return t.getDate("originaldate") }
|
||||||
func (t Tags) ReleaseDate() (int, string) { return t.getDate("releasedate") }
|
func (t Tags) ReleaseDate() (int, string) { return t.getDate("releasedate") }
|
||||||
func (t Tags) Comment() string { return t.getFirstTagValue("comment") }
|
func (t Tags) Comment() string { return t.getFirstTagValue("comment") }
|
||||||
|
func (t Tags) Compilation() bool { return t.getBool("tcmp", "compilation", "wm/iscompilation") }
|
||||||
|
func (t Tags) TrackNumber() (int, int) { return t.getTuple("track", "tracknumber") }
|
||||||
|
func (t Tags) DiscNumber() (int, int) { return t.getTuple("disc", "discnumber") }
|
||||||
|
func (t Tags) DiscSubtitle() string {
|
||||||
|
return t.getFirstTagValue("tsst", "discsubtitle", "setsubtitle")
|
||||||
|
}
|
||||||
|
func (t Tags) CatalogNum() string { return t.getFirstTagValue("catalognumber") }
|
||||||
|
func (t Tags) Bpm() int { return (int)(math.Round(t.getFloat("tbpm", "bpm", "fbpm"))) }
|
||||||
|
func (t Tags) HasPicture() bool { return t.getFirstTagValue("has_picture") != "" }
|
||||||
|
|
||||||
|
// MusicBrainz Identifiers
|
||||||
|
|
||||||
|
func (t Tags) MbzReleaseTrackID() string {
|
||||||
|
return t.getMbzID("musicbrainz_releasetrackid", "musicbrainz release track id")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t Tags) MbzRecordingID() string {
|
||||||
|
return t.getMbzID("musicbrainz_trackid", "musicbrainz track id")
|
||||||
|
}
|
||||||
|
func (t Tags) MbzAlbumID() string { return t.getMbzID("musicbrainz_albumid", "musicbrainz album id") }
|
||||||
|
func (t Tags) MbzArtistID() string {
|
||||||
|
return t.getMbzID("musicbrainz_artistid", "musicbrainz artist id")
|
||||||
|
}
|
||||||
|
func (t Tags) MbzAlbumArtistID() string {
|
||||||
|
return t.getMbzID("musicbrainz_albumartistid", "musicbrainz album artist id")
|
||||||
|
}
|
||||||
|
func (t Tags) MbzAlbumType() string {
|
||||||
|
return t.getFirstTagValue("musicbrainz_albumtype", "musicbrainz album type")
|
||||||
|
}
|
||||||
|
func (t Tags) MbzAlbumComment() string {
|
||||||
|
return t.getFirstTagValue("musicbrainz_albumcomment", "musicbrainz album comment")
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReplayGain Properties
|
||||||
|
|
||||||
|
func (t Tags) RGAlbumGain() float64 { return t.getGainValue("replaygain_album_gain") }
|
||||||
|
func (t Tags) RGAlbumPeak() float64 { return t.getPeakValue("replaygain_album_peak") }
|
||||||
|
func (t Tags) RGTrackGain() float64 { return t.getGainValue("replaygain_track_gain") }
|
||||||
|
func (t Tags) RGTrackPeak() float64 { return t.getPeakValue("replaygain_track_peak") }
|
||||||
|
|
||||||
|
// File properties
|
||||||
|
|
||||||
|
func (t Tags) Duration() float32 { return float32(t.getFloat("duration")) }
|
||||||
|
func (t Tags) SampleRate() int { return t.getInt("samplerate") }
|
||||||
|
func (t Tags) BitRate() int { return t.getInt("bitrate") }
|
||||||
|
func (t Tags) Channels() int { return t.getInt("channels") }
|
||||||
|
func (t Tags) ModificationTime() time.Time { return t.fileInfo.ModTime() }
|
||||||
|
func (t Tags) Size() int64 { return t.fileInfo.Size() }
|
||||||
|
func (t Tags) FilePath() string { return t.filePath }
|
||||||
|
func (t Tags) Suffix() string { return strings.ToLower(strings.TrimPrefix(path.Ext(t.filePath), ".")) }
|
||||||
|
func (t Tags) BirthTime() time.Time {
|
||||||
|
if ts := times.Get(t.fileInfo); ts.HasBirthTime() {
|
||||||
|
return ts.BirthTime()
|
||||||
|
}
|
||||||
|
return time.Now()
|
||||||
|
}
|
||||||
|
|
||||||
func (t Tags) Lyrics() string {
|
func (t Tags) Lyrics() string {
|
||||||
lyricList := model.LyricList{}
|
lyricList := model.LyricList{}
|
||||||
basicLyrics := t.getAllTagValues("lyrics", "unsynced_lyrics", "unsynced lyrics", "unsyncedlyrics")
|
basicLyrics := t.getAllTagValues("lyrics", "unsynced_lyrics", "unsynced lyrics", "unsyncedlyrics")
|
||||||
|
@ -181,62 +238,6 @@ func (t Tags) Lyrics() string {
|
||||||
return string(res)
|
return string(res)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t Tags) Compilation() bool { return t.getBool("tcmp", "compilation", "wm/iscompilation") }
|
|
||||||
func (t Tags) TrackNumber() (int, int) { return t.getTuple("track", "tracknumber") }
|
|
||||||
func (t Tags) DiscNumber() (int, int) { return t.getTuple("disc", "discnumber") }
|
|
||||||
func (t Tags) DiscSubtitle() string {
|
|
||||||
return t.getFirstTagValue("tsst", "discsubtitle", "setsubtitle")
|
|
||||||
}
|
|
||||||
func (t Tags) CatalogNum() string { return t.getFirstTagValue("catalognumber") }
|
|
||||||
func (t Tags) Bpm() int { return (int)(math.Round(t.getFloat("tbpm", "bpm", "fbpm"))) }
|
|
||||||
func (t Tags) HasPicture() bool { return t.getFirstTagValue("has_picture") != "" }
|
|
||||||
|
|
||||||
// MusicBrainz Identifiers
|
|
||||||
|
|
||||||
func (t Tags) MbzReleaseTrackID() string {
|
|
||||||
return t.getMbzID("musicbrainz_releasetrackid", "musicbrainz release track id")
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t Tags) MbzRecordingID() string {
|
|
||||||
return t.getMbzID("musicbrainz_trackid", "musicbrainz track id")
|
|
||||||
}
|
|
||||||
func (t Tags) MbzAlbumID() string { return t.getMbzID("musicbrainz_albumid", "musicbrainz album id") }
|
|
||||||
func (t Tags) MbzArtistID() string {
|
|
||||||
return t.getMbzID("musicbrainz_artistid", "musicbrainz artist id")
|
|
||||||
}
|
|
||||||
func (t Tags) MbzAlbumArtistID() string {
|
|
||||||
return t.getMbzID("musicbrainz_albumartistid", "musicbrainz album artist id")
|
|
||||||
}
|
|
||||||
func (t Tags) MbzAlbumType() string {
|
|
||||||
return t.getFirstTagValue("musicbrainz_albumtype", "musicbrainz album type")
|
|
||||||
}
|
|
||||||
func (t Tags) MbzAlbumComment() string {
|
|
||||||
return t.getFirstTagValue("musicbrainz_albumcomment", "musicbrainz album comment")
|
|
||||||
}
|
|
||||||
|
|
||||||
// File properties
|
|
||||||
|
|
||||||
func (t Tags) Duration() float32 { return float32(t.getFloat("duration")) }
|
|
||||||
func (t Tags) BitRate() int { return t.getInt("bitrate") }
|
|
||||||
func (t Tags) Channels() int { return t.getInt("channels") }
|
|
||||||
func (t Tags) ModificationTime() time.Time { return t.fileInfo.ModTime() }
|
|
||||||
func (t Tags) Size() int64 { return t.fileInfo.Size() }
|
|
||||||
func (t Tags) FilePath() string { return t.filePath }
|
|
||||||
func (t Tags) Suffix() string { return strings.ToLower(strings.TrimPrefix(path.Ext(t.filePath), ".")) }
|
|
||||||
func (t Tags) BirthTime() time.Time {
|
|
||||||
if ts := times.Get(t.fileInfo); ts.HasBirthTime() {
|
|
||||||
return ts.BirthTime()
|
|
||||||
}
|
|
||||||
return time.Now()
|
|
||||||
}
|
|
||||||
|
|
||||||
// ReplayGain Properties
|
|
||||||
|
|
||||||
func (t Tags) RGAlbumGain() float64 { return t.getGainValue("replaygain_album_gain") }
|
|
||||||
func (t Tags) RGAlbumPeak() float64 { return t.getPeakValue("replaygain_album_peak") }
|
|
||||||
func (t Tags) RGTrackGain() float64 { return t.getGainValue("replaygain_track_gain") }
|
|
||||||
func (t Tags) RGTrackPeak() float64 { return t.getPeakValue("replaygain_track_peak") }
|
|
||||||
|
|
||||||
func (t Tags) getGainValue(tagName string) float64 {
|
func (t Tags) getGainValue(tagName string) float64 {
|
||||||
// Gain is in the form [-]a.bb dB
|
// Gain is in the form [-]a.bb dB
|
||||||
var tag = t.getFirstTagValue(tagName)
|
var tag = t.getFirstTagValue(tagName)
|
||||||
|
|
|
@ -94,6 +94,7 @@ var _ = Describe("Tags", func() {
|
||||||
Expect(m.Duration()).To(BeNumerically("~", 1.02, 0.01))
|
Expect(m.Duration()).To(BeNumerically("~", 1.02, 0.01))
|
||||||
Expect(m.BitRate()).To(Equal(192))
|
Expect(m.BitRate()).To(Equal(192))
|
||||||
Expect(m.Channels()).To(Equal(2))
|
Expect(m.Channels()).To(Equal(2))
|
||||||
|
Expect(m.SampleRate()).To(Equal(44100))
|
||||||
Expect(m.FilePath()).To(Equal("tests/fixtures/test.mp3"))
|
Expect(m.FilePath()).To(Equal("tests/fixtures/test.mp3"))
|
||||||
Expect(m.Suffix()).To(Equal("mp3"))
|
Expect(m.Suffix()).To(Equal("mp3"))
|
||||||
Expect(m.Size()).To(Equal(int64(51876)))
|
Expect(m.Size()).To(Equal(int64(51876)))
|
||||||
|
@ -113,6 +114,7 @@ var _ = Describe("Tags", func() {
|
||||||
// TabLib 1.12 returns 18, previous versions return 39.
|
// TabLib 1.12 returns 18, previous versions return 39.
|
||||||
// See https://github.com/taglib/taglib/commit/2f238921824741b2cfe6fbfbfc9701d9827ab06b
|
// See https://github.com/taglib/taglib/commit/2f238921824741b2cfe6fbfbfc9701d9827ab06b
|
||||||
Expect(m.BitRate()).To(BeElementOf(18, 39, 40, 43, 49))
|
Expect(m.BitRate()).To(BeElementOf(18, 39, 40, 43, 49))
|
||||||
|
Expect(m.SampleRate()).To(Equal(8000))
|
||||||
|
|
||||||
m = mds["tests/fixtures/test.wma"]
|
m = mds["tests/fixtures/test.wma"]
|
||||||
Expect(err).To(BeNil())
|
Expect(err).To(BeNil())
|
||||||
|
@ -124,6 +126,7 @@ var _ = Describe("Tags", func() {
|
||||||
Expect(m.FilePath()).To(Equal("tests/fixtures/test.wma"))
|
Expect(m.FilePath()).To(Equal("tests/fixtures/test.wma"))
|
||||||
Expect(m.Size()).To(Equal(int64(21581)))
|
Expect(m.Size()).To(Equal(int64(21581)))
|
||||||
Expect(m.BitRate()).To(BeElementOf(128))
|
Expect(m.BitRate()).To(BeElementOf(128))
|
||||||
|
Expect(m.SampleRate()).To(Equal(44100))
|
||||||
})
|
})
|
||||||
|
|
||||||
DescribeTable("Lyrics test",
|
DescribeTable("Lyrics test",
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue