db

package
v0.0.0-...-15592ba Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 18, 2023 License: BSD-3-Clause Imports: 14 Imported by: 0

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

View Source
const (
	// Datastore kinds of various objects.
	PlayKind        = "Play"
	SongKind        = "Song"
	DeletedPlayKind = "DeletedPlay"
	DeletedSongKind = "DeletedSong"
)
View Source
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 DiffSongs

func DiffSongs(a, b *Song) string

DiffSongs diffs a and b and returns a multiline string describing differences.

func Normalize

func Normalize(s string) (string, error)

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.

func NewPlay

func NewPlay(t time.Time, ip string) Play

func (*Play) Equal

func (p *Play) Equal(o *Play) bool

type PlayArray

type PlayArray []Play

func (PlayArray) Len

func (a PlayArray) Len() int

func (PlayArray) Less

func (a PlayArray) Less(i, j int) bool

func (PlayArray) Swap

func (a PlayArray) Swap(i, j int)

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

func (s *Song) Load(orig []datastore.Property) error

Load implements datastore.PropertyLoadSaver. A custom implementation is needed to handle old DeletedSong entities.

func (Song) MarshalJSON

func (s Song) MarshalJSON() ([]byte, error)

MarshalJSON uses a disgusting hack from https://stackoverflow.com/a/60567000 to omit "Date" fields that have the zero value.

func (*Song) MetadataEquals

func (s *Song) MetadataEquals(o *Song) bool

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

func (s *Song) RebuildPlayStats(plays []Play)

RebuildPlayStats regenerates NumPlays, FirstStartTime, and LastStartTime based on the supplied plays.

func (*Song) Save

func (s *Song) Save() ([]datastore.Property, error)

Save implements datastore.PropertyLoadSaver.

func (*Song) SetRating

func (s *Song) SetRating(r int)

SetRating sets Rating to r and updates RatingAtLeast*.

func (*Song) Update

func (dst *Song) Update(src *Song, copyUserData bool) error

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

func (s *Song) UpdatePlayStats(startTime time.Time)

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.

func NewStats

func NewStats() *Stats

NewStats returns a new Stats struct with all fields initialized to 0.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL