channels

package
v1.1.0 Latest Latest
Warning

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

Go to latest
Published: Mar 5, 2026 License: MIT Imports: 6 Imported by: 0

Documentation

Index

Constants

View Source
const (
	ChannelClassTraditional      = "traditional"
	ChannelClassDynamicGenerated = "dynamic_generated"
)
View Source
const (
	TraditionalGuideStart = 100
	TraditionalGuideEnd   = 9999

	DynamicGuideStart       = 10000
	DynamicGuideBlockSize   = 1000
	DynamicGuideBlockMaxLen = 1000
)

Variables

View Source
var (
	ErrItemNotFound         = errors.New("playlist item not found")
	ErrChannelNotFound      = errors.New("channel not found")
	ErrSourceNotFound       = errors.New("channel source not found")
	ErrSourceOrderDrift     = errors.New("channel source set changed")
	ErrDynamicQueryNotFound = errors.New("dynamic channel query not found")
	ErrAssociationMismatch  = errors.New("source metadata does not match channel metadata")
)

Functions

func DynamicChannelOrderIndex

func DynamicChannelOrderIndex(orderIndex, position int) (int, error)

func DynamicGuideBlockStart

func DynamicGuideBlockStart(orderIndex int) (int, error)

func DynamicGuideNumber

func DynamicGuideNumber(orderIndex, position int) (int, error)

func GroupNameAlias

func GroupNameAlias(groupNames []string) string

GroupNameAlias returns the legacy single-group alias for compatibility.

func NormalizeGroupNames

func NormalizeGroupNames(groupName string, groupNames []string) []string

NormalizeGroupNames trims, deduplicates, and deterministically orders dynamic filter group selectors. Legacy single-group callers can pass groupName with an empty groupNames slice.

func NormalizeSourceIDs added in v1.1.0

func NormalizeSourceIDs(sourceIDs []int64) []int64

NormalizeSourceIDs deduplicates and deterministically orders source selectors. Non-positive source IDs are ignored.

func ValidateSourceIDs added in v1.1.0

func ValidateSourceIDs(sourceIDs []int64, field string) error

ValidateSourceIDs reports an input validation error when source selectors contain non-positive values.

Types

type Channel

type Channel struct {
	ChannelID      int64             `json:"channel_id"`
	ChannelClass   string            `json:"channel_class,omitempty"`
	ChannelKey     string            `json:"channel_key,omitempty"`
	GuideNumber    string            `json:"guide_number"`
	GuideName      string            `json:"guide_name"`
	OrderIndex     int               `json:"order_index"`
	Enabled        bool              `json:"enabled"`
	DynamicQueryID int64             `json:"dynamic_query_id,omitempty"`
	DynamicItemKey string            `json:"dynamic_item_key,omitempty"`
	DynamicRule    DynamicSourceRule `json:"dynamic_rule"`
	SourceTotal    int               `json:"source_total"`
	SourceEnabled  int               `json:"source_enabled"`
	SourceDynamic  int               `json:"source_dynamic"`
	SourceManual   int               `json:"source_manual"`
}

Channel is a published HDHomeRun channel entry.

type DuplicateGroup

type DuplicateGroup struct {
	ChannelKey string          `json:"channel_key"`
	Count      int             `json:"count"`
	Items      []DuplicateItem `json:"items"`
}

DuplicateGroup is a grouped set of catalog items sharing the same channel key.

type DuplicateItem

type DuplicateItem struct {
	ItemKey            string `json:"item_key"`
	Name               string `json:"name"`
	GroupName          string `json:"group_name"`
	TVGID              string `json:"tvg_id,omitempty"`
	StreamURL          string `json:"stream_url,omitempty"`
	PlaylistSourceID   int64  `json:"playlist_source_id,omitempty"`
	PlaylistSourceName string `json:"playlist_source_name,omitempty"`
	Active             bool   `json:"active"`
}

DuplicateItem is one catalog item included in a duplicate suggestion group.

type DynamicChannelQuery

type DynamicChannelQuery struct {
	QueryID     int64    `json:"query_id"`
	Enabled     bool     `json:"enabled"`
	Name        string   `json:"name"`
	GroupName   string   `json:"group_name"`
	GroupNames  []string `json:"group_names,omitempty"`
	SourceIDs   []int64  `json:"source_ids"`
	SearchQuery string   `json:"search_query"`
	SearchRegex bool     `json:"search_regex,omitempty"`
	// NextSlotCursor tracks where new dynamic matches should be placed next.
	NextSlotCursor int   `json:"next_slot_cursor"`
	OrderIndex     int   `json:"order_index"`
	CreatedAt      int64 `json:"created_at"`
	UpdatedAt      int64 `json:"updated_at"`
	LastCount      int   `json:"last_count"`
	TruncatedBy    int   `json:"truncated_by"`
}

DynamicChannelQuery stores one dynamic block query configuration.

type DynamicChannelQueryCreate

type DynamicChannelQueryCreate struct {
	Enabled     *bool    `json:"enabled,omitempty"`
	Name        string   `json:"name"`
	GroupName   string   `json:"group_name"`
	GroupNames  []string `json:"group_names,omitempty"`
	SourceIDs   []int64  `json:"source_ids"`
	SearchQuery string   `json:"search_query"`
	SearchRegex bool     `json:"search_regex,omitempty"`
}

DynamicChannelQueryCreate carries create-time fields for one dynamic query block.

type DynamicChannelQueryUpdate

type DynamicChannelQueryUpdate struct {
	Enabled     *bool     `json:"enabled,omitempty"`
	Name        *string   `json:"name,omitempty"`
	GroupName   *string   `json:"group_name,omitempty"`
	GroupNames  *[]string `json:"group_names,omitempty"`
	SourceIDs   *[]int64  `json:"source_ids,omitempty"`
	SearchQuery *string   `json:"search_query,omitempty"`
	SearchRegex *bool     `json:"search_regex,omitempty"`
}

DynamicChannelQueryUpdate carries mutable fields for one dynamic query block.

type DynamicChannelSyncResult

type DynamicChannelSyncResult struct {
	QueriesProcessed int `json:"queries_processed"`
	QueriesEnabled   int `json:"queries_enabled"`
	ChannelsAdded    int `json:"channels_added"`
	ChannelsUpdated  int `json:"channels_updated"`
	ChannelsRetained int `json:"channels_retained"`
	ChannelsRemoved  int `json:"channels_removed"`
	TruncatedCount   int `json:"truncated_count"`
}

DynamicChannelSyncResult summarizes one full dynamic block materialization run.

type DynamicSourceRule

type DynamicSourceRule struct {
	Enabled     bool     `json:"enabled"`
	GroupName   string   `json:"group_name"`
	GroupNames  []string `json:"group_names,omitempty"`
	SourceIDs   []int64  `json:"source_ids"`
	SearchQuery string   `json:"search_query"`
	SearchRegex bool     `json:"search_regex,omitempty"`
}

DynamicSourceRule defines one catalog-filter rule used to manage dynamic channel sources.

type DynamicSourceSyncResult

type DynamicSourceSyncResult struct {
	Added    int `json:"added"`
	Removed  int `json:"removed"`
	Retained int `json:"retained"`
}

DynamicSourceSyncResult summarizes one dynamic source synchronization run.

type Service

type Service struct {
	// contains filtered or unexported fields
}

Service provides business operations for published channels and source mappings.

func NewService

func NewService(store Store) *Service

func NewServiceWithStartGuideNumber added in v1.0.6

func NewServiceWithStartGuideNumber(store Store, startGuideNumber int) *Service

func (*Service) AddSource

func (s *Service) AddSource(ctx context.Context, channelID int64, itemKey string, allowCrossChannel bool) (Source, error)

func (*Service) ClearAllSourceHealth

func (s *Service) ClearAllSourceHealth(ctx context.Context) (int64, error)

func (*Service) ClearSourceHealth

func (s *Service) ClearSourceHealth(ctx context.Context, channelID int64) (int64, error)

func (*Service) Create

func (s *Service) Create(ctx context.Context, itemKey, guideName, channelKey string, dynamicRule *DynamicSourceRule) (Channel, error)

func (*Service) CreateDynamicChannelQuery

func (s *Service) CreateDynamicChannelQuery(ctx context.Context, create DynamicChannelQueryCreate) (DynamicChannelQuery, error)

func (*Service) Delete

func (s *Service) Delete(ctx context.Context, channelID int64) error

func (*Service) DeleteDynamicChannelQuery

func (s *Service) DeleteDynamicChannelQuery(ctx context.Context, queryID int64) error

func (*Service) DeleteSource

func (s *Service) DeleteSource(ctx context.Context, channelID, sourceID int64) error

func (*Service) DuplicateSuggestions

func (s *Service) DuplicateSuggestions(ctx context.Context, minItems int, searchQuery string, limit, offset int) ([]DuplicateGroup, int, error)

func (*Service) GetByGuideNumber

func (s *Service) GetByGuideNumber(ctx context.Context, guideNumber string) (Channel, error)

func (*Service) GetDynamicChannelQuery

func (s *Service) GetDynamicChannelQuery(ctx context.Context, queryID int64) (DynamicChannelQuery, error)

func (*Service) GetSource

func (s *Service) GetSource(ctx context.Context, channelID, sourceID int64, enabledOnly bool) (Source, error)

func (*Service) List

func (s *Service) List(ctx context.Context) ([]Channel, error)

func (*Service) ListDynamicChannelQueries

func (s *Service) ListDynamicChannelQueries(ctx context.Context) ([]DynamicChannelQuery, error)

func (*Service) ListDynamicChannelQueriesPaged

func (s *Service) ListDynamicChannelQueriesPaged(ctx context.Context, limit, offset int) ([]DynamicChannelQuery, int, error)

func (*Service) ListDynamicGeneratedChannelsPaged

func (s *Service) ListDynamicGeneratedChannelsPaged(ctx context.Context, queryID int64, limit, offset int) ([]Channel, int, error)

func (*Service) ListEnabled

func (s *Service) ListEnabled(ctx context.Context) ([]Channel, error)

func (*Service) ListPaged

func (s *Service) ListPaged(ctx context.Context, limit, offset int) ([]Channel, int, error)

func (*Service) ListSources

func (s *Service) ListSources(ctx context.Context, channelID int64, enabledOnly bool) ([]Source, error)

func (*Service) ListSourcesByChannelIDs

func (s *Service) ListSourcesByChannelIDs(ctx context.Context, channelIDs []int64, enabledOnly bool) (map[int64][]Source, error)

func (*Service) ListSourcesPaged

func (s *Service) ListSourcesPaged(ctx context.Context, channelID int64, enabledOnly bool, limit, offset int) ([]Source, int, error)

func (*Service) MarkSourceFailure

func (s *Service) MarkSourceFailure(ctx context.Context, sourceID int64, reason string, failedAt time.Time) error

func (*Service) MarkSourceSuccess

func (s *Service) MarkSourceSuccess(ctx context.Context, sourceID int64, succeededAt time.Time) error

func (*Service) RefreshDynamicGeneratedGuideNames

func (s *Service) RefreshDynamicGeneratedGuideNames(ctx context.Context) (int, error)

func (*Service) Reorder

func (s *Service) Reorder(ctx context.Context, channelIDs []int64) error

func (*Service) ReorderDynamicGeneratedChannels

func (s *Service) ReorderDynamicGeneratedChannels(ctx context.Context, queryID int64, channelIDs []int64) error

func (*Service) ReorderSources

func (s *Service) ReorderSources(ctx context.Context, channelID int64, sourceIDs []int64) error

func (*Service) SupportsSourceScopedDynamicChannelBlocks added in v1.1.0

func (s *Service) SupportsSourceScopedDynamicChannelBlocks() bool

SupportsSourceScopedDynamicChannelBlocks reports whether the backing store can materialize dynamic channel blocks with source-scoped query filters.

func (*Service) SyncDynamicChannelBlocks

func (s *Service) SyncDynamicChannelBlocks(ctx context.Context) (DynamicChannelSyncResult, error)

func (*Service) SyncDynamicSources

func (s *Service) SyncDynamicSources(ctx context.Context, channelID int64, matchedItemKeys []string) (DynamicSourceSyncResult, error)

func (*Service) SyncDynamicSourcesByCatalogFilter

func (s *Service) SyncDynamicSourcesByCatalogFilter(
	ctx context.Context,
	channelID int64,
	groupNames []string,
	searchQuery string,
	searchRegex bool,
	pageSize int,
	maxMatches int,
) (DynamicSourceSyncResult, int, error)

SyncDynamicSourcesByCatalogFilter synchronizes dynamic sources for one channel by streaming catalog-filter matches in bounded pages when supported by the backing store.

func (*Service) SyncDynamicSourcesByCatalogFilterWithSourceIDs added in v1.1.0

func (s *Service) SyncDynamicSourcesByCatalogFilterWithSourceIDs(
	ctx context.Context,
	channelID int64,
	sourceIDs []int64,
	groupNames []string,
	searchQuery string,
	searchRegex bool,
	pageSize int,
	maxMatches int,
) (DynamicSourceSyncResult, int, error)

SyncDynamicSourcesByCatalogFilterWithSourceIDs synchronizes dynamic sources for one channel by streaming catalog-filter matches in bounded pages when supported by the backing store, optionally scoping matches to playlist source IDs.

func (*Service) Update

func (s *Service) Update(ctx context.Context, channelID int64, guideName *string, enabled *bool, dynamicRule *DynamicSourceRule) (Channel, error)

func (*Service) UpdateDynamicChannelQuery

func (s *Service) UpdateDynamicChannelQuery(ctx context.Context, queryID int64, update DynamicChannelQueryUpdate) (DynamicChannelQuery, error)

func (*Service) UpdateSource

func (s *Service) UpdateSource(ctx context.Context, channelID, sourceID int64, enabled *bool) (Source, error)

func (*Service) UpdateSourceProfile

func (s *Service) UpdateSourceProfile(ctx context.Context, sourceID int64, profile SourceProfileUpdate) error

type Source

type Source struct {
	SourceID             int64   `json:"source_id"`
	ChannelID            int64   `json:"channel_id"`
	ItemKey              string  `json:"item_key"`
	TVGName              string  `json:"tvg_name,omitempty"`
	StreamURL            string  `json:"stream_url,omitempty"`
	PlaylistSourceID     int64   `json:"playlist_source_id,omitempty"`
	PlaylistSourceName   string  `json:"playlist_source_name,omitempty"`
	PlaylistSourceTuners int     `json:"playlist_source_tuner_count,omitempty"`
	PriorityIndex        int     `json:"priority_index"`
	Enabled              bool    `json:"enabled"`
	AssociationType      string  `json:"association_type"`
	LastOKAt             int64   `json:"last_ok_at,omitempty"`
	LastFailAt           int64   `json:"last_fail_at,omitempty"`
	LastFailReason       string  `json:"last_fail_reason,omitempty"`
	SuccessCount         int     `json:"success_count"`
	FailCount            int     `json:"fail_count"`
	CooldownUntil        int64   `json:"cooldown_until"`
	LastProbeAt          int64   `json:"last_probe_at,omitempty"`
	ProfileWidth         int     `json:"profile_width,omitempty"`
	ProfileHeight        int     `json:"profile_height,omitempty"`
	ProfileFPS           float64 `json:"profile_fps,omitempty"`
	ProfileVideoCodec    string  `json:"profile_video_codec,omitempty"`
	ProfileAudioCodec    string  `json:"profile_audio_codec,omitempty"`
	ProfileBitrateBPS    int64   `json:"profile_bitrate_bps,omitempty"`
}

Source is an ordered failover source attached to a channel.

type SourceProfileUpdate

type SourceProfileUpdate struct {
	LastProbeAt time.Time
	Width       int
	Height      int
	FPS         float64
	VideoCodec  string
	AudioCodec  string
	BitrateBPS  int64
}

SourceProfileUpdate carries persisted stream-profile metadata for one source.

type Store

type Store interface {
	CreateChannelFromItem(ctx context.Context, itemKey, guideName, channelKey string, dynamicRule *DynamicSourceRule, startGuideNumber int) (Channel, error)
	DeleteChannel(ctx context.Context, channelID int64, startGuideNumber int) error
	ListChannels(ctx context.Context, enabledOnly bool) ([]Channel, error)
	ListChannelsPaged(ctx context.Context, enabledOnly bool, limit, offset int) ([]Channel, int, error)
	ListLineupChannels(ctx context.Context) ([]Channel, error)
	ReorderChannels(ctx context.Context, channelIDs []int64, startGuideNumber int) error
	UpdateChannel(ctx context.Context, channelID int64, guideName *string, enabled *bool, dynamicRule *DynamicSourceRule) (Channel, error)
	GetChannelByGuideNumber(ctx context.Context, guideNumber string) (Channel, error)
	SyncDynamicChannelBlocks(ctx context.Context) (DynamicChannelSyncResult, error)
	ListDynamicChannelQueries(ctx context.Context) ([]DynamicChannelQuery, error)
	ListDynamicChannelQueriesPaged(ctx context.Context, limit, offset int) ([]DynamicChannelQuery, int, error)
	GetDynamicChannelQuery(ctx context.Context, queryID int64) (DynamicChannelQuery, error)
	CreateDynamicChannelQuery(ctx context.Context, create DynamicChannelQueryCreate) (DynamicChannelQuery, error)
	UpdateDynamicChannelQuery(ctx context.Context, queryID int64, update DynamicChannelQueryUpdate) (DynamicChannelQuery, error)
	DeleteDynamicChannelQuery(ctx context.Context, queryID int64) error
	ListDynamicGeneratedChannelsPaged(ctx context.Context, queryID int64, limit, offset int) ([]Channel, int, error)
	ReorderDynamicGeneratedChannels(ctx context.Context, queryID int64, channelIDs []int64) error
	GetSource(ctx context.Context, channelID, sourceID int64, enabledOnly bool) (Source, error)
	ListSources(ctx context.Context, channelID int64, enabledOnly bool) ([]Source, error)
	ListSourcesPaged(ctx context.Context, channelID int64, enabledOnly bool, limit, offset int) ([]Source, int, error)
	AddSource(ctx context.Context, channelID int64, itemKey string, allowCrossChannel bool) (Source, error)
	DeleteSource(ctx context.Context, channelID, sourceID int64) error
	ReorderSources(ctx context.Context, channelID int64, sourceIDs []int64) error
	UpdateSource(ctx context.Context, channelID, sourceID int64, enabled *bool) (Source, error)
	SyncDynamicSources(ctx context.Context, channelID int64, matchedItemKeys []string) (DynamicSourceSyncResult, error)
	MarkSourceFailure(ctx context.Context, sourceID int64, reason string, failedAt time.Time) error
	MarkSourceSuccess(ctx context.Context, sourceID int64, succeededAt time.Time) error
	UpdateSourceProfile(ctx context.Context, sourceID int64, profile SourceProfileUpdate) error
	ClearSourceHealth(ctx context.Context, channelID int64) (int64, error)
	ClearAllSourceHealth(ctx context.Context) (int64, error)
	ListDuplicateSuggestions(ctx context.Context, minItems int, searchQuery string, limit, offset int) ([]DuplicateGroup, int, error)
}

Store captures persistence operations required by channel management.

Jump to

Keyboard shortcuts

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