streamstore

package
v0.1.1 Latest Latest
Warning

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

Go to latest
Published: Oct 9, 2026 License: MIT Imports: 12 Imported by: 0

Documentation

Overview

Package streamstore keeps the plays and stream health events the stream recorder sees, one SQLite database per profile, and answers history, report, and export queries over them.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Gap

type Gap struct {
	From time.Time `json:"from"`
	To   time.Time `json:"to"`
}

Gap is a period the store has no recording for.

type HealthEvent

type HealthEvent struct {
	RadioID int       `json:"radio_id"`
	At      time.Time `json:"at"`
	Code    int       `json:"code"` // AudD notification code, e.g. 650 can't connect, 651 no music; 0 for running-state changes
	Message string    `json:"message"`
	Running bool      `json:"running"`
}

HealthEvent is a stream status change (AudD notification or a change in the stream_running flag).

type Play

type Play struct {
	RadioID     int             `json:"radio_id"`
	Timestamp   time.Time       `json:"timestamp"`
	PlayLength  int             `json:"play_length"` // seconds; 0 when unknown
	Artist      string          `json:"artist"`
	Title       string          `json:"title"`
	Album       string          `json:"album"`
	Label       string          `json:"label"`
	ReleaseDate string          `json:"release_date"`
	ISRC        string          `json:"isrc"`
	UPC         string          `json:"upc"`
	SongLink    string          `json:"song_link"`
	Score       int             `json:"score"`
	Raw         json.RawMessage `json:"-"` // the song object as AudD sent it
}

Play is one recognized song on a stream.

func (Play) MarshalJSON

func (p Play) MarshalJSON() ([]byte, error)

MarshalJSON writes the typed fields, then every other field of the song object as AudD sent it (provider blocks such as apple_music or spotify, and fields this version does not know), under their API names.

type ReportRow

type ReportRow struct {
	Key      string
	Plays    int
	Airtime  time.Duration
	Stations int
}

ReportRow is one line of a report.

type Store

type Store struct {

	// Now is the clock used for gap detection.
	Now func() time.Time
	// contains filtered or unexported fields
}

Store is a stream store database. It is safe for concurrent use, and several processes may write the same file.

func Open

func Open(profile string) (*Store, error)

Open opens DataDir()/streams-<profile>.db.

func OpenPath

func OpenPath(path string) (*Store, error)

OpenPath opens a stream store at an explicit path.

func (*Store) AccountStreams

func (s *Store) AccountStreams() ([]int, error)

AccountStreams returns the streams the account had when it was last listed, in radio ID order (empty when it was never listed).

func (*Store) AddHealth

func (s *Store) AddHealth(h HealthEvent) error

AddHealth stores a health event.

func (*Store) AddPlay

func (s *Store) AddPlay(p Play) (inserted bool, err error)

AddPlay stores a play unless one with the same stream and timestamp (to the second) exists. inserted reports whether it was new.

func (*Store) Close

func (s *Store) Close() error

Close closes the database.

func (*Store) CountPlays

func (s *Store) CountPlays() (int, error)

CountPlays returns the number of stored plays.

func (*Store) Cover

func (s *Store) Cover(from, to time.Time, radioIDs ...int) error

Cover records that the store is complete for a period for the given streams (for example after a backfill from the recent-results endpoint reached back that far). Without IDs it covers every stream.

func (*Store) Earliest

func (s *Store) Earliest() (time.Time, error)

Earliest returns the oldest point the store knows about: the start of the first recorded period or the first play, whichever is older (zero when the store is empty).

func (*Store) Gaps

func (s *Store) Gaps(since time.Time, radioIDs ...int) ([]Gap, error)

Gaps returns the periods since a time (up to now) that no recorder heartbeat or backfill covers, for the given streams; a period missing for any one of them is a gap. Without IDs it checks the streams the account had when last listed (or, if it was never listed, every stream the store knows). Gaps shorter than two minutes are left out. A zero since means all time: gaps then start at Earliest, and an empty store has none. A stream first seen on the account after the store began recording has no gap before it was seen.

func (*Store) HasStreams

func (s *Store) HasStreams() (bool, error)

HasStreams reports whether the account has streams or the store has plays or coverage for any.

func (*Store) Heartbeat

func (s *Store) Heartbeat(at time.Time, radioIDs ...int) error

Heartbeat records that a recorder was running and connected at a time for the given streams. Without IDs it records it for every stream.

func (*Store) History

func (s *Store) History(radioID *int, since time.Time, limit int) ([]Play, error)

History returns plays newest first. radioID nil means all streams; a zero since means all time; limit 0 means no limit.

func (*Store) LastHeartbeat

func (s *Store) LastHeartbeat(radioIDs ...int) (time.Time, error)

LastHeartbeat returns the end of the newest recorded period (zero if none). With IDs it is the oldest of those streams' newest periods: the time up to which all of them were recorded (zero when any has none).

func (*Store) Latest

func (s *Store) Latest(radioID int) (*Play, error)

Latest returns the most recent play on a stream, or nil.

func (*Store) LatestHealth

func (s *Store) LatestHealth(radioID int) (*HealthEvent, error)

LatestHealth returns the last health event stored for a stream, or nil.

func (*Store) Meta

func (s *Store) Meta(key string) (string, error)

Meta reads a value stored with SetMeta ("" when absent).

func (*Store) Path

func (s *Store) Path() string

Path is the database file.

func (*Store) Report

func (s *Store) Report(by string, since time.Time) ([]ReportRow, error)

Report groups plays since a time. by is song, artist, label, or station. Rows are ordered by plays, then airtime, then key.

func (*Store) SetAccountStreams

func (s *Store) SetAccountStreams(radioIDs []int, at time.Time) error

SetAccountStreams records the streams the account has now. A stream seen for the first time is remembered with the time it was first seen, so a stream added later does not show the time before it existed as a gap.

func (*Store) SetMeta

func (s *Store) SetMeta(key, value string) error

SetMeta stores a small value (recorder status notes).

Jump to

Keyboard shortcuts

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