Documentation ¶
Overview ¶
Package db defines database-related types and constants.
This package should not have any dependencies beyond the standard library, as it's loaded by many other packages.
Index ¶
- Constants
- func DiffSongs(a, b *Song) string
- func Normalize(s string) (string, error)
- type Play
- type PlayArray
- type PlayDump
- type PlayStats
- type Song
- func (s *Song) Clean()
- func (s *Song) Load(orig []datastore.Property) error
- func (s Song) MarshalJSON() ([]byte, error)
- func (s *Song) MetadataEquals(o *Song) bool
- func (s *Song) RebuildPlayStats(plays []Play)
- func (s *Song) Save() ([]datastore.Property, error)
- func (s *Song) SetRating(r int)
- func (dst *Song) Update(src *Song, copyUserData bool) error
- func (s *Song) UpdatePlayStats(startTime time.Time)
- type Stats
Constants ¶
const ( // Datastore kinds of various objects. PlayKind = "Play" SongKind = "Song" DeletedPlayKind = "DeletedPlay" DeletedSongKind = "DeletedSong" )
const ( // StatsKind is the Stats struct's Datastore kind. StatsKind = "Stats" // StatsKeyName is the Stats struct's key name for both Datastore and memcache. StatsKeyName = "stats" )
Variables ¶
This section is empty.
Functions ¶
func Normalize ¶
Normalize normalizes s for searches.
NFKD form is used. Unicode characters are decomposed (runes are broken into their components) and replaced for compatibility equivalence (characters that represent the same characters but have different visual representations, e.g. '9' and '⁹', are equal). Visually-similar characters from different alphabets will not be equal, however (e.g. Latin 'o', Greek 'ο', and Cyrillic 'о'). See https://go.dev/blog/normalization for more details.
Characters are also de-accented and lowercased, but punctuation is preserved.
Types ¶
type Play ¶
type Play struct { // StartTime is the time at which playback started. StartTime time.Time `json:"t"` // IPAddress is the IPv4 or IPv6 address of the client playing the song. IPAddress string `datastore:"IpAddress" json:"ip"` }
Play represents one playback of a Song.
type PlayDump ¶
type PlayDump struct { // Song entity's key ID from Datastore. SongID string `json:"songId"` // Play information. Play Play `json:"play"` }
PlayDump is used when dumping data.
type PlayStats ¶
type PlayStats struct { // Plays is the number of plays. Plays int `json:"plays"` // TotalSec is the total duration in seconds of played songs. TotalSec float64 `json:"totalSec"` // FirstPlays is the number of songs that were first played in the interval. FirstPlays int `json:"firstPlays"` // LastPlays is the number of songs that were last played in the interval. LastPlays int `json:"lastPlays"` }
PlayStats summarizes plays in a time interval.
type Song ¶
type Song struct { // SHA1 is a hash of the audio portion of the file. SHA1 string `datastore:"Sha1" json:"sha1,omitempty"` // SongID is the Song entity's key ID from Datastore. Only set in search results. SongID string `datastore:"-" json:"songId,omitempty"` // Filename is a relative path from the base of the music directory. // Clients can pass this to the server's /song endpoint to download the // song's music data. Filename string `json:"filename,omitempty"` // CoverFilename is a relative path from the base of the covers directory. // Must be escaped for Cloud Storage when constructing CoverURL. // Clients can pass this to the server's /cover endpoint to get a scaled // copy of the cover. CoverFilename string `datastore:",noindex" json:"coverFilename,omitempty"` // Canonical versions used for display. Artist string `datastore:",noindex" json:"artist"` Title string `datastore:",noindex" json:"title"` Album string `datastore:",noindex" json:"album"` // Lowercase versions used for searching and sorting. // Additional normalization is performed: see query.Normalize. ArtistLower string `json:"-"` TitleLower string `json:"-"` AlbumLower string `json:"-"` // AlbumArtist contains the album's artist if it isn't the same as Artist. // This corresponds to the TPE2 ID3 tag, which may hold the performer name // in the case of a classical album, or the remixer name in the case of an // album consisting of songs remixed by a single artist. AlbumArtist string `datastore:",noindex" json:"albumArtist,omitempty"` // DiscSubtitle contains the disc's subtitle, if any. DiscSubtitle string `json:"discSubtitle,omitempty"` // Keywords contains words from ArtistLower, TitleLower, AlbumLower, and // AlbumArtist and DiscSubtitle (after normalization). It is used for searching. Keywords []string `json:"-"` // AlbumID is an opaque ID uniquely identifying the album // (generally, a MusicBrainz release ID taken from a "MusicBrainz Album Id" ID3v2 tag). AlbumID string `datastore:"AlbumId" json:"albumId,omitempty"` // CoverID is an opaque ID from a "nup Cover Id" ID3v2 tag used to specify cover art. // If unset, AlbumID and then RecordingID is used when looking for art. CoverID string `datastore:"-" json:"-"` // RecordingID is an opaque ID uniquely identifying the recording (generally, the MusicBrainz ID // corresponding to the MusicBrainz recording entity, taken from a UFID ID3v2 tag). // This is used to find cover art if neither AlbumID nor CoverID is set. // It is also used to find updated metadata for the song in MusicBrainz. RecordingID string `datastore:"-" json:"-"` // OrigAlbumID and OrigRecordingID contain the original values of AlbumID and RecordingID // if they were overridden by JSON files. These are only used by the client. OrigAlbumID string `datastore:"-" json:"-"` OrigRecordingID string `datastore:"-" json:"-"` // Track is the song's track number, or 0 if unset. Track int `json:"track"` // Disc is the song's disc number, or 0 if unset. Disc int `json:"disc"` // Date is the date on which this song was recorded or released in UTC. // It is used when listing songs or albums in chronological order. // This is vaguely defined because the ID3v2 fields related to it are a mess: // https://github.com/derat/nup/issues/42 Date time.Time `json:"date,omitempty"` // Length is the song's duration in seconds. Length float64 `json:"length"` // TrackGain is the song's dB gain adjustment independent of its album. More info: // https://en.wikipedia.org/wiki/ReplayGain // https://wiki.hydrogenaud.io/index.php?title=ReplayGain_specification // https://productionadvice.co.uk/tidal-normalization-upgrade/ TrackGain float64 `datastore:",noindex" json:"trackGain"` // AlbumGain is the song's dB gain adjustment relative to its album. AlbumGain float64 `datastore:",noindex" json:"albumGain"` // PeakAmp is the song's peak amplitude, with 1.0 representing the highest // amplitude that can be played without clipping. PeakAmp float64 `datastore:",noindex" json:"peakAmp"` // Rating is the song's rating in the range [1, 5], or 0 if unrated. // The server should call SetRating to additionally update the RatingAtLeast* fields. Rating int `json:"rating"` // RatingAtLeast* are true if Rating is at least the specified value. // These are maintained to sidestep Datastore's restriction against using multiple // inequality filters in a query. RatingAtLeast1 bool `json:"-"` RatingAtLeast2 bool `json:"-"` RatingAtLeast3 bool `json:"-"` RatingAtLeast4 bool `json:"-"` // FirstStartTime is the first time the song was played. FirstStartTime time.Time `json:"-"` // LastStartTime is the last time the song was played. LastStartTime time.Time `json:"-"` // NumPlays is the number of times the song has been played. NumPlays int `json:"-"` // Plays contains the song's playback history. // Only used for importing data -- in Datastore, Play is a descendant of Song. Plays []Play `datastore:"-" json:"plays,omitempty"` // Tags contains tags assigned to the song by the user. Tags []string `json:"tags"` // LastModifiedTime is the time that the song was modified. LastModifiedTime time.Time `json:"-"` }
Song represents an audio file and holds metadata and user-generated data.
When adding fields, the MetadataEquals and Update methods must be updated.
func (*Song) Clean ¶
func (s *Song) Clean()
Clean sorts and removes duplicates from slice fields in s.
func (*Song) Load ¶
Load implements datastore.PropertyLoadSaver. A custom implementation is needed to handle old DeletedSong entities.
func (Song) MarshalJSON ¶
MarshalJSON uses a disgusting hack from https://stackoverflow.com/a/60567000 to omit "Date" fields that have the zero value.
func (*Song) MetadataEquals ¶
MetadataEquals returns true if s and o have identical metadata. User data (ratings, plays, tags) and server-managed fields are not checked.
func (*Song) RebuildPlayStats ¶
RebuildPlayStats regenerates NumPlays, FirstStartTime, and LastStartTime based on the supplied plays.
func (*Song) Update ¶
Update copies fields from src to dst.
If copyUserData is true, the Rating*, FirstStartTime, LastStartTime, NupPlays, and Tags fields are also copied; otherwise they are left unchanged.
ArtistLower, TitleLower, AlbumLower, and Keywords are also initialized in dst, and Clean is called.
func (*Song) UpdatePlayStats ¶
UpdatePlayStats updates NumPlays, FirstStartTime, and LastStartTime to reflect an additional play starting at startTime.
type Stats ¶
type Stats struct { // Songs is the total number of songs in the database. Songs int `json:"songs"` // Albums is the total number of albums in the database. // This is computed by counting distinct Song.AlbumID values. Albums int `json:"albums"` // TotalSec is the total duration in seconds of all songs. TotalSec float64 `json:"totalSec"` // Ratings maps from a rating in [1, 5] (or 0 for unrated) to number of songs with that rating. Ratings map[int]int `json:"ratings"` // SongDecades maps from the year at the beginning of a decade (e.g. 1990) to the number of // songs in the database with a Date field in the decade. 0 is used for songs with unset dates. SongDecades map[int]int `json:"songDecades"` // Tags maps from tag to number of songs with that tag. Tags map[string]int `json:"tags"` // Years maps from year (e.g. 2020) to stats about plays in that year. Years map[int]PlayStats `json:"years"` // UpdateTime is the time at which these stats were generated. UpdateTime time.Time `json:"updateTime"` }
Stats summarizes information from the database.