feat(subsonic): expose replaygain tags

This commit is contained in:
sentriz
2024-05-30 11:43:45 +01:00
parent 259be0edde
commit 0e45f5e84c
18 changed files with 307 additions and 178 deletions

View File

@@ -67,7 +67,7 @@ password can then be changed from the web interface
| `GONIC_JUKEBOX_ENABLED` | `-jukebox-enabled` | **optional** whether the subsonic [jukebox api](https://airsonic.github.io/docs/jukebox/) should be enabled |
| `GONIC_JUKEBOX_MPV_EXTRA_ARGS` | `-jukebox-mpv-extra-args` | **optional** extra command line arguments to pass to the jukebox mpv daemon |
| `GONIC_PODCAST_PURGE_AGE` | `-podcast-purge-age` | **optional** age (in days) to purge podcast episodes if not accessed |
| `GONIC_EXCLUDE_PATTERN` | `-exclude-pattern` | **optional** files matching this regex pattern will not be imported. Example : <code>@eaDir\|[aA]rtwork\|[cC]overs\|[sS]cans\|[sS]pectrals</code> |
| `GONIC_EXCLUDE_PATTERN` | `-exclude-pattern` | **optional** files matching this regex pattern will not be imported. eg <code>@eaDir\|[aA]rtwork\|[cC]overs\|[sS]cans\|[sS]pectrals</code> |
| `GONIC_MULTI_VALUE_GENRE` | `-multi-value-genre` | **optional** setting for multi-valued genre tags when scanning ([see more](#multi-valued-tags-v016)) |
| `GONIC_MULTI_VALUE_ARTIST` | `-multi-value-artist` | **optional** setting for multi-valued artist tags when scanning ([see more](#multi-valued-tags-v016)) |
| `GONIC_MULTI_VALUE_ALBUM_ARTIST` | `-multi-value-album-artist` | **optional** setting for multi-valued album artist tags when scanning ([see more](#multi-valued-tags-v016)) |
@@ -97,7 +97,7 @@ the available modes are:
gonic supports multiple music folders. this can be handy if you have your music separated by albums, compilations, singles. or maybe 70s, 80s, 90s. whatever.
on top of that - if you don't decide your folder names, or simply do not want the same name in your subsonic client,
on top of that - if you don't decide your folder names, or simply do not want the same name in your subsonic client,
gonic can parse aliases for the folder names with the optional `ALIAS->PATH` syntax
if you're running gonic with the command line, stack the `-music-path` arg

View File

@@ -235,9 +235,15 @@ type Track struct {
TagTrackNumber int `sql:"default: null"`
TagDiscNumber int `sql:"default: null"`
TagBrainzID string `sql:"default: null"`
TrackStar *TrackStar
TrackRating *TrackRating
AverageRating float64 `sql:"default: null"`
ReplayGainTrackGain float32
ReplayGainTrackPeak float32
ReplayGainAlbumGain float32
ReplayGainAlbumPeak float32
TrackStar *TrackStar
TrackRating *TrackRating
AverageRating float64 `sql:"default: null"`
}
func (t *Track) AudioLength() int { return t.Length }

View File

@@ -72,6 +72,7 @@ func (db *DB) Migrate(ctx MigrationContext) error {
construct(ctx, "202311072309", migrateAlbumInfo),
construct(ctx, "202311082304", migrateTemporaryDisplayAlbumArtist),
construct(ctx, "202312110003", migrateAddExtraIndexes),
construct(ctx, "202405301140", migrateAddReplayGainFields),
}
return gormigrate.
@@ -813,3 +814,7 @@ func migrateAddExtraIndexes(tx *gorm.DB, _ MigrationContext) error {
CREATE INDEX idx_artist_appearances_album_id ON "artist_appearances" (album_id);
`).Error
}
func migrateAddReplayGainFields(tx *gorm.DB, _ MigrationContext) error {
return tx.AutoMigrate(Track{}).Error
}

View File

@@ -362,8 +362,14 @@ func (i *TagInfo) Genres() []string { return []string{i.RawGenre} }
func (i *TagInfo) TrackNumber() int { return 1 }
func (i *TagInfo) DiscNumber() int { return 1 }
func (i *TagInfo) Year() int { return 2021 }
func (i *TagInfo) Length() int { return firstInt(100, i.RawLength) }
func (i *TagInfo) Bitrate() int { return firstInt(100, i.RawBitrate) }
func (i *TagInfo) ReplayGainTrackGain() float32 { return 0 }
func (i *TagInfo) ReplayGainTrackPeak() float32 { return 0 }
func (i *TagInfo) ReplayGainAlbumGain() float32 { return 0 }
func (i *TagInfo) ReplayGainAlbumPeak() float32 { return 0 }
func (i *TagInfo) Length() int { return firstInt(100, i.RawLength) }
func (i *TagInfo) Bitrate() int { return firstInt(100, i.RawBitrate) }
var _ tagcommon.Reader = (*tagReader)(nil)

View File

@@ -469,8 +469,14 @@ func populateTrack(tx *db.DB, album *db.Album, track *db.Track, trags tagcommon.
track.TagDiscNumber = trags.DiscNumber()
track.TagBrainzID = trags.BrainzID()
track.Length = trags.Length() // these two should be calculated
track.Bitrate = trags.Bitrate() // ...from the file instead of tags
track.ReplayGainTrackGain = trags.ReplayGainTrackGain()
track.ReplayGainTrackPeak = trags.ReplayGainTrackPeak()
track.ReplayGainAlbumGain = trags.ReplayGainAlbumGain()
track.ReplayGainAlbumPeak = trags.ReplayGainAlbumPeak()
// these two are calculated from the file instead of tags
track.Length = trags.Length()
track.Bitrate = trags.Bitrate()
if err := tx.Save(&track).Error; err != nil {
return fmt.Errorf("saving track: %w", err)

View File

@@ -102,6 +102,14 @@ func NewTCTrackByFolder(t *db.Track, parent *db.Album) *TrackChild {
for _, a := range t.Artists {
trCh.Artists = append(trCh.Artists, &ArtistRef{ID: a.SID(), Name: a.Name})
}
if t.ReplayGainTrackGain != 0 || t.ReplayGainAlbumGain != 0 {
trCh.ReplayGain = &ReplayGain{
TrackGain: t.ReplayGainTrackGain,
TrackPeak: t.ReplayGainTrackPeak,
AlbumGain: t.ReplayGainAlbumGain,
AlbumPeak: t.ReplayGainAlbumPeak,
}
}
return trCh
}

View File

@@ -112,6 +112,14 @@ func NewTrackByTags(t *db.Track, album *db.Album) *TrackChild {
for _, a := range album.Artists {
ret.AlbumArtists = append(ret.AlbumArtists, &ArtistRef{ID: a.SID(), Name: a.Name})
}
if t.ReplayGainTrackGain != 0 || t.ReplayGainAlbumGain != 0 {
ret.ReplayGain = &ReplayGain{
TrackGain: t.ReplayGainTrackGain,
TrackPeak: t.ReplayGainTrackPeak,
AlbumGain: t.ReplayGainAlbumGain,
AlbumPeak: t.ReplayGainAlbumPeak,
}
}
return ret
}

View File

@@ -169,6 +169,13 @@ type TranscodeMeta struct {
TranscodedSuffix string `xml:"transcodedSuffix,attr,omitempty" json:"transcodedSuffix,omitempty"`
}
type ReplayGain struct {
TrackGain float32 `xml:"trackGain,attr" json:"trackGain"`
TrackPeak float32 `xml:"trackPeak,attr" json:"trackPeak"`
AlbumGain float32 `xml:"albumGain,attr" json:"albumGain"`
AlbumPeak float32 `xml:"albumPeak,attr" json:"albumPeak"`
}
// https://opensubsonic.netlify.app/docs/responses/child/
type TrackChild struct {
ID *specid.ID `xml:"id,attr,omitempty" json:"id,omitempty"`
@@ -211,6 +218,8 @@ type TrackChild struct {
UserRating int `xml:"userRating,attr,omitempty" json:"userRating,omitempty"`
AverageRating string `xml:"averageRating,attr,omitempty" json:"averageRating,omitempty"`
ReplayGain *ReplayGain `xml:"replayGain" json:"replayGain"`
TranscodeMeta
}

View File

@@ -8,16 +8,16 @@
"albumList": {
"album": [
{
"id": "al-9",
"id": "al-5",
"created": "2019-11-30T00:00:00Z",
"artist": "artist-1",
"artist": "artist-0",
"artists": null,
"displayArtist": "",
"title": "album-2",
"album": "album-2",
"parent": "al-6",
"parent": "al-2",
"isDir": true,
"coverArt": "al-9",
"coverArt": "al-5",
"name": "album-2",
"songCount": 3,
"duration": 300,
@@ -40,48 +40,16 @@
"playCount": 0
},
{
"id": "al-4",
"created": "2019-11-30T00:00:00Z",
"artist": "artist-0",
"artists": null,
"displayArtist": "",
"title": "album-1",
"album": "album-1",
"parent": "al-2",
"isDir": true,
"coverArt": "al-4",
"name": "album-1",
"songCount": 3,
"duration": 300,
"playCount": 0
},
{
"id": "al-12",
"id": "al-13",
"created": "2019-11-30T00:00:00Z",
"artist": "artist-2",
"artists": null,
"displayArtist": "",
"title": "album-1",
"album": "album-1",
"parent": "al-10",
"isDir": true,
"coverArt": "al-12",
"name": "album-1",
"songCount": 3,
"duration": 300,
"playCount": 0
},
{
"id": "al-5",
"created": "2019-11-30T00:00:00Z",
"artist": "artist-0",
"artists": null,
"displayArtist": "",
"title": "album-2",
"album": "album-2",
"parent": "al-2",
"parent": "al-10",
"isDir": true,
"coverArt": "al-5",
"coverArt": "al-13",
"name": "album-2",
"songCount": 3,
"duration": 300,
@@ -103,6 +71,54 @@
"duration": 300,
"playCount": 0
},
{
"id": "al-4",
"created": "2019-11-30T00:00:00Z",
"artist": "artist-0",
"artists": null,
"displayArtist": "",
"title": "album-1",
"album": "album-1",
"parent": "al-2",
"isDir": true,
"coverArt": "al-4",
"name": "album-1",
"songCount": 3,
"duration": 300,
"playCount": 0
},
{
"id": "al-9",
"created": "2019-11-30T00:00:00Z",
"artist": "artist-1",
"artists": null,
"displayArtist": "",
"title": "album-2",
"album": "album-2",
"parent": "al-6",
"isDir": true,
"coverArt": "al-9",
"name": "album-2",
"songCount": 3,
"duration": 300,
"playCount": 0
},
{
"id": "al-12",
"created": "2019-11-30T00:00:00Z",
"artist": "artist-2",
"artists": null,
"displayArtist": "",
"title": "album-1",
"album": "album-1",
"parent": "al-10",
"isDir": true,
"coverArt": "al-12",
"name": "album-1",
"songCount": 3,
"duration": 300,
"playCount": 0
},
{
"id": "al-8",
"created": "2019-11-30T00:00:00Z",
@@ -119,22 +135,6 @@
"duration": 300,
"playCount": 0
},
{
"id": "al-13",
"created": "2019-11-30T00:00:00Z",
"artist": "artist-2",
"artists": null,
"displayArtist": "",
"title": "album-2",
"album": "album-2",
"parent": "al-10",
"isDir": true,
"coverArt": "al-13",
"name": "album-2",
"songCount": 3,
"duration": 300,
"playCount": 0
},
{
"id": "al-11",
"created": "2019-11-30T00:00:00Z",

View File

@@ -24,32 +24,16 @@
"year": 2021
},
{
"id": "al-5",
"created": "2019-11-30T00:00:00Z",
"artistId": "ar-1",
"artist": "artist-0",
"artists": [{ "id": "ar-1", "name": "artist-0" }],
"displayArtist": "artist-0",
"title": "album-2",
"album": "album-2",
"coverArt": "al-5",
"name": "album-2",
"songCount": 3,
"duration": 300,
"playCount": 0,
"year": 2021
},
{
"id": "al-8",
"id": "al-7",
"created": "2019-11-30T00:00:00Z",
"artistId": "ar-2",
"artist": "artist-1",
"artists": [{ "id": "ar-2", "name": "artist-1" }],
"displayArtist": "artist-1",
"title": "album-1",
"album": "album-1",
"coverArt": "al-8",
"name": "album-1",
"title": "album-0",
"album": "album-0",
"coverArt": "al-7",
"name": "album-0",
"songCount": 3,
"duration": 300,
"playCount": 0,
@@ -71,38 +55,6 @@
"playCount": 0,
"year": 2021
},
{
"id": "al-12",
"created": "2019-11-30T00:00:00Z",
"artistId": "ar-3",
"artist": "artist-2",
"artists": [{ "id": "ar-3", "name": "artist-2" }],
"displayArtist": "artist-2",
"title": "album-1",
"album": "album-1",
"coverArt": "al-12",
"name": "album-1",
"songCount": 3,
"duration": 300,
"playCount": 0,
"year": 2021
},
{
"id": "al-7",
"created": "2019-11-30T00:00:00Z",
"artistId": "ar-2",
"artist": "artist-1",
"artists": [{ "id": "ar-2", "name": "artist-1" }],
"displayArtist": "artist-1",
"title": "album-0",
"album": "album-0",
"coverArt": "al-7",
"name": "album-0",
"songCount": 3,
"duration": 300,
"playCount": 0,
"year": 2021
},
{
"id": "al-13",
"created": "2019-11-30T00:00:00Z",
@@ -135,6 +87,54 @@
"playCount": 0,
"year": 2021
},
{
"id": "al-12",
"created": "2019-11-30T00:00:00Z",
"artistId": "ar-3",
"artist": "artist-2",
"artists": [{ "id": "ar-3", "name": "artist-2" }],
"displayArtist": "artist-2",
"title": "album-1",
"album": "album-1",
"coverArt": "al-12",
"name": "album-1",
"songCount": 3,
"duration": 300,
"playCount": 0,
"year": 2021
},
{
"id": "al-5",
"created": "2019-11-30T00:00:00Z",
"artistId": "ar-1",
"artist": "artist-0",
"artists": [{ "id": "ar-1", "name": "artist-0" }],
"displayArtist": "artist-0",
"title": "album-2",
"album": "album-2",
"coverArt": "al-5",
"name": "album-2",
"songCount": 3,
"duration": 300,
"playCount": 0,
"year": 2021
},
{
"id": "al-8",
"created": "2019-11-30T00:00:00Z",
"artistId": "ar-2",
"artist": "artist-1",
"artists": [{ "id": "ar-2", "name": "artist-1" }],
"displayArtist": "artist-1",
"title": "album-1",
"album": "album-1",
"coverArt": "al-8",
"name": "album-1",
"songCount": 3,
"duration": 300,
"playCount": 0,
"year": 2021
},
{
"id": "al-9",
"created": "2019-11-30T00:00:00Z",

View File

@@ -48,7 +48,8 @@
"discNumber": 1,
"type": "music",
"year": 2021,
"musicBrainzId": ""
"musicBrainzId": "",
"replayGain": null
},
{
"id": "tr-2",
@@ -75,7 +76,8 @@
"discNumber": 1,
"type": "music",
"year": 2021,
"musicBrainzId": ""
"musicBrainzId": "",
"replayGain": null
},
{
"id": "tr-3",
@@ -102,7 +104,8 @@
"discNumber": 1,
"type": "music",
"year": 2021,
"musicBrainzId": ""
"musicBrainzId": "",
"replayGain": null
}
]
}

View File

@@ -33,7 +33,8 @@
"discNumber": 1,
"type": "music",
"year": 2021,
"musicBrainzId": ""
"musicBrainzId": "",
"replayGain": null
},
{
"id": "tr-2",
@@ -58,7 +59,8 @@
"discNumber": 1,
"type": "music",
"year": 2021,
"musicBrainzId": ""
"musicBrainzId": "",
"replayGain": null
},
{
"id": "tr-3",
@@ -83,7 +85,8 @@
"discNumber": 1,
"type": "music",
"year": 2021,
"musicBrainzId": ""
"musicBrainzId": "",
"replayGain": null
}
]
}

View File

@@ -23,7 +23,8 @@
"isVideo": false,
"parent": "al-2",
"title": "album-0",
"musicBrainzId": ""
"musicBrainzId": "",
"replayGain": null
},
{
"id": "al-4",
@@ -38,7 +39,8 @@
"isVideo": false,
"parent": "al-2",
"title": "album-1",
"musicBrainzId": ""
"musicBrainzId": "",
"replayGain": null
},
{
"id": "al-5",
@@ -53,7 +55,8 @@
"isVideo": false,
"parent": "al-2",
"title": "album-2",
"musicBrainzId": ""
"musicBrainzId": "",
"replayGain": null
}
]
}

View File

@@ -34,7 +34,8 @@
"discNumber": 1,
"type": "music",
"year": 2021,
"musicBrainzId": ""
"musicBrainzId": "",
"replayGain": null
},
{
"id": "tr-2",
@@ -63,7 +64,8 @@
"discNumber": 1,
"type": "music",
"year": 2021,
"musicBrainzId": ""
"musicBrainzId": "",
"replayGain": null
},
{
"id": "tr-3",
@@ -92,7 +94,8 @@
"discNumber": 1,
"type": "music",
"year": 2021,
"musicBrainzId": ""
"musicBrainzId": "",
"replayGain": null
},
{
"id": "tr-4",
@@ -121,7 +124,8 @@
"discNumber": 1,
"type": "music",
"year": 2021,
"musicBrainzId": ""
"musicBrainzId": "",
"replayGain": null
},
{
"id": "tr-5",
@@ -150,7 +154,8 @@
"discNumber": 1,
"type": "music",
"year": 2021,
"musicBrainzId": ""
"musicBrainzId": "",
"replayGain": null
},
{
"id": "tr-6",
@@ -179,7 +184,8 @@
"discNumber": 1,
"type": "music",
"year": 2021,
"musicBrainzId": ""
"musicBrainzId": "",
"replayGain": null
},
{
"id": "tr-7",
@@ -208,7 +214,8 @@
"discNumber": 1,
"type": "music",
"year": 2021,
"musicBrainzId": ""
"musicBrainzId": "",
"replayGain": null
},
{
"id": "tr-8",
@@ -237,7 +244,8 @@
"discNumber": 1,
"type": "music",
"year": 2021,
"musicBrainzId": ""
"musicBrainzId": "",
"replayGain": null
},
{
"id": "tr-9",
@@ -266,7 +274,8 @@
"discNumber": 1,
"type": "music",
"year": 2021,
"musicBrainzId": ""
"musicBrainzId": "",
"replayGain": null
},
{
"id": "tr-10",
@@ -295,7 +304,8 @@
"discNumber": 1,
"type": "music",
"year": 2021,
"musicBrainzId": ""
"musicBrainzId": "",
"replayGain": null
},
{
"id": "tr-11",
@@ -324,7 +334,8 @@
"discNumber": 1,
"type": "music",
"year": 2021,
"musicBrainzId": ""
"musicBrainzId": "",
"replayGain": null
},
{
"id": "tr-12",
@@ -353,7 +364,8 @@
"discNumber": 1,
"type": "music",
"year": 2021,
"musicBrainzId": ""
"musicBrainzId": "",
"replayGain": null
},
{
"id": "tr-13",
@@ -382,7 +394,8 @@
"discNumber": 1,
"type": "music",
"year": 2021,
"musicBrainzId": ""
"musicBrainzId": "",
"replayGain": null
},
{
"id": "tr-14",
@@ -411,7 +424,8 @@
"discNumber": 1,
"type": "music",
"year": 2021,
"musicBrainzId": ""
"musicBrainzId": "",
"replayGain": null
},
{
"id": "tr-15",
@@ -440,7 +454,8 @@
"discNumber": 1,
"type": "music",
"year": 2021,
"musicBrainzId": ""
"musicBrainzId": "",
"replayGain": null
},
{
"id": "tr-16",
@@ -469,7 +484,8 @@
"discNumber": 1,
"type": "music",
"year": 2021,
"musicBrainzId": ""
"musicBrainzId": "",
"replayGain": null
},
{
"id": "tr-17",
@@ -498,7 +514,8 @@
"discNumber": 1,
"type": "music",
"year": 2021,
"musicBrainzId": ""
"musicBrainzId": "",
"replayGain": null
},
{
"id": "tr-18",
@@ -527,7 +544,8 @@
"discNumber": 1,
"type": "music",
"year": 2021,
"musicBrainzId": ""
"musicBrainzId": "",
"replayGain": null
},
{
"id": "tr-19",
@@ -556,7 +574,8 @@
"discNumber": 1,
"type": "music",
"year": 2021,
"musicBrainzId": ""
"musicBrainzId": "",
"replayGain": null
},
{
"id": "tr-20",
@@ -585,7 +604,8 @@
"discNumber": 1,
"type": "music",
"year": 2021,
"musicBrainzId": ""
"musicBrainzId": "",
"replayGain": null
}
]
}

View File

@@ -20,7 +20,8 @@
"isVideo": false,
"parent": "al-2",
"title": "album-0",
"musicBrainzId": ""
"musicBrainzId": "",
"replayGain": null
},
{
"id": "al-4",
@@ -35,7 +36,8 @@
"isVideo": false,
"parent": "al-2",
"title": "album-1",
"musicBrainzId": ""
"musicBrainzId": "",
"replayGain": null
},
{
"id": "al-5",
@@ -50,7 +52,8 @@
"isVideo": false,
"parent": "al-2",
"title": "album-2",
"musicBrainzId": ""
"musicBrainzId": "",
"replayGain": null
},
{
"id": "al-7",
@@ -65,7 +68,8 @@
"isVideo": false,
"parent": "al-6",
"title": "album-0",
"musicBrainzId": ""
"musicBrainzId": "",
"replayGain": null
},
{
"id": "al-8",
@@ -80,7 +84,8 @@
"isVideo": false,
"parent": "al-6",
"title": "album-1",
"musicBrainzId": ""
"musicBrainzId": "",
"replayGain": null
},
{
"id": "al-9",
@@ -95,7 +100,8 @@
"isVideo": false,
"parent": "al-6",
"title": "album-2",
"musicBrainzId": ""
"musicBrainzId": "",
"replayGain": null
},
{
"id": "al-11",
@@ -110,7 +116,8 @@
"isVideo": false,
"parent": "al-10",
"title": "album-0",
"musicBrainzId": ""
"musicBrainzId": "",
"replayGain": null
},
{
"id": "al-12",
@@ -125,7 +132,8 @@
"isVideo": false,
"parent": "al-10",
"title": "album-1",
"musicBrainzId": ""
"musicBrainzId": "",
"replayGain": null
},
{
"id": "al-13",
@@ -140,7 +148,8 @@
"isVideo": false,
"parent": "al-10",
"title": "album-2",
"musicBrainzId": ""
"musicBrainzId": "",
"replayGain": null
}
]
}

View File

@@ -30,7 +30,8 @@
"discNumber": 1,
"type": "music",
"year": 2021,
"musicBrainzId": ""
"musicBrainzId": "",
"replayGain": null
},
{
"id": "tr-2",
@@ -55,7 +56,8 @@
"discNumber": 1,
"type": "music",
"year": 2021,
"musicBrainzId": ""
"musicBrainzId": "",
"replayGain": null
},
{
"id": "tr-3",
@@ -80,7 +82,8 @@
"discNumber": 1,
"type": "music",
"year": 2021,
"musicBrainzId": ""
"musicBrainzId": "",
"replayGain": null
},
{
"id": "tr-4",
@@ -105,7 +108,8 @@
"discNumber": 1,
"type": "music",
"year": 2021,
"musicBrainzId": ""
"musicBrainzId": "",
"replayGain": null
},
{
"id": "tr-5",
@@ -130,7 +134,8 @@
"discNumber": 1,
"type": "music",
"year": 2021,
"musicBrainzId": ""
"musicBrainzId": "",
"replayGain": null
},
{
"id": "tr-6",
@@ -155,7 +160,8 @@
"discNumber": 1,
"type": "music",
"year": 2021,
"musicBrainzId": ""
"musicBrainzId": "",
"replayGain": null
},
{
"id": "tr-7",
@@ -180,7 +186,8 @@
"discNumber": 1,
"type": "music",
"year": 2021,
"musicBrainzId": ""
"musicBrainzId": "",
"replayGain": null
},
{
"id": "tr-8",
@@ -205,7 +212,8 @@
"discNumber": 1,
"type": "music",
"year": 2021,
"musicBrainzId": ""
"musicBrainzId": "",
"replayGain": null
},
{
"id": "tr-9",
@@ -230,7 +238,8 @@
"discNumber": 1,
"type": "music",
"year": 2021,
"musicBrainzId": ""
"musicBrainzId": "",
"replayGain": null
},
{
"id": "tr-10",
@@ -255,7 +264,8 @@
"discNumber": 1,
"type": "music",
"year": 2021,
"musicBrainzId": ""
"musicBrainzId": "",
"replayGain": null
},
{
"id": "tr-11",
@@ -280,7 +290,8 @@
"discNumber": 1,
"type": "music",
"year": 2021,
"musicBrainzId": ""
"musicBrainzId": "",
"replayGain": null
},
{
"id": "tr-12",
@@ -305,7 +316,8 @@
"discNumber": 1,
"type": "music",
"year": 2021,
"musicBrainzId": ""
"musicBrainzId": "",
"replayGain": null
},
{
"id": "tr-13",
@@ -330,7 +342,8 @@
"discNumber": 1,
"type": "music",
"year": 2021,
"musicBrainzId": ""
"musicBrainzId": "",
"replayGain": null
},
{
"id": "tr-14",
@@ -355,7 +368,8 @@
"discNumber": 1,
"type": "music",
"year": 2021,
"musicBrainzId": ""
"musicBrainzId": "",
"replayGain": null
},
{
"id": "tr-15",
@@ -380,7 +394,8 @@
"discNumber": 1,
"type": "music",
"year": 2021,
"musicBrainzId": ""
"musicBrainzId": "",
"replayGain": null
},
{
"id": "tr-16",
@@ -405,7 +420,8 @@
"discNumber": 1,
"type": "music",
"year": 2021,
"musicBrainzId": ""
"musicBrainzId": "",
"replayGain": null
},
{
"id": "tr-17",
@@ -430,7 +446,8 @@
"discNumber": 1,
"type": "music",
"year": 2021,
"musicBrainzId": ""
"musicBrainzId": "",
"replayGain": null
},
{
"id": "tr-18",
@@ -455,7 +472,8 @@
"discNumber": 1,
"type": "music",
"year": 2021,
"musicBrainzId": ""
"musicBrainzId": "",
"replayGain": null
},
{
"id": "tr-19",
@@ -480,7 +498,8 @@
"discNumber": 1,
"type": "music",
"year": 2021,
"musicBrainzId": ""
"musicBrainzId": "",
"replayGain": null
},
{
"id": "tr-20",
@@ -505,7 +524,8 @@
"discNumber": 1,
"type": "music",
"year": 2021,
"musicBrainzId": ""
"musicBrainzId": "",
"replayGain": null
}
]
}

View File

@@ -24,9 +24,15 @@ type Info interface {
Genres() []string
TrackNumber() int
DiscNumber() int
Year() int
ReplayGainTrackGain() float32
ReplayGainTrackPeak() float32
ReplayGainAlbumGain() float32
ReplayGainAlbumPeak() float32
Length() int
Bitrate() int
Year() int
}
const (

View File

@@ -51,8 +51,14 @@ func (i *info) Genres() []string { return find(i.raw, "genres") }
func (i *info) TrackNumber() int { return intSep("/", first(find(i.raw, "tracknumber"))) } // eg. 5/12
func (i *info) DiscNumber() int { return intSep("/", first(find(i.raw, "discnumber"))) } // eg. 1/2
func (i *info) Year() int { return intSep("-", first(find(i.raw, "originaldate", "date", "year"))) } // eg. 2023-12-01
func (i *info) Length() int { return i.props.Length }
func (i *info) Bitrate() int { return i.props.Bitrate }
func (i *info) ReplayGainTrackGain() float32 { return dB(first(find(i.raw, "replaygain_track_gain"))) }
func (i *info) ReplayGainTrackPeak() float32 { return flt(first(find(i.raw, "replaygain_track_peak"))) }
func (i *info) ReplayGainAlbumGain() float32 { return dB(first(find(i.raw, "replaygain_album_gain"))) }
func (i *info) ReplayGainAlbumPeak() float32 { return flt(first(find(i.raw, "replaygain_album_peak"))) }
func (i *info) Length() int { return i.props.Length }
func (i *info) Bitrate() int { return i.props.Bitrate }
func first[T comparable](is []T) T {
var z T
@@ -83,6 +89,17 @@ func filterStr(ss []string) []string {
return r
}
func flt(in string) float32 {
f, _ := strconv.ParseFloat(in, 32)
return float32(f)
}
func dB(in string) float32 {
in = strings.ToLower(in)
in = strings.TrimSuffix(in, " db")
in = strings.TrimSuffix(in, "db")
return flt(in)
}
func intSep(sep, in string) int {
start, _, _ := strings.Cut(in, sep)
out, _ := strconv.Atoi(start)