Documentation
¶
Overview ¶
AIClient provides typed access to AI capabilities (embedding, chat).
This client wraps the low-level Invoke calls and handles proto marshaling internally, so plugin code doesn't need to import proto or pluginv1.
Usage ¶
ai := sdk.NewAIClient(plugins)
// Generate embeddings
embedding, err := ai.GenerateEmbedding(ctx, "hello world")
// Chat completion
resp, err := ai.Chat(ctx, sdk.ChatRequest{
Messages: []sdk.ChatMessage{
{Role: "user", Content: "Hello!"},
},
})
Package sdk provides utilities for building ViewRA plugins.
The SDK provides common functionality that all plugins need:
- Logging with request ID tracking
- Metrics collection
- Data directory access
- Settings schema building
Plugin Structure ¶
All plugins embed sdk.Base to get common functionality:
type MyPlugin struct {
sdk.Base
// your fields
}
Logging ¶
Use sdk.NewLogger in your main() to create properly configured loggers:
func main() {
hclogger, logger := sdk.NewLogger("my-plugin")
plugin := NewMyPlugin(logger)
// ... serve plugin
}
Then use p.Log() or p.LogWithContext(ctx) in your plugin code:
func (p *MyPlugin) DoSomething(ctx context.Context) {
p.LogWithContext(ctx).Info("doing something", "key", "value")
}
Data Directory ¶
Plugins can store persistent data in their data directory:
func (p *MyPlugin) Initialize(ctx context.Context, dataDir string, config []byte) error {
cachePath := filepath.Join(p.DataDir(), "cache.db")
// ... use cache
}
Metrics ¶
Track request metrics for health monitoring:
func (p *MyPlugin) HandleRequest(ctx context.Context) error {
start := time.Now()
defer func() {
p.RecordRequest(time.Since(start))
}()
// ... handle request
}
Package sdk provides database utilities for ViewRA plugins.
The SQLClient provides managed SQL storage where the host handles table namespacing, connection pooling, and security enforcement. Plugins don't need to manage their own database connections or bundle SQLite drivers.
Usage ¶
func (p *MyPlugin) Initialize(ctx context.Context, req *pluginv1.InitRequest) (*pluginv1.InitResponse, error) {
db := p.storage.SQL()
// Run migrations
err := db.Migrate(ctx, []sdk.Migration{
{Version: 1, SQL: `CREATE TABLE items (id INTEGER PRIMARY KEY, name TEXT)`},
})
if err != nil {
return nil, err
}
p.db = db
return &pluginv1.InitResponse{Success: true}, nil
}
Table Namespacing ¶
All table names are automatically prefixed by the host with plugin_{id}_ For example, if your plugin ID is "semantic-search" and you create a table named "embeddings", the actual table name will be "plugin_semantic_search_embeddings".
You don't need to worry about this - just use your table names as-is.
Dual Database Compatibility ¶
SQL must work on both PostgreSQL and SQLite. Stick to common SQL features:
- Basic types: TEXT, INTEGER, REAL, BLOB
- CREATE TABLE, CREATE INDEX, DROP TABLE, DROP INDEX
- PRIMARY KEY, UNIQUE, NOT NULL, DEFAULT
- INSERT, UPDATE, DELETE, SELECT
- WHERE, ORDER BY, LIMIT, OFFSET
- JOIN, LEFT JOIN
- COUNT, MAX, MIN, SUM, AVG
Avoid:
- RETURNING clause (use LastInsertID instead)
- Array types
- SERIAL (use INTEGER PRIMARY KEY for auto-increment)
- Database-specific JSON operators
Enricher plugin support for ViewRA metadata enricher plugins.
This file provides the EnricherPlugin interface and ServeEnricher() helper for building enricher plugins (like TMDb, MusicBrainz).
Quick Start ¶
Create an enricher plugin that implements the EnricherPlugin interface:
type MyEnricher struct {
sdk.Base
storage *sdk.StorageClient
}
func (e *MyEnricher) GetCapabilities() sdk.EnricherCapabilities {
return sdk.EnricherCapabilities{
MediaTypes: []string{"movie", "tv"},
Provides: []string{"metadata", "artwork"},
}
}
func (e *MyEnricher) Initialize(ctx context.Context, dataDir string, config []byte, services *sdk.HostServices) error {
e.storage = services.Storage // Use host storage for caching
return nil
}
// ... implement other methods
func main() {
hclogger, logger := sdk.NewLogger("my-enricher")
plugin := &MyEnricher{}
plugin.SetLogger(logger)
sdk.ServeEnricher(plugin, hclogger)
}
Event handling helpers for ViewRA plugins.
Plugins can subscribe to events from the host to react to changes in the media library, playback state, and more.
Available Events ¶
Media events:
- media.added: New media item added to library
- media.updated: Media metadata updated
- media.deleted: Media item removed
Playback events:
- playback.started: User started playback
- playback.stopped: User stopped playback
- playback.completed: Playback reached end
Library events:
- library.scan.started: Library scan started
- library.scan.completed: Library scan finished
Usage ¶
Implement the EventHandler interface and return subscriptions:
func (p *MyPlugin) GetSubscriptions() []string {
return []string{"media.added", "media.updated"}
}
func (p *MyPlugin) OnEvent(ctx context.Context, event sdk.Event) bool {
switch event.Type {
case "media.added":
var payload MediaAddedPayload
if err := event.Unmarshal(&payload); err != nil {
return false
}
// Handle new media
return true
}
return false
}
Host service client wrappers for ViewRA plugins.
This file provides type-safe wrappers around the host services available to plugins. These services are exposed by the host and allow plugins to access data, storage, and more.
Available Services ¶
The host exposes these services to plugins:
- HostData: Access media library data (read-only)
- HostStorage: Plugin-scoped key-value, SQL, and vector storage
- HostPlugins: Capability-based plugin discovery and inter-plugin communication
- HostWeather: Weather and time context for search queries
- HostRatings: User ratings (favorites, likes, dislikes) for recommendations
AI Capabilities ¶
For AI functionality (embeddings, chat), use PluginsClient to discover and connect to provider plugins that offer "embeddings" or "chat" capabilities. See PluginsClient.GetConnection() for details.
Usage ¶
Plugins receive broker IDs in the InitRequest. Use these to connect:
func (p *MyPlugin) Initialize(ctx context.Context, req *pluginv1.InitRequest) (*pluginv1.InitResponse, error) {
if req.HostStorageBrokerId > 0 {
conn, _ := broker.Dial(req.HostStorageBrokerId)
p.storage = sdk.NewStorageClient(conn)
}
if req.HostPluginsBrokerId > 0 {
conn, _ := broker.Dial(req.HostPluginsBrokerId)
// PluginsClient provides capability invocation via host-proxied generic invoke
p.plugins = sdk.NewPluginsClient(conn)
}
return &pluginv1.InitResponse{Success: true}, nil
}
HTTP helpers for ViewRA plugin endpoints.
This package provides types and utilities for handling HTTP requests in plugins that expose custom routes.
Quick Start ¶
Implement the HTTPProvider interface to expose routes:
func (p *MyPlugin) GetRoutes() []sdk.Route {
return []sdk.Route{
{Path: "/health", Methods: []string{"GET"}},
{Path: "/items", Methods: []string{"GET", "POST"}},
{Path: "/items/:id", Methods: []string{"DELETE"}},
}
}
func (p *MyPlugin) HandleHTTP(ctx context.Context, req *sdk.HTTPRequest) (*sdk.HTTPResponse, error) {
switch req.Path {
case "/health":
return sdk.JSONResponse(200, map[string]bool{"healthy": true})
case "/items":
if req.Method == "GET" {
return p.listItems(ctx, req)
}
return p.createItem(ctx, req)
default:
return sdk.JSONError(404, "not found")
}
}
Response Helpers ¶
Use the response helpers for common patterns:
// JSON response with any data
sdk.JSONResponse(200, map[string]any{"items": items})
// Error response
sdk.JSONError(400, "invalid request")
// Empty success
sdk.EmptyResponse(204)
SSE Streaming ¶
For streaming responses (like download progress):
func (p *MyPlugin) HandleHTTPStream(ctx context.Context, req *sdk.HTTPRequest, w sdk.HTTPStreamWriter) error {
w.WriteHeader(200, "text/event-stream", nil)
for progress := range downloadProgress {
data, _ := json.Marshal(progress)
w.WriteSSE("progress", data)
}
return nil
}
Logging utilities for ViewRA plugins.
ViewRA plugins use go-plugin for process isolation, which requires special handling of logs. This file provides logger adapters that ensure plugin logs are properly captured and forwarded to the host application.
Why Special Logging? ¶
go-plugin runs plugins in separate processes. For logs to appear in the host's log output, they must be written in a format that go-plugin can parse and forward. The NewLogger function creates loggers configured for this.
Usage ¶
In your plugin's main() function:
func main() {
// Create both hclog (for go-plugin) and slog (for your code) loggers
hclogger, logger := sdk.NewLogger("my-plugin")
// Create your plugin with the slog logger
plugin := internal.NewPlugin(logger)
// Start the plugin server with the hclog logger
go_plugin.Serve(&go_plugin.ServeConfig{
HandshakeConfig: sdk.Handshake,
Plugins: map[string]go_plugin.Plugin{
"core": &MyGRPCPlugin{Impl: plugin},
},
GRPCServer: go_plugin.DefaultGRPCServer,
Logger: hclogger, // Important: pass hclogger here
})
}
Then use the slog logger throughout your plugin:
func (p *Plugin) DoSomething() {
p.logger.Info("doing something", "key", "value")
}
PluginsClient provides access to other plugins via the host-proxied capability invoke.
This allows plugins to invoke methods on other plugins that provide specific capabilities like "embedding", "chat", or custom plugin-defined capabilities. The host acts as a proxy, routing requests to the appropriate provider.
Usage ¶
The PluginsClient is obtained from the HostServices:
plugins := hostServices.Plugins
if plugins.IsAvailable(ctx, "embedding") {
respBytes, meta, err := plugins.Invoke(ctx, "embedding", "GenerateEmbedding", req)
// Unmarshal respBytes to get the typed response
}
Capabilities ¶
Capabilities are declared in plugin manifests via the "provides" field. Common capabilities include:
- "embedding" - Vector embedding generation
- "chat" - Chat/completion generation
- "search" - Search over media
Plugins can also define custom capabilities for inter-plugin communication.
Provider plugin support for ViewRA AI provider plugins.
This file provides the ProviderPlugin interface and ServeProvider() helper for building AI provider plugins (like Ollama, OpenAI, Anthropic).
Quick Start ¶
Create a provider plugin that implements the ProviderPlugin interface:
type MyProvider struct {
sdk.Base
apiKey string
}
func (p *MyProvider) GetProviderCapabilities() sdk.ProviderCapabilities {
return sdk.ProviderCapabilities{
ProviderID: "my-provider",
DisplayName: "My Provider",
SupportsChat: true,
SupportsEmbedding: true,
}
}
// ... implement other methods
func main() {
hclogger, logger := sdk.NewLogger("my-provider")
plugin := &MyProvider{}
plugin.SetLogger(logger)
sdk.ServeProvider(plugin, hclogger)
}
Schema builder for ViewRA plugin settings.
This package provides a fluent API for building JSON Schema definitions with ViewRA-specific extensions. Plugin authors use this to define their settings UI without writing raw JSON.
Quick Start ¶
Create a schema.go file in your plugin's internal package:
package internal
import "github.com/mantonx/viewra/pkg/plugin/sdk"
func SettingsSchema() *sdk.Schema {
return sdk.NewSchema("My Plugin Settings").
Meta(sdk.PluginMeta{
DisplayName: "My Plugin",
Description: "Does something useful",
Icon: "star",
}).
Property("api_key", sdk.String().
Title("API Key").
Description("Your API key").
Format("password").
Required()).
Action(sdk.TestAction("test-connection", "/health"))
}
Then in your plugin.go, use it in GetSettingsSchema:
func (p *Plugin) GetSettingsSchema(ctx context.Context, _ *pluginv1.Empty) (*pluginv1.SettingsSchema, error) {
return SettingsSchema().BuildSettingsSchema()
}
ViewRA Schema Extensions ¶
ViewRA extends JSON Schema with custom fields:
- x-viewra-meta: Plugin metadata for the UI (display name, icon, etc.)
- x-viewra-actions: Interactive UI elements (test buttons, lists, forms)
- x-viewra-sections: Group properties/actions by capability for filtering
Examples ¶
Simple API provider (like OpenAI):
sdk.NewSchema("OpenAI Settings").
Meta(sdk.PluginMeta{
DisplayName: "OpenAI",
Description: "OpenAI API for embeddings and chat",
Tip: "Requires API key. Usage is billed per token.",
Icon: "cloud",
}).
Property("api_key", sdk.String().
Title("API Key").
Format("password").
Required()).
Property("model", sdk.String().
Title("Model").
Default("gpt-4o-mini")).
Action(sdk.TestAction("test-connection", "/health"))
Provider with model management (like Ollama):
sdk.NewSchema("Ollama Settings").
Meta(sdk.PluginMeta{
DisplayName: "Ollama",
Description: "Local AI inference",
IsLocal: true,
Icon: "hard-drive",
}).
Property("base_url", sdk.String().
Title("Server URL").
Default("http://localhost:11434")).
Property("model", sdk.String().
Title("Model").
EnumStrings("llama3", "mistral")). // Dynamic from installed models
Section(sdk.NewSection("connection").
Properties("base_url").
Actions("test-connection").
Capabilities("embedding", "chat")).
Section(sdk.NewSection("models").
Properties("model").
Actions("model-list").
Capabilities("chat")).
Action(sdk.TestAction("test-connection", "/health")).
Action(sdk.ListAction("model-list", "/models").
Title("Available Models").
TabTitle("Models").
Display(sdk.NewListDisplay("name").
SecondaryField("description")).
ItemAction(sdk.NewDeleteAction("delete", "/models/:id").
Confirm("Delete Model", "Are you sure?")))
Available Icons ¶
Common icons: "cloud", "hard-drive", "brain", "compass", "star", "settings", "database", "film", "music", "tv", "search", "sparkles"
Property Formats ¶
Special formats for string properties:
- "password": Renders as a password field (masked input)
- "uri": URL validation
- "email": Email validation
Search provider plugin support for ViewRA.
This file provides the SearchProvider interface for building plugins that provide search functionality. Multiple search providers can be registered, with the highest priority enabled one being the default.
Quick Start ¶
Implement the SearchProvider interface in your plugin:
type MySearchPlugin struct {
sdk.Base
// ...
}
func (p *MySearchPlugin) Search(ctx context.Context, req *sdk.SearchProviderRequest) (*sdk.SearchProviderResponse, error) {
// Perform search
return &sdk.SearchProviderResponse{
Results: results,
Total: len(results),
}, nil
}
func (p *MySearchPlugin) GetSuggestions(ctx context.Context, req *sdk.SuggestionRequest) (*sdk.SuggestionResponse, error) {
// Return contextual suggestions
return &sdk.SuggestionResponse{
Suggestions: suggestions,
}, nil
}
func (p *MySearchPlugin) GetSearchProviderInfo(ctx context.Context) (*sdk.SearchProviderInfo, error) {
return &sdk.SearchProviderInfo{
ID: "my-search",
Name: "My Search",
Description: "AI-powered semantic search",
Priority: 100,
Capabilities: []string{"natural_language", "suggestions"},
}, nil
}
Then declare the capability in plugin.yml:
provides: - search_provider
Trending provider plugin support for ViewRA.
This file provides the TrendingProvider interface for building plugins that provide trending/popular content data. Trending data is matched against the user's library to show relevant trending items.
Quick Start ¶
Implement the TrendingProvider interface in your enricher plugin:
type TMDbPlugin struct {
sdk.Base
// ...
}
func (p *TMDbPlugin) GetTrending(ctx context.Context, req *sdk.TrendingRequest) (*sdk.TrendingResponse, error) {
// Fetch trending from TMDb API
return &sdk.TrendingResponse{
Items: items,
Window: req.Window,
Source: "tmdb",
}, nil
}
func (p *TMDbPlugin) GetTrendingProviderInfo(ctx context.Context) (*sdk.TrendingProviderInfo, error) {
return &sdk.TrendingProviderInfo{
ID: "tmdb",
Name: "TMDb Trending",
Description: "Trending movies and TV shows from The Movie Database",
Windows: []string{"day", "week"},
MediaTypes: []string{"movie", "tv", "all"},
UpdateFreq: "daily",
}, nil
}
Then declare the capability in plugin.yml:
provides: - enricher - trending
Package sdk provides vector storage utilities for ViewRA plugins.
The VectorClient provides managed vector storage with automatic indexing. The host uses pgvector (PostgreSQL) or sqlite-vec (SQLite) under the hood, providing fast approximate nearest neighbor (ANN) search.
Usage ¶
func (p *MyPlugin) Initialize(ctx context.Context, req *pluginv1.InitRequest) (*pluginv1.InitResponse, error) {
vec := p.storage.Vector()
// Store an embedding
err := vec.Store(ctx, sdk.Embedding{
EntityType: "movie",
EntityID: 123,
Vector: embedding, // []float32 from your embedding model
Text: "The Matrix (1999) - A computer hacker learns...",
})
// Search for similar items
results, err := vec.Search(ctx, sdk.VectorSearchRequest{
QueryVector: queryEmbedding,
Limit: 10,
})
}
Entity Namespacing ¶
Embeddings are automatically namespaced per-plugin. Each plugin has its own isolated vector index. Entity types and IDs are scoped to the plugin.
Embedding Dimensions ¶
The host automatically detects the embedding dimensions from the first vector stored. All subsequent vectors must have the same dimensions. Common dimensions: 384 (MiniLM), 768 (BERT), 1536 (OpenAI ada-002), 3072 (OpenAI text-embedding-3-large)
Vector search plugin support for ViewRA semantic search plugins.
This file provides the VectorSearchPlugin interface and ServeVectorSearchEnricher() helper for building search plugins that provide semantic search, similarity matching, and embedding-based media indexing.
Widget plugin support for ViewRA widget plugins.
This file provides the WidgetPlugin interface and ServeWidget() helper for building widget plugins that provide HTTP routes and home screen widgets but don't enrich media items (like recommendations, continue watching, etc.).
Quick Start ¶
Create a widget plugin that implements the WidgetPlugin interface:
type MyWidget struct {
sdk.Base
storage *sdk.StorageClient
}
func (w *MyWidget) Initialize(ctx context.Context, dataDir string, config []byte, services *sdk.HostServices) error {
w.storage = services.Storage
return nil
}
func (w *MyWidget) Shutdown(ctx context.Context) error {
return nil
}
func (w *MyWidget) GetSettingsSchema() ([]byte, error) {
return sdk.NewSchema().
Widgets([]sdk.Widget{...}).
Build()
}
func (w *MyWidget) Configure(settings []byte) error {
return nil
}
func (w *MyWidget) GetRoutes() []sdk.Route {
return []sdk.Route{...}
}
func (w *MyWidget) HandleHTTP(ctx context.Context, req *sdk.HTTPRequest) (*sdk.HTTPResponse, error) {
// Handle requests
}
func main() {
hclogger, logger := sdk.NewLogger("my-widget")
plugin := &MyWidget{}
plugin.SetLogger(logger)
sdk.ServeWidget(plugin, hclogger)
}
Widget definitions for ViewRA home screen plugin integration.
Plugins can register widgets to appear on the home screen via their settings schema. Widgets are rendered by clients (web, iOS, Roku, etc.) using the data provided by the plugin.
Quick Start ¶
In your plugin's schema.go, add widgets:
func SettingsSchema() *sdk.Schema {
return sdk.NewSchema("My Plugin Settings").
Meta(sdk.PluginMeta{...}).
Widgets([]sdk.Widget{
{
ID: "my-recommendations",
Type: sdk.WidgetTypeMediaRow,
Location: sdk.LocationHomepageSections,
ClientTypes: []string{sdk.ClientTypeAll},
Priority: 80,
CacheTTLSeconds: 600,
Config: map[string]any{
"endpoint": "/recommendations",
"title": "Recommended for You",
},
SettingsKey: "enabled",
},
})
}
Then implement the HTTP endpoint to return widget data:
func (p *Plugin) HandleHTTP(ctx context.Context, req *sdk.HTTPRequest) (*sdk.HTTPResponse, error) {
if req.Path == "/recommendations" {
items := p.getRecommendations(ctx, req.UserID)
return jsonResponse(200, map[string]any{
"title": "Recommended for You",
"items": items,
})
}
// ...
}
Index ¶
- Constants
- Variables
- func GetHeader(req *HTTPRequest, key string) string
- func GetPathParam(req *HTTPRequest, key string) string
- func GetQuery(req *HTTPRequest, key, defaultValue string) string
- func GetRequestID(ctx context.Context) string
- func NewLogger(name string) (hclog.Logger, *slog.Logger)
- func NewLoggerWithLevel(name string, level slog.Level) (hclog.Logger, *slog.Logger)
- func ParseJSON(req *HTTPRequest, v any) error
- func ServeEnricher(impl EnricherPlugin, logger hclog.Logger)
- func ServeEnricherWithExtra(impl EnricherPlugin, logger hclog.Logger, extra map[string]plugin.Plugin)
- func ServeProvider(impl ProviderPlugin, logger hclog.Logger)
- func ServeVectorSearchEnricher(impl VectorSearchEnricherPlugin, logger hclog.Logger)
- func ServeWidget(impl WidgetPlugin, logger hclog.Logger)
- func WithRequestID(ctx context.Context, requestID string) context.Context
- func WriteSSE(w HTTPStreamWriter, event string, data []byte) error
- func WriteSSEJSON(w HTTPStreamWriter, event string, data any) error
- type AIClient
- func (c *AIClient) Chat(ctx context.Context, req ChatRequest, opts ...InvokeOption) (*ChatResponse, error)
- func (c *AIClient) ChatStream(ctx context.Context, req ChatRequest, opts ...InvokeOption) (<-chan ChatChunk, error)
- func (c *AIClient) GenerateEmbedding(ctx context.Context, text string, opts ...InvokeOption) ([]float32, error)
- func (c *AIClient) GenerateEmbeddingBatch(ctx context.Context, texts []string, opts ...InvokeOption) ([][]float32, error)
- func (c *AIClient) GenerateEmbeddingBatchWithModel(ctx context.Context, texts []string, model string, opts ...InvokeOption) ([][]float32, error)
- func (c *AIClient) GenerateEmbeddingWithModel(ctx context.Context, text, model string, opts ...InvokeOption) ([]float32, error)
- func (c *AIClient) IsChatAvailable(ctx context.Context) bool
- func (c *AIClient) IsEmbeddingAvailable(ctx context.Context) bool
- type Action
- type AlbumMetadata
- type ArtistMetadata
- type AudioTrack
- type Badge
- type Base
- func (b *Base) DataDir() string
- func (b *Base) Init(dataDir string)
- func (b *Base) InitWithLogger(dataDir string, logger *slog.Logger)
- func (b *Base) Log() *slog.Logger
- func (b *Base) LogWithContext(ctx context.Context) *slog.Logger
- func (b *Base) Metrics() PluginMetrics
- func (b *Base) RecordError()
- func (b *Base) RecordRequest(latency time.Duration)
- func (b *Base) SetLogger(logger *slog.Logger)
- type Capability
- type CapabilityDescription
- type CapabilityError
- type CapabilityMethod
- type CastMember
- type ChatChunk
- type ChatMessage
- type ChatRequest
- type ChatResponse
- type ConfigurableEnricher
- type ConfigurableProvider
- type DataClient
- func (c *DataClient) GetLibrary(ctx context.Context, libraryID int64) (*Library, error)
- func (c *DataClient) GetMedia(ctx context.Context, mediaID int64, mediaType string) (*Media, error)
- func (c *DataClient) GetMediaDetails(ctx context.Context, mediaID int64, mediaType string) (*MediaDetails, error)
- func (c *DataClient) ListMediaByDirector(ctx context.Context, mediaType, directorName string, libraryID int64, ...) ([]*Media, error)
- func (c *DataClient) ListMediaByGenre(ctx context.Context, mediaType, genre string, libraryID int64, ...) ([]*Media, error)
- func (c *DataClient) ListMediaByLibrary(ctx context.Context, libraryID int64, limit, offset int) (*MediaList, error)
- type DeleteItemAction
- type DependsOnConfig
- type Embedding
- type EmptyState
- type EnrichRequest
- type EnrichResponse
- type EnrichedImage
- type EnrichedMetadata
- type EnricherCapabilities
- type EnricherCoreGRPCPlugin
- type EnricherGRPCPlugin
- type EnricherPlugin
- type EntityTypeStats
- type Event
- type EventHandler
- type FindSimilarRequest
- type HTTPEnricher
- type HTTPProvider
- type HTTPRequest
- type HTTPResponse
- type HTTPStreamWriter
- type HostDataGRPCPlugin
- type HostPluginsGRPCPlugin
- type HostServices
- type HostStorageGRPCPlugin
- type HostWeatherGRPCPlugin
- type IndexLibraryRequest
- type IndexLibraryResponse
- type IndexingProgress
- type InvokeMetadata
- type InvokeOption
- type ItemAction
- type Keyword
- type Library
- type LibraryScanCompletedPayload
- type LibraryScanStartedPayload
- type ListActionDef
- func (a *ListActionDef) DependsOn(field string, value any) *ListActionDef
- func (a *ListActionDef) Display(display *ListDisplay) *ListActionDef
- func (a *ListActionDef) EmptyState(state *EmptyState) *ListActionDef
- func (a *ListActionDef) ItemAction(action ItemAction) *ListActionDef
- func (a *ListActionDef) Params(params map[string]string) *ListActionDef
- func (a *ListActionDef) ShowSystemInfo() *ListActionDef
- func (a *ListActionDef) TabTitle(title string) *ListActionDef
- func (a *ListActionDef) Title(title string) *ListActionDef
- type ListDisplay
- type Media
- type MediaAddedPayload
- type MediaDeletedPayload
- type MediaDetails
- type MediaItem
- type MediaList
- type MediaProgress
- type MediaUpdatedPayload
- type Migration
- type MoodTag
- type PlaybackInfo
- type PlaybackStartedPayload
- type PlaybackStoppedPayload
- type PluginMeta
- type PluginMetrics
- type PluginProvider
- type PluginRefConfig
- type PluginsClient
- func (c *PluginsClient) ClearCapabilityPreference(ctx context.Context, capability string) error
- func (c *PluginsClient) Describe(ctx context.Context, capability string) (*CapabilityDescription, error)
- func (c *PluginsClient) FindSimilar(ctx context.Context, entityType string, entityID int64, limit int, ...) ([]SemanticSearchResult, string, error)
- func (c *PluginsClient) GetCapabilityPreferences(ctx context.Context) (map[string]string, error)
- func (c *PluginsClient) Invoke(ctx context.Context, capability, method string, req proto.Message, ...) ([]byte, *InvokeMetadata, error)
- func (c *PluginsClient) InvokeStream(ctx context.Context, capability, method string, req proto.Message, ...) (<-chan *StreamChunk, error)
- func (c *PluginsClient) IsAvailable(ctx context.Context, capability string) bool
- func (c *PluginsClient) IsVectorSearchAvailable(ctx context.Context) bool
- func (c *PluginsClient) ListCapabilities(ctx context.Context) ([]Capability, error)
- func (c *PluginsClient) ListProviders(ctx context.Context, capability string) ([]PluginProvider, error)
- func (c *PluginsClient) SemanticSearch(ctx context.Context, query string, entityTypes []string, limit int, ...) ([]SemanticSearchResult, string, error)
- func (c *PluginsClient) SetCapabilityPreference(ctx context.Context, capability, pluginID string) error
- type PluginsClientAware
- type ProgressClient
- func (c *ProgressClient) GetWatchedEntityIDs(ctx context.Context, userID, mediaType string, limit int) ([]int64, error)
- func (c *ProgressClient) HasWatchHistory(ctx context.Context, userID string) (bool, error)
- func (c *ProgressClient) ListInProgressItems(ctx context.Context, userID, mediaType string, limit, offset int) ([]*WatchProgress, error)
- func (c *ProgressClient) ListWatchedItems(ctx context.Context, userID, mediaType string, limit, offset int) ([]*WatchProgress, error)
- type Property
- func (p *Property) Default(val any) *Property
- func (p *Property) DependsOn(field string, value any) *Property
- func (p *Property) Description(desc string) *Property
- func (p *Property) Enum(values ...any) *Property
- func (p *Property) EnumStrings(values ...string) *Property
- func (p *Property) Format(format string) *Property
- func (p *Property) ItemsEnum(values ...string) *Property
- func (p *Property) Max(val float64) *Property
- func (p *Property) Min(val float64) *Property
- func (p *Property) Required() *Property
- func (p *Property) SettingsKey(key string) *Property
- func (p *Property) Title(title string) *Property
- type PropertyType
- type ProviderCapabilities
- type ProviderCoreGRPCPlugin
- type ProviderHealth
- type ProviderModel
- type ProviderPlugin
- type ProviderServiceGRPCPlugin
- type RateLimit
- type Rating
- type RatingsClient
- func (c *RatingsClient) GetDownvotedIDs(ctx context.Context, userID, entityType string, limit int) ([]int64, error)
- func (c *RatingsClient) GetFavoriteIDs(ctx context.Context, userID, entityType string, limit int) ([]int64, error)
- func (c *RatingsClient) GetPositivelyRatedIDs(ctx context.Context, userID, entityType string, limit int) ([]int64, error)
- func (c *RatingsClient) GetUpvotedIDs(ctx context.Context, userID, entityType string, limit int) ([]int64, error)
- func (c *RatingsClient) HasRatings(ctx context.Context, userID string) (bool, error)
- func (c *RatingsClient) ListRatings(ctx context.Context, userID, entityType, ratingType string) ([]*Rating, error)
- type Route
- type Row
- type Rows
- type SQLClient
- func (c *SQLClient) Exec(ctx context.Context, sql string, args ...any) (rowsAffected int64, lastInsertID int64, err error)
- func (c *SQLClient) Migrate(ctx context.Context, migrations []Migration) error
- func (c *SQLClient) Query(ctx context.Context, sql string, args ...any) (*Rows, error)
- func (c *SQLClient) QueryRow(ctx context.Context, sql string, args ...any) *Row
- type Schema
- func (s *Schema) Action(action Action) *Schema
- func (s *Schema) Build() ([]byte, error)
- func (s *Schema) BuildSettingsSchema() (*pluginv1.SettingsSchema, error)
- func (s *Schema) Meta(meta PluginMeta) *Schema
- func (s *Schema) Property(name string, prop *Property) *Schema
- func (s *Schema) Section(section *Section) *Schema
- func (s *Schema) Widgets(widgets []Widget) *Schema
- type SearchProvider
- type SearchProviderInfo
- type SearchProviderRequest
- type SearchProviderResponse
- type SearchResult
- type Section
- type SemanticSearchRequest
- type SemanticSearchResponse
- type SemanticSearchResult
- type ShowWhen
- type StorageClient
- func (c *StorageClient) Delete(ctx context.Context, key string) error
- func (c *StorageClient) Get(ctx context.Context, key string) ([]byte, bool, error)
- func (c *StorageClient) GetDatabasePath(ctx context.Context) (string, error)deprecated
- func (c *StorageClient) List(ctx context.Context, prefix string, limit int) ([]string, error)
- func (c *StorageClient) SQL() *SQLClient
- func (c *StorageClient) Set(ctx context.Context, key string, value []byte, ttlSeconds int64) error
- func (c *StorageClient) Vector() *VectorClient
- type StreamChunk
- type StreamingItemAction
- type SubtitleTrack
- type Suggestion
- type SuggestionAction
- type SuggestionRequest
- type SuggestionResponse
- type SystemInfo
- type TestActionDef
- type TrendingItem
- type TrendingProvider
- type TrendingProviderGRPCPlugin
- type TrendingProviderInfo
- type TrendingRequest
- type TrendingResponse
- type TrendingResult
- type VectorClient
- func (c *VectorClient) Count(ctx context.Context, entityType string) (int64, error)
- func (c *VectorClient) Delete(ctx context.Context, entityType string, entityID int64) error
- func (c *VectorClient) DeleteAll(ctx context.Context) (int64, error)
- func (c *VectorClient) DeleteByType(ctx context.Context, entityType string) (int64, error)
- func (c *VectorClient) Get(ctx context.Context, entityType string, entityID int64) (*Embedding, error)
- func (c *VectorClient) Search(ctx context.Context, req VectorSearchRequest) (*VectorSearchResponse, error)
- func (c *VectorClient) SearchText(ctx context.Context, query string, entityTypes []string, limit int) (*VectorSearchResponse, error)
- func (c *VectorClient) Store(ctx context.Context, emb Embedding) error
- func (c *VectorClient) StoreBatch(ctx context.Context, embeddings []Embedding) error
- type VectorSearchEnricherPlugin
- type VectorSearchGRPCPlugin
- type VectorSearchPlugin
- type VectorSearchRequest
- type VectorSearchResponse
- type VectorSearchResult
- type VectorSearchStatus
- type WatchProgress
- type Weather
- type WeatherClient
- type Widget
- type WidgetCoreGRPCPlugin
- type WidgetDataRequest
- type WidgetDataResponse
- type WidgetError
- type WidgetPlugin
Constants ¶
const ( // Media events EventMediaAdded = "media.added" EventMediaUpdated = "media.updated" EventMediaDeleted = "media.deleted" // Playback events EventPlaybackStarted = "playback.started" EventPlaybackStopped = "playback.stopped" EventPlaybackCompleted = "playback.completed" // Library events EventLibraryScanStarted = "library.scan.started" EventLibraryScanCompleted = "library.scan.completed" )
Event types
const ( RatingFavorite = "favorite" RatingUp = "up" RatingDown = "down" )
Rating type constants.
const ( // LocationHomepageTop is the top section of the homepage (search hero, featured content). LocationHomepageTop = "homepage-top" // LocationHomepageSections is the main content area with horizontal rows. LocationHomepageSections = "homepage-sections" )
Widget locations define where a widget appears on the home screen.
const ( // WidgetTypeSearchHero is a search input with AI-generated suggestion chips. // Best for: semantic-search plugin on web/iOS/Android. // Data shape: {placeholder, suggestions[], search_url} WidgetTypeSearchHero = "search-hero" // WidgetTypeFeaturedRow is a horizontal row of featured items. // Best for: constrained clients (Roku) as an alternative to search-hero. // Data shape: {title, items[]} WidgetTypeFeaturedRow = "featured-row" // WidgetTypeContinueRow is a continue watching row with progress bars. // Best for: showing in-progress content. // Data shape: {title, items[] with progress} WidgetTypeContinueRow = "continue-row" // WidgetTypeMediaRow is a generic horizontal media row. // Best for: recommendations, similar items, trending. // Data shape: {title, subtitle?, items[], see_all_url?} WidgetTypeMediaRow = "media-row" )
Widget types define how a widget is rendered.
const ( // ClientTypeAll means all clients should render this widget. ClientTypeAll = "all" // ClientTypeWeb is the web browser client. ClientTypeWeb = "web" // ClientTypeIOS is the iOS/tvOS client. ClientTypeIOS = "ios" // ClientTypeAndroid is the Android/Android TV client. ClientTypeAndroid = "android" // ClientTypeRoku is the Roku channel. ClientTypeRoku = "roku" // ClientTypeFireTV is the Amazon Fire TV client. ClientTypeFireTV = "firetv" // ClientTypeSmartTV is LG WebOS, Samsung Tizen, etc. ClientTypeSmartTV = "smarttv" )
Client types identify which clients should render a widget.
Variables ¶
var ErrNoRows = errors.New("sql: no rows in result set")
ErrNoRows is returned by QueryRow when no rows are found.
var Handshake = plugin.HandshakeConfig{
ProtocolVersion: 1,
MagicCookieKey: "VIEWRA_PLUGIN",
MagicCookieValue: "viewra-plugin-v1",
}
Handshake is the shared handshake config for all ViewRA plugins. Both host and plugin must agree on these values.
Functions ¶
func GetHeader ¶
func GetHeader(req *HTTPRequest, key string) string
GetHeader gets a header value (case-insensitive lookup assumed in Headers map).
Example:
contentType := sdk.GetHeader(req, "content-type")
func GetPathParam ¶
func GetPathParam(req *HTTPRequest, key string) string
GetPathParam gets a path parameter or returns empty string.
Example:
id := sdk.GetPathParam(req, "id")
func GetQuery ¶
func GetQuery(req *HTTPRequest, key, defaultValue string) string
GetQuery gets a query parameter with a default value.
Example:
limit := sdk.GetQuery(req, "limit", "10")
func GetRequestID ¶
GetRequestID extracts the request ID from the gRPC context. Returns empty string if no request ID is present.
Example:
reqID := sdk.GetRequestID(ctx)
if reqID != "" {
log.Info("handling request", "request_id", reqID)
}
func NewLogger ¶
NewLogger creates a new logger pair for use in ViewRA plugins.
Returns:
- hclog.Logger: Pass this to plugin.Serve() for go-plugin log forwarding
- *slog.Logger: Use this in your plugin code for logging
The hclog.Logger outputs JSON to stderr, which go-plugin parses and forwards to the host. The slog.Logger wraps hclog so you can use the standard slog API.
Example:
func main() {
hclogger, logger := sdk.NewLogger("my-plugin")
plugin := NewMyPlugin(logger)
go_plugin.Serve(&go_plugin.ServeConfig{
HandshakeConfig: sdk.Handshake,
Plugins: map[string]go_plugin.Plugin{...},
GRPCServer: go_plugin.DefaultGRPCServer,
Logger: hclogger,
})
}
func NewLoggerWithLevel ¶
NewLoggerWithLevel creates a logger pair with a specific log level. Use this when you want to control the verbosity of plugin logs.
Example:
// Only log warnings and errors
hclogger, logger := sdk.NewLoggerWithLevel("my-plugin", slog.LevelWarn)
func ParseJSON ¶
func ParseJSON(req *HTTPRequest, v any) error
ParseJSON parses the request body as JSON into the provided struct.
Example:
var req CreateItemRequest
if err := sdk.ParseJSON(httpReq, &req); err != nil {
return sdk.JSONError(400, "invalid JSON")
}
func ServeEnricher ¶
func ServeEnricher(impl EnricherPlugin, logger hclog.Logger)
ServeEnricher starts an enricher plugin server. Call this from your plugin's main() function.
If the plugin also implements TrendingProvider, it will automatically register the trending_provider service.
Example:
func main() {
hclogger, logger := sdk.NewLogger("my-enricher")
p := NewMyEnricher()
p.SetLogger(logger)
sdk.ServeEnricher(p, hclogger)
}
func ServeEnricherWithExtra ¶
func ServeEnricherWithExtra(impl EnricherPlugin, logger hclog.Logger, extra map[string]plugin.Plugin)
ServeEnricherWithExtra starts an enricher plugin server with additional gRPC services. Use this when your plugin exposes additional interfaces beyond the standard enricher.
If the plugin also implements TrendingProvider, it will automatically register the trending_provider service.
Example (vector-search plugin):
func main() {
hclogger, logger := sdk.NewLogger("semantic-search")
p := NewVectorSearchPlugin()
p.SetLogger(logger)
sdk.ServeEnricherWithExtra(p, hclogger, map[string]plugin.Plugin{
"vector_search": &VectorSearchGRPCPlugin{Impl: p},
})
}
func ServeProvider ¶
func ServeProvider(impl ProviderPlugin, logger hclog.Logger)
ServeProvider starts a provider plugin server. Call this from your plugin's main() function.
Example:
func main() {
hclogger, logger := sdk.NewLogger("my-provider")
p := NewMyProvider()
p.SetLogger(logger)
sdk.ServeProvider(p, hclogger)
}
func ServeVectorSearchEnricher ¶
func ServeVectorSearchEnricher(impl VectorSearchEnricherPlugin, logger hclog.Logger)
ServeVectorSearchEnricher starts a plugin server for plugins that implement both EnricherPlugin (for auto-indexing in enrichment pipeline) and VectorSearchPlugin (for semantic search, similarity matching, and manual indexing).
func ServeWidget ¶
func ServeWidget(impl WidgetPlugin, logger hclog.Logger)
ServeWidget starts a widget plugin server. Call this from your plugin's main() function.
Example:
func main() {
hclogger, logger := sdk.NewLogger("my-widget")
p := NewMyWidget()
p.SetLogger(logger)
sdk.ServeWidget(p, hclogger)
}
func WithRequestID ¶
WithRequestID returns a context with the request ID in outgoing metadata. Use this when making calls to host services to propagate request tracing.
Example:
ctx = sdk.WithRequestID(ctx, requestID) result, err := hostClient.DoSomething(ctx, req)
func WriteSSE ¶
func WriteSSE(w HTTPStreamWriter, event string, data []byte) error
WriteSSE writes a Server-Sent Event to a stream writer. This is a convenience method for writing SSE-formatted data.
Example:
w.WriteHeader(200, "text/event-stream", nil) sdk.WriteSSE(w, "progress", progressData)
func WriteSSEJSON ¶
func WriteSSEJSON(w HTTPStreamWriter, event string, data any) error
WriteSSEJSON writes a Server-Sent Event with JSON data.
Example:
sdk.WriteSSEJSON(w, "progress", map[string]any{"percent": 50})
Types ¶
type AIClient ¶
type AIClient struct {
// contains filtered or unexported fields
}
AIClient provides typed access to AI capabilities. It wraps PluginsClient and handles proto marshaling internally.
func NewAIClient ¶
func NewAIClient(plugins *PluginsClient) *AIClient
NewAIClient creates a new AI client from a PluginsClient. Returns nil if plugins is nil.
func (*AIClient) Chat ¶
func (c *AIClient) Chat(ctx context.Context, req ChatRequest, opts ...InvokeOption) (*ChatResponse, error)
Chat sends a chat completion request. Uses the "chat" capability.
Example:
resp, err := ai.Chat(ctx, sdk.ChatRequest{
Messages: []sdk.ChatMessage{
{Role: "system", Content: "You are a helpful assistant."},
{Role: "user", Content: "Hello!"},
},
Temperature: 0.7,
})
func (*AIClient) ChatStream ¶
func (c *AIClient) ChatStream(ctx context.Context, req ChatRequest, opts ...InvokeOption) (<-chan ChatChunk, error)
ChatStream sends a streaming chat completion request. Returns a channel that receives response chunks until closed.
Example:
chunks, err := ai.ChatStream(ctx, sdk.ChatRequest{...})
for chunk := range chunks {
if chunk.Done {
break
}
fmt.Print(chunk.Content)
}
func (*AIClient) GenerateEmbedding ¶
func (c *AIClient) GenerateEmbedding(ctx context.Context, text string, opts ...InvokeOption) ([]float32, error)
GenerateEmbedding generates an embedding vector for a single text. Uses the "embedding" capability.
Example:
embedding, err := ai.GenerateEmbedding(ctx, "hello world")
if err != nil {
return err
}
fmt.Printf("Embedding dimensions: %d\n", len(embedding))
func (*AIClient) GenerateEmbeddingBatch ¶
func (c *AIClient) GenerateEmbeddingBatch(ctx context.Context, texts []string, opts ...InvokeOption) ([][]float32, error)
GenerateEmbeddingBatch generates embeddings for multiple texts. Uses the "embedding" capability.
Example:
embeddings, err := ai.GenerateEmbeddingBatch(ctx, []string{"hello", "world"})
func (*AIClient) GenerateEmbeddingBatchWithModel ¶
func (c *AIClient) GenerateEmbeddingBatchWithModel(ctx context.Context, texts []string, model string, opts ...InvokeOption) ([][]float32, error)
GenerateEmbeddingBatchWithModel generates embeddings using a specific model.
func (*AIClient) GenerateEmbeddingWithModel ¶
func (c *AIClient) GenerateEmbeddingWithModel(ctx context.Context, text, model string, opts ...InvokeOption) ([]float32, error)
GenerateEmbeddingWithModel generates an embedding using a specific model.
func (*AIClient) IsChatAvailable ¶
IsChatAvailable checks if any chat provider is available.
type Action ¶
type Action interface {
// contains filtered or unexported methods
}
Action represents an x-viewra-actions entry. Actions are interactive UI elements that call plugin endpoints.
type AlbumMetadata ¶
type AlbumMetadata struct {
Title *string
AlbumArtist *string
Artist *string
Year *int
ReleaseDate *string
Genre *string
TotalTracks *int
TotalDiscs *int
RecordLabel *string
ReleaseType *string
Compilation *bool
MusicbrainzAlbumID *string
SortTitle *string
}
AlbumMetadata contains fields specific to music albums.
type ArtistMetadata ¶
type ArtistMetadata struct {
Name *string
SortName *string
MusicbrainzArtistID *string
Bio *string
Country *string
FormedYear *int
Genre *string
}
ArtistMetadata contains fields specific to music artists.
type AudioTrack ¶
type AudioTrack struct {
Codec string // "aac", "ac3", "eac3", "truehd", "dts", "dts-hd", "flac"
Channels int // Number of channels (2, 6, 8, etc.)
ChannelLayout string // "stereo", "5.1", "7.1", "Atmos"
Language string // ISO 639-1/2 code, e.g., "en", "eng"
IsDefault bool
IsCommentary bool
}
AudioTrack represents an audio stream in a media file.
type Badge ¶
type Badge struct {
// contains filtered or unexported fields
}
Badge represents a conditional badge configuration. Badges appear on list items when a field matches a value.
func NewBadge ¶
NewBadge creates a badge configuration. The badge appears when item[field] == value.
Colors: "blue", "green", "emerald", "yellow", "red", "purple", "gray"
Example:
// Show "Installed" badge when installed field is true
sdk.NewBadge("installed", true, "Installed", "emerald")
// Show "Error" badge when status is "failed"
sdk.NewBadge("status", "failed", "Error", "red")
type Base ¶
type Base struct {
// contains filtered or unexported fields
}
Base provides common functionality for all plugins. Plugin structs must embed this type to get logging, metrics, and data directory access.
Example:
type MyPlugin struct {
sdk.Base
apiKey string
}
func NewMyPlugin(logger *slog.Logger) *MyPlugin {
p := &MyPlugin{}
p.SetLogger(logger)
return p
}
func (*Base) DataDir ¶
DataDir returns the plugin's data directory path. Plugins can store persistent data here (caches, databases, etc.). The directory is created by the host and is unique to each plugin.
Example:
func (p *MyPlugin) getCachePath() string {
return filepath.Join(p.DataDir(), "cache.json")
}
func (*Base) Init ¶
Init initializes the base plugin functionality. Called automatically by the SDK during plugin initialization. Use InitWithLogger for proper go-plugin log forwarding.
func (*Base) InitWithLogger ¶
InitWithLogger initializes the base plugin with a specific logger. Use sdk.NewLogger() to create a logger that properly forwards to the host.
Example:
func (p *MyPlugin) Initialize(ctx context.Context, dataDir string, config []byte) error {
_, logger := sdk.NewLogger("my-plugin")
p.InitWithLogger(dataDir, logger)
return nil
}
func (*Base) Log ¶
Log returns the plugin's logger. Use this for logging without request context.
Example:
p.Log().Info("plugin started", "version", "1.0.0")
func (*Base) LogWithContext ¶
LogWithContext returns a logger with the request ID from the context. Use this when handling requests to enable request tracing.
Example:
func (p *MyPlugin) HandleRequest(ctx context.Context, req *Request) error {
p.LogWithContext(ctx).Info("handling request", "type", req.Type)
// ...
}
func (*Base) Metrics ¶
func (b *Base) Metrics() PluginMetrics
Metrics returns the current plugin metrics. These metrics are reported to the host for health monitoring.
func (*Base) RecordError ¶
func (b *Base) RecordError()
RecordError records an error for metrics. Call this when a request fails to track error rates.
Example:
if err != nil {
p.RecordError()
return err
}
func (*Base) RecordRequest ¶
RecordRequest records a successful request for metrics. Call this after handling each request to track performance.
Example:
func (p *MyPlugin) HandleRequest(ctx context.Context) error {
start := time.Now()
defer p.RecordRequest(time.Since(start))
// ... handle request
}
type Capability ¶
type Capability struct {
Name string // Capability name (e.g., "embedding")
Providers []PluginProvider // Plugins providing this capability
}
Capability describes an available capability and its providers.
type CapabilityDescription ¶
type CapabilityDescription struct {
Capability string
APIVersion string
SupportedVersions []string
Methods []CapabilityMethod
Providers []PluginProvider
}
CapabilityDescription describes a capability and its available methods.
type CapabilityError ¶
type CapabilityError struct {
Code pluginv1.CapabilityErrorCode
Message string
Details string
Retryable bool
}
CapabilityError represents a structured error from a capability call.
func (*CapabilityError) Error ¶
func (e *CapabilityError) Error() string
type CapabilityMethod ¶
type CapabilityMethod struct {
Name string
Description string
IsStreaming bool
RequestType string
ResponseType string
}
CapabilityMethod describes a method available on a capability.
type CastMember ¶
CastMember represents an actor in the cast.
type ChatChunk ¶
type ChatChunk struct {
// Content is the text in this chunk
Content string
// Done indicates if this is the final chunk
Done bool
// FinishReason is set on the final chunk
FinishReason string
}
ChatChunk is a chunk of a streaming chat response.
type ChatMessage ¶
type ChatMessage struct {
// Role is "system", "user", or "assistant"
Role string
// Content is the message text
Content string
}
ChatMessage represents a message in a chat conversation.
type ChatRequest ¶
type ChatRequest struct {
// Messages is the conversation history
Messages []ChatMessage
// Model is the model to use (uses provider default if empty)
Model string
// Temperature controls randomness (0.0-2.0)
Temperature float32
// MaxTokens limits the response length
MaxTokens int
}
ChatRequest contains the parameters for a chat completion.
type ChatResponse ¶
type ChatResponse struct {
// Content is the generated text
Content string
// FinishReason indicates why generation stopped: "stop", "length", "content_filter"
FinishReason string
// PromptTokens is the number of tokens in the prompt
PromptTokens int
// CompletionTokens is the number of tokens in the response
CompletionTokens int
}
ChatResponse is the result of a chat completion.
type ConfigurableEnricher ¶
type ConfigurableEnricher interface {
// GetSettingsSchema returns a JSON Schema describing the plugin's configurable settings.
// Use Schema.Build() to generate this from your schema definition.
GetSettingsSchema() ([]byte, error)
// Configure applies new settings to the plugin.
Configure(settings []byte) error
// IsConfigured returns whether the plugin is properly configured.
// Plugins requiring API keys should return false until the key is set.
// The host uses this to exclude unconfigured plugins from capability resolution.
IsConfigured() bool
}
ConfigurableEnricher is an optional interface for enrichers that support runtime configuration.
type ConfigurableProvider ¶
type ConfigurableProvider interface {
// GetSettingsSchema returns the JSON Schema for provider settings.
// Use Schema.Build() to generate this from your schema definition.
GetSettingsSchema() ([]byte, error)
// Configure applies new settings to the provider.
Configure(settings []byte) error
// IsConfigured returns whether the provider is properly configured.
// Providers requiring API keys should return false until the key is set.
// The host uses this to exclude unconfigured providers from capability resolution.
IsConfigured() bool
}
ConfigurableProvider is an optional interface for providers with settings UI.
type DataClient ¶
type DataClient struct {
// contains filtered or unexported fields
}
DataClient wraps the HostData service for media access.
func NewDataClient ¶
func NewDataClient(conn *grpc.ClientConn) *DataClient
NewDataClient creates a new data client.
func (*DataClient) GetLibrary ¶
GetLibrary retrieves library information by ID.
func (*DataClient) GetMediaDetails ¶
func (c *DataClient) GetMediaDetails(ctx context.Context, mediaID int64, mediaType string) (*MediaDetails, error)
GetMediaDetails retrieves full metadata for a media item. Includes plot, cast, genres, etc. for plugin indexing.
func (*DataClient) ListMediaByDirector ¶
func (c *DataClient) ListMediaByDirector(ctx context.Context, mediaType, directorName string, libraryID int64, excludeIDs []int64, limit int) ([]*Media, error)
ListMediaByDirector returns media items directed by a specific person. Used for director-based recommendations and themed collections.
Parameters:
- mediaType: "movie" or "tv_show"
- directorName: director name to match (e.g., "Christopher Nolan", "Spielberg")
- libraryID: library to filter by (0 = all libraries)
- excludeIDs: entity IDs to exclude from results
- limit: maximum results (default: 20, max: 100)
Example:
items, err := data.ListMediaByDirector(ctx, "movie", "Christopher Nolan", 0, []int64{}, 20)
for _, item := range items {
fmt.Printf("Found: %s (%d)\n", item.Title, item.Year)
}
func (*DataClient) ListMediaByGenre ¶
func (c *DataClient) ListMediaByGenre(ctx context.Context, mediaType, genre string, libraryID int64, excludeIDs []int64, limit int) ([]*Media, error)
ListMediaByGenre returns media items matching a genre pattern. Used for genre-based recommendations when semantic search is unavailable.
Parameters:
- mediaType: "movie" or "tv_show"
- genre: genre pattern to match (e.g., "Action", "Comedy")
- libraryID: library to filter by (0 = all libraries)
- excludeIDs: entity IDs to exclude from results
- limit: maximum results (default: 20, max: 100)
Example:
items, err := data.ListMediaByGenre(ctx, "movie", "Action", 0, []int64{1, 2}, 20)
for _, item := range items {
fmt.Printf("Found: %s (%d)\n", item.Title, item.Year)
}
func (*DataClient) ListMediaByLibrary ¶
func (c *DataClient) ListMediaByLibrary(ctx context.Context, libraryID int64, limit, offset int) (*MediaList, error)
ListMediaByLibrary lists all media in a library with pagination.
type DeleteItemAction ¶
type DeleteItemAction struct {
// contains filtered or unexported fields
}
DeleteItemAction represents a delete action with confirmation.
func NewDeleteAction ¶
func NewDeleteAction(id, endpoint string) *DeleteItemAction
NewDeleteAction creates a delete item action. The endpoint should support DELETE method with the item ID. Use :id in the endpoint path for the item ID placeholder.
Example:
sdk.NewDeleteAction("delete", "/models/:id")
func (*DeleteItemAction) Confirm ¶
func (a *DeleteItemAction) Confirm(title, message string) *DeleteItemAction
Confirm sets the confirmation dialog text. When set, a confirmation modal appears before deleting.
Example:
sdk.NewDeleteAction("delete", "/models/:id").
Confirm("Delete Model", "Are you sure you want to delete this model?")
func (*DeleteItemAction) Label ¶
func (a *DeleteItemAction) Label(label string) *DeleteItemAction
Label sets the action button label. Default is "Delete".
func (*DeleteItemAction) ShowWhen ¶
func (a *DeleteItemAction) ShowWhen(field string, value any) *DeleteItemAction
ShowWhen sets a condition for showing this action.
Example:
// Only show delete on installed items
sdk.NewDeleteAction("delete", "/models/:id").ShowWhen("installed", true)
type DependsOnConfig ¶
type DependsOnConfig struct {
// Field is the property name this depends on
Field string `json:"field"`
// Value is the value the field must have for this to be visible
Value any `json:"value"`
}
DependsOnConfig configures conditional visibility for a property or section.
type Embedding ¶
type Embedding struct {
// EntityType identifies the type of entity (e.g., "movie", "tv_show", "track")
EntityType string
// EntityID is the unique identifier within the entity type
EntityID int64
// Vector is the embedding vector (float32)
Vector []float32
// Text is the original text that was embedded (optional, for debugging)
Text string
// Model is the model used to generate the embedding (optional, for tracking)
Model string
}
Embedding represents a stored embedding.
type EmptyState ¶
type EmptyState struct {
// contains filtered or unexported fields
}
EmptyState represents the empty state configuration for a list.
func NewEmptyState ¶
func NewEmptyState(title string) *EmptyState
NewEmptyState creates an empty state configuration. Shown when the list has no items.
Example:
sdk.NewEmptyState("No models installed")
func (*EmptyState) Description ¶
func (e *EmptyState) Description(desc string) *EmptyState
Description sets the empty state description.
Example:
sdk.NewEmptyState("No models").Description("Pull a model to get started")
func (*EmptyState) ShowCreate ¶
func (e *EmptyState) ShowCreate(actionID string) *EmptyState
ShowCreate sets an action ID to show a "create" button. When clicked, switches to the referenced action (e.g., a create form).
type EnrichRequest ¶
type EnrichRequest struct {
MediaID int64
MediaType string
FilePath string
Title string
Year int
ExistingIDs map[string]string
// TV-specific
ShowTitle string
SeasonNumber int
EpisodeNumber int
// Music-specific
Artist string
Album string
TrackNumber int
}
EnrichRequest contains all information needed to enrich a media item.
type EnrichResponse ¶
type EnrichResponse struct {
Matched bool
Metadata *EnrichedMetadata
DiscoveredIDs map[string]string
Images []EnrichedImage
Skipped bool
SkipReason string
ConfidenceScore float32 // 0.0 to 1.0
}
EnrichResponse contains the results of enrichment.
func NoMatch ¶
func NoMatch() *EnrichResponse
NoMatch creates a response indicating no match was found.
func Skip ¶
func Skip(reason string) *EnrichResponse
Skip creates a skipped response with the given reason.
type EnrichedImage ¶
type EnrichedImage struct {
Type string // "poster", "fanart", "banner", etc.
Path string // Local path or remote URL
IsRemote bool
Language string
Width int
Height int
Rating float32
}
EnrichedImage represents an image discovered by an enricher.
type EnrichedMetadata ¶
type EnrichedMetadata struct {
Title *string
OriginalTitle *string
SortTitle *string
Year *int
Plot *string
Tagline *string
Genres []string
Keywords []Keyword
ContentRating *string
RuntimeMinutes *int
Rating *float32
RatingVotes *int
Directors []string
Writers []string
Cast []CastMember
Studios []string
SimilarTitles []string // Titles of similar/recommended content (from TMDb recommendations)
// Music-specific fields (for tracks)
Artist *string
Album *string
ReleaseDate *string
// Music album metadata
AlbumMetadata *AlbumMetadata
// Music artist metadata
ArtistMetadata *ArtistMetadata
}
EnrichedMetadata contains metadata fields that can be updated.
type EnricherCapabilities ¶
type EnricherCapabilities struct {
MediaTypes []string // "movie", "tv", "music"
Provides []string // "metadata", "artwork", "external_ids"
IsLocal bool // Local enrichers get high concurrency
RateLimit int // Requests per minute (0 = unlimited)
Requires []string // External IDs required (e.g., ["imdb"])
Priority int // Execution priority (lower = earlier)
}
EnricherCapabilities describes what an enricher provides and requires.
type EnricherCoreGRPCPlugin ¶
type EnricherCoreGRPCPlugin struct {
plugin.Plugin
Impl EnricherPlugin
// contains filtered or unexported fields
}
EnricherCoreGRPCPlugin is the go-plugin for PluginCore service (enrichers).
func (*EnricherCoreGRPCPlugin) GRPCClient ¶
func (p *EnricherCoreGRPCPlugin) GRPCClient(ctx context.Context, broker *plugin.GRPCBroker, c *grpc.ClientConn) (interface{}, error)
func (*EnricherCoreGRPCPlugin) GRPCServer ¶
func (p *EnricherCoreGRPCPlugin) GRPCServer(broker *plugin.GRPCBroker, s *grpc.Server) error
type EnricherGRPCPlugin ¶
type EnricherGRPCPlugin struct {
plugin.Plugin
Impl EnricherPlugin
// contains filtered or unexported fields
}
EnricherGRPCPlugin is the go-plugin for Enricher service.
func (*EnricherGRPCPlugin) GRPCClient ¶
func (p *EnricherGRPCPlugin) GRPCClient(ctx context.Context, broker *plugin.GRPCBroker, c *grpc.ClientConn) (interface{}, error)
func (*EnricherGRPCPlugin) GRPCServer ¶
func (p *EnricherGRPCPlugin) GRPCServer(broker *plugin.GRPCBroker, s *grpc.Server) error
type EnricherPlugin ¶
type EnricherPlugin interface {
// GetCapabilities returns what this enricher provides and requires.
GetCapabilities() EnricherCapabilities
// Initialize is called when the plugin is loaded.
// Config is the contents of config.yml passed by the host.
// Services provides access to host services (storage, LLM, etc.) - may have nil fields.
Initialize(ctx context.Context, dataDir string, config []byte, services *HostServices) error
// Shutdown is called before the plugin is unloaded.
// Use this to clean up any resources.
Shutdown(ctx context.Context) error
// Enrich processes a single media item.
Enrich(ctx context.Context, req *EnrichRequest) (*EnrichResponse, error)
// contains filtered or unexported methods
}
EnricherPlugin is the interface that enricher plugins must implement. Plugin authors implement this interface and use ServeEnricher() to run the plugin.
Plugin identity comes from plugin.yml manifest file, not code.
type EntityTypeStats ¶
type EntityTypeStats struct {
EntityType string // "movie", "tv_show", etc.
Indexed int64 // Number of indexed items
Total int64 // Total items in database
}
EntityTypeStats contains statistics for an entity type.
type Event ¶
type Event struct {
// Type is the event type, e.g., "media.added"
Type string
// Source identifies who emitted the event
Source string
// Timestamp is when the event occurred
Timestamp time.Time
// Payload is the JSON-encoded event data
Payload []byte
// CorrelationID links related events
CorrelationID string
}
Event represents an event from the host.
type EventHandler ¶
type EventHandler interface {
// GetSubscriptions returns event types this plugin wants to receive.
GetSubscriptions() []string
// OnEvent handles an incoming event.
// Returns true if the event was handled.
OnEvent(event Event) bool
}
EventHandler is an optional interface for plugins that handle events.
type FindSimilarRequest ¶
type FindSimilarRequest struct {
EntityType string // Type of the source entity
EntityID int64 // ID of the source entity
Limit int // Maximum number of similar items to return
}
FindSimilarRequest contains parameters for finding similar items.
type HTTPEnricher ¶
type HTTPEnricher interface {
// GetRoutes returns HTTP routes this enricher exposes.
GetRoutes() []Route
// HandleHTTP handles a non-streaming HTTP request.
HandleHTTP(ctx context.Context, req *HTTPRequest) (*HTTPResponse, error)
}
HTTPEnricher is an optional interface for enrichers that expose HTTP routes.
type HTTPProvider ¶
type HTTPProvider interface {
// GetRoutes returns HTTP routes this provider exposes.
GetRoutes() []Route
// HandleHTTP handles a non-streaming HTTP request.
HandleHTTP(ctx context.Context, req *HTTPRequest) (*HTTPResponse, error)
// HandleHTTPStream handles a streaming HTTP request (e.g., model download).
// Return nil if not implemented.
HandleHTTPStream(ctx context.Context, req *HTTPRequest, stream HTTPStreamWriter) error
}
HTTPProvider is an optional interface for providers that expose HTTP routes. Implement this for model management endpoints, health checks, etc.
type HTTPRequest ¶
type HTTPRequest struct {
// Path is the request path relative to the plugin, e.g., "/search"
Path string
// Method is the HTTP method: GET, POST, etc.
Method string
// Headers contains HTTP headers (lowercase keys)
Headers map[string]string
// Query contains query string parameters
Query map[string]string
// PathParams contains parameters extracted from :param patterns
PathParams map[string]string
// Body is the request body (for POST, PUT, PATCH)
Body []byte
// UserID is the authenticated user ID (empty if not authenticated)
UserID string
// IsAdmin indicates whether the user has admin role
IsAdmin bool
}
HTTPRequest contains an incoming HTTP request to a plugin route.
type HTTPResponse ¶
type HTTPResponse struct {
// StatusCode is the HTTP status code
StatusCode int
// Headers contains response headers
Headers map[string]string
// Body is the response body
Body []byte
// ContentType is the Content-Type header (convenience, also in Headers)
ContentType string
}
HTTPResponse is the response from a plugin route handler.
func EmptyResponse ¶
func EmptyResponse(statusCode int) (*HTTPResponse, error)
EmptyResponse creates an empty response with just a status code. Useful for 204 No Content responses.
Example:
return sdk.EmptyResponse(204)
func JSONError ¶
func JSONError(statusCode int, message string) (*HTTPResponse, error)
JSONError creates a JSON error response. The message is wrapped in {"error": "message"}.
Example:
return sdk.JSONError(400, "invalid request")
func JSONResponse ¶
func JSONResponse(statusCode int, data any) (*HTTPResponse, error)
JSONResponse creates a JSON HTTP response. The data is marshaled to JSON automatically.
Example:
return sdk.JSONResponse(200, map[string]any{"items": items})
type HTTPStreamWriter ¶
type HTTPStreamWriter interface {
// WriteHeader sends the response status and headers.
// Must be called before WriteChunk.
WriteHeader(statusCode int, contentType string, headers map[string]string) error
// WriteChunk sends a chunk of response data.
WriteChunk(data []byte) error
}
HTTPStreamWriter is used for streaming HTTP responses.
type HostDataGRPCPlugin ¶
func (*HostDataGRPCPlugin) GRPCClient ¶
func (p *HostDataGRPCPlugin) GRPCClient(ctx context.Context, broker *plugin.GRPCBroker, c *grpc.ClientConn) (interface{}, error)
func (*HostDataGRPCPlugin) GRPCServer ¶
func (p *HostDataGRPCPlugin) GRPCServer(broker *plugin.GRPCBroker, s *grpc.Server) error
type HostPluginsGRPCPlugin ¶
func (*HostPluginsGRPCPlugin) GRPCClient ¶
func (p *HostPluginsGRPCPlugin) GRPCClient(ctx context.Context, broker *plugin.GRPCBroker, c *grpc.ClientConn) (interface{}, error)
func (*HostPluginsGRPCPlugin) GRPCServer ¶
func (p *HostPluginsGRPCPlugin) GRPCServer(broker *plugin.GRPCBroker, s *grpc.Server) error
type HostServices ¶
type HostServices struct {
// Storage provides key-value, SQL, and vector storage for plugins
Storage *StorageClient
// Data provides access to media database
Data *DataClient
// Weather provides weather/location data
Weather *WeatherClient
// Plugins provides capability-based access to other plugins
Plugins *PluginsClient
// Ratings provides read-only access to user ratings (favorites, likes, dislikes)
Ratings *RatingsClient
// Progress provides read-only access to user watch history
Progress *ProgressClient
}
HostServices provides access to host-provided services. Fields may be nil if the service is not available.
For AI capabilities (embeddings, chat), use the Plugins client with capability-based discovery. Call Plugins.GetConnection("embeddings") or Plugins.GetConnection("chat") to get a connection to a provider plugin.
type HostStorageGRPCPlugin ¶
func (*HostStorageGRPCPlugin) GRPCClient ¶
func (p *HostStorageGRPCPlugin) GRPCClient(ctx context.Context, broker *plugin.GRPCBroker, c *grpc.ClientConn) (interface{}, error)
func (*HostStorageGRPCPlugin) GRPCServer ¶
func (p *HostStorageGRPCPlugin) GRPCServer(broker *plugin.GRPCBroker, s *grpc.Server) error
type HostWeatherGRPCPlugin ¶
func (*HostWeatherGRPCPlugin) GRPCClient ¶
func (p *HostWeatherGRPCPlugin) GRPCClient(ctx context.Context, broker *plugin.GRPCBroker, c *grpc.ClientConn) (interface{}, error)
func (*HostWeatherGRPCPlugin) GRPCServer ¶
func (p *HostWeatherGRPCPlugin) GRPCServer(broker *plugin.GRPCBroker, s *grpc.Server) error
type IndexLibraryRequest ¶
type IndexLibraryRequest struct {
LibraryID int64 // Library database ID
LibraryType string // "movie", "tv", "music"
}
IndexLibraryRequest contains parameters for indexing a library.
type IndexLibraryResponse ¶
type IndexLibraryResponse struct {
Started bool // Whether indexing was started
Message string // Status message
}
IndexLibraryResponse contains the result of an indexing trigger.
type IndexingProgress ¶
type IndexingProgress struct {
EntityType string // Entity type being indexed
Total int64 // Total items to process
Processed int64 // Items processed so far
Failed int64 // Items that failed
LastError string // Most recent error message
StartedAt int64 // Unix timestamp when started
LastUpdated int64 // Unix timestamp of last update
}
IndexingProgress tracks indexing operation progress.
type InvokeMetadata ¶
type InvokeMetadata struct {
ProviderPlugin string // Which plugin handled the request
LatencyMs int64 // How long the provider took
Metadata map[string]string // Response metadata from provider
}
InvokeMetadata contains metadata about an invoke call.
type InvokeOption ¶
type InvokeOption func(*invokeOptions)
InvokeOption configures an Invoke call.
func WithAPIVersion ¶
func WithAPIVersion(version string) InvokeOption
WithAPIVersion sets the API version for this invoke.
func WithMetadata ¶
func WithMetadata(meta map[string]string) InvokeOption
WithMetadata sets request metadata for this invoke.
func WithPreferredPlugin ¶
func WithPreferredPlugin(pluginID string) InvokeOption
WithPreferredPlugin sets the preferred provider plugin for this invoke.
type ItemAction ¶
type ItemAction interface {
// contains filtered or unexported methods
}
ItemAction represents an action button on a list item.
type LibraryScanCompletedPayload ¶
type LibraryScanCompletedPayload struct {
LibraryID int64 `json:"library_id"`
ItemsAdded int `json:"items_added"`
ItemsUpdate int `json:"items_updated"`
ItemsRemove int `json:"items_removed"`
DurationMs int64 `json:"duration_ms"`
}
LibraryScanCompletedPayload is the payload for library.scan.completed events.
type LibraryScanStartedPayload ¶
type LibraryScanStartedPayload struct {
LibraryID int64 `json:"library_id"`
ScanType string `json:"scan_type"` // "full" or "incremental"
}
LibraryScanStartedPayload is the payload for library.scan.started events.
type ListActionDef ¶
type ListActionDef struct {
// contains filtered or unexported fields
}
ListActionDef defines a list action that displays items from an endpoint. Use this for managing collections like models, sources, or configurations.
func ListAction ¶
func ListAction(id, endpoint string) *ListActionDef
ListAction creates a list action builder. The endpoint should return a JSON response with:
{"items": [{"id": "1", "name": "Item 1", ...}, ...]}
Example:
sdk.ListAction("model-list", "/models")
func (*ListActionDef) DependsOn ¶
func (a *ListActionDef) DependsOn(field string, value any) *ListActionDef
DependsOn sets conditional visibility - this action/tab only shows when the specified field has the specified value.
Example:
sdk.ListAction("embedding-models", "/models").
TabTitle("Ollama Embedding Models").
DependsOn("embedding_provider", "ai-local")
func (*ListActionDef) Display ¶
func (a *ListActionDef) Display(display *ListDisplay) *ListActionDef
Display sets how list items are rendered. Use NewListDisplay to configure field mapping.
Example:
sdk.ListAction("models", "/models").
Display(sdk.NewListDisplay("name").SecondaryField("description"))
func (*ListActionDef) EmptyState ¶
func (a *ListActionDef) EmptyState(state *EmptyState) *ListActionDef
EmptyState sets what to show when the list is empty.
Example:
sdk.ListAction("models", "/models").
EmptyState(sdk.NewEmptyState("No models installed").
Description("Pull a model to get started"))
func (*ListActionDef) ItemAction ¶
func (a *ListActionDef) ItemAction(action ItemAction) *ListActionDef
ItemAction adds an action that appears on each list item. Common item actions: delete, download, configure.
Example:
sdk.ListAction("models", "/models").
ItemAction(sdk.NewDeleteAction("delete", "/models/:id"))
func (*ListActionDef) Params ¶
func (a *ListActionDef) Params(params map[string]string) *ListActionDef
Params sets query parameters to include when calling the endpoint. Use this to filter list results.
Example:
sdk.ListAction("embedding-models", "/models").
Params(map[string]string{"type": "embedding"})
func (*ListActionDef) ShowSystemInfo ¶
func (a *ListActionDef) ShowSystemInfo() *ListActionDef
ShowSystemInfo enables display of system resource information. When enabled, shows available RAM/VRAM above the list. Useful for model lists where resource requirements matter.
The endpoint response should include:
{"items": [...], "systemInfo": {"ramBytes": 16000000000, "vramBytes": 8000000000, "hasGpu": true}}
func (*ListActionDef) TabTitle ¶
func (a *ListActionDef) TabTitle(title string) *ListActionDef
TabTitle sets the tab title. When set, this action appears as a tab in the settings form instead of inline.
Example:
sdk.ListAction("models", "/models").TabTitle("Models")
func (*ListActionDef) Title ¶
func (a *ListActionDef) Title(title string) *ListActionDef
Title sets the list header title.
Example:
sdk.ListAction("models", "/models").Title("Available Models")
type ListDisplay ¶
type ListDisplay struct {
// contains filtered or unexported fields
}
ListDisplay configures how list items are rendered.
func NewListDisplay ¶
func NewListDisplay(primaryField string) *ListDisplay
NewListDisplay creates a list display configuration. The primary field is required and shown as the main text for each item.
Example:
sdk.NewListDisplay("name").SecondaryField("description")
func (*ListDisplay) Badge ¶
func (d *ListDisplay) Badge(badge Badge) *ListDisplay
Badge adds a conditional badge to list items. Badges are colored labels that appear when a condition is met.
Example:
sdk.NewListDisplay("name").
Badge(sdk.NewBadge("installed", true, "Installed", "emerald")).
Badge(sdk.NewBadge("canRun", false, "Too Large", "red"))
func (*ListDisplay) Metadata ¶
func (d *ListDisplay) Metadata(fields ...string) *ListDisplay
Metadata sets additional fields to show as small metadata items.
Example:
sdk.NewListDisplay("name").Metadata("size", "created")
func (*ListDisplay) SecondaryField ¶
func (d *ListDisplay) SecondaryField(field string) *ListDisplay
SecondaryField sets the secondary display field. Shown below the primary field in smaller text.
Example:
sdk.NewListDisplay("name").SecondaryField("description")
type Media ¶
type Media struct {
ID int64
MediaType string
Title string
Year int
FilePath string
LibraryID int64
ExternalIDs map[string]string
}
Media represents a media item.
type MediaAddedPayload ¶
type MediaAddedPayload struct {
MediaID int64 `json:"media_id"`
MediaType string `json:"media_type"`
Title string `json:"title"`
Year int `json:"year"`
LibraryID int64 `json:"library_id"`
}
MediaAddedPayload is the payload for media.added events.
type MediaDeletedPayload ¶
type MediaDeletedPayload struct {
MediaID int64 `json:"media_id"`
MediaType string `json:"media_type"`
}
MediaDeletedPayload is the payload for media.deleted events.
type MediaDetails ¶
type MediaDetails struct {
ID int64
MediaType string
Title string
Year int
LibraryID int64
ExternalIDs map[string]string
// Rich metadata
Plot string
Tagline string
Genres []string
Directors []string
Writers []string
Cast []CastMember
Studios []string
ContentRating string
RuntimeMinutes int
OriginalLanguage string
CountryOfOrigin string
Producers []string
LocationKeywords []string
ThemeKeywords []string
Composers []string // Music composers
Cinematographers []string // Directors of Photography
SimilarTitles []string // Similar/recommended titles from TMDb
// Playback information for filtering by technical specs
PlaybackInfo *PlaybackInfo
// TV-specific
ShowTitle string
SeasonNumber int
EpisodeNumber int
// Music-specific
ArtistName string
AlbumTitle string
Biography string
Country string
ReleaseType string
}
MediaDetails contains full metadata for plugin indexing.
type MediaItem ¶
type MediaItem struct {
// EntityType is the media type: "movie", "tv_show", "tv_episode", etc.
EntityType string `json:"entity_type"`
// EntityID is the database ID of the media item.
EntityID int64 `json:"entity_id"`
// Title is the display title.
Title string `json:"title"`
// Year is the release/air year.
Year int `json:"year,omitempty"`
// Poster is the URL to the poster image.
Poster string `json:"poster,omitempty"`
// Backdrop is the URL to the backdrop image.
Backdrop string `json:"backdrop,omitempty"`
// Reason is an optional recommendation reason.
// Example: "Similar to Breaking Bad"
Reason string `json:"reason,omitempty"`
// Progress is optional playback progress (for continue watching).
Progress *MediaProgress `json:"progress,omitempty"`
// Rating is the user's rating for this item (if any).
// Values: "up", "down", "favorite", or nil if not rated.
Rating *string `json:"rating,omitempty"`
}
MediaItem represents a media item in widget data. Used in WidgetTypeMediaRow, WidgetTypeFeaturedRow, etc.
type MediaList ¶
type MediaList struct {
Items []*MediaDetails
Total int
HasMore bool
}
MediaList is a paginated list of media.
type MediaProgress ¶
type MediaProgress struct {
// Percent is the progress percentage (0-100).
Percent int `json:"percent"`
// PositionSeconds is the playback position in seconds.
PositionSeconds int `json:"position_seconds"`
// DurationSeconds is the total duration in seconds.
DurationSeconds int `json:"duration_seconds"`
}
MediaProgress represents playback progress for a media item.
type MediaUpdatedPayload ¶
type MediaUpdatedPayload struct {
MediaID int64 `json:"media_id"`
MediaType string `json:"media_type"`
UpdatedField []string `json:"updated_fields"`
}
MediaUpdatedPayload is the payload for media.updated events.
type Migration ¶
type Migration struct {
// Version is the migration version number. Must be unique and positive.
// Migrations are applied in version order.
Version int
// SQL is the DDL statement(s) to execute for this migration.
// Multiple statements can be separated by semicolons.
SQL string
}
Migration represents a schema migration.
type PlaybackInfo ¶
type PlaybackInfo struct {
// Video specs
Width int // Video width in pixels
Height int // Video height in pixels
ResolutionLabel string // "SD", "720p", "1080p", "4K", "8K"
HDRFormat string // "SDR", "HDR10", "HDR10+", "Dolby Vision", "HLG"
VideoCodec string // "h264", "hevc", "av1", etc.
Bitrate int64 // Video bitrate in bits/second
// Audio and subtitle tracks
AudioTracks []AudioTrack
SubtitleTracks []SubtitleTrack
}
PlaybackInfo contains technical playback metadata for filtering. Used for queries like "4K movies", "Dolby Vision content", "movies with subtitles".
type PlaybackStartedPayload ¶
type PlaybackStartedPayload struct {
SessionID string `json:"session_id"`
UserID string `json:"user_id"`
MediaID int64 `json:"media_id"`
MediaType string `json:"media_type"`
}
PlaybackStartedPayload is the payload for playback.started events.
type PlaybackStoppedPayload ¶
type PlaybackStoppedPayload struct {
SessionID string `json:"session_id"`
UserID string `json:"user_id"`
MediaID int64 `json:"media_id"`
PositionSecs float64 `json:"position_secs"`
DurationSecs float64 `json:"duration_secs"`
}
PlaybackStoppedPayload is the payload for playback.stopped events.
type PluginMeta ¶
type PluginMeta struct {
// DisplayName is the human-readable name shown in the UI.
// Example: "OpenAI", "Ollama", "TMDB"
DisplayName string `json:"displayName"`
// ProviderName is the name shown in provider selection dropdowns.
// If not set, DisplayName is used. Use this when the plugin name
// differs from how it should appear as a provider option.
// Example: DisplayName="AI Features", ProviderName="Ollama"
ProviderName string `json:"providerName,omitempty"`
// Description is a short description of what the plugin does.
// Example: "OpenAI API for embeddings and chat"
Description string `json:"description"`
// Tip is optional help text shown as a tooltip.
// Example: "Requires API key. Usage is billed per token."
Tip string `json:"tip,omitempty"`
// IsLocal indicates if this runs locally (no external API calls).
// Local plugins show a "Local" badge in the UI.
IsLocal bool `json:"isLocal,omitempty"`
// Icon is the icon name to display. Common options:
// "cloud", "hard-drive", "brain", "compass", "star", "settings"
Icon string `json:"icon,omitempty"`
}
PluginMeta contains metadata for the plugin UI display. This appears in the settings page header when the plugin is selected.
type PluginMetrics ¶
type PluginMetrics struct {
// RequestsTotal is the total number of requests handled.
RequestsTotal int64
// ErrorsTotal is the total number of errors encountered.
ErrorsTotal int64
// AvgLatency is the average request latency.
AvgLatency time.Duration
}
PluginMetrics contains plugin performance metrics. These are reported to the host for health monitoring and displayed in the UI.
type PluginProvider ¶
type PluginProvider struct {
ID string // Plugin ID (e.g., "provider-ollama")
Name string // Human-readable name (e.g., "Ollama Provider")
Enabled bool // Whether the plugin is enabled
Configured bool // Whether the plugin is properly configured
IsPreferred bool // Whether this is the preferred provider
}
PluginProvider describes a plugin that provides a capability.
type PluginRefConfig ¶
type PluginRefConfig struct {
// Capability is the capability to filter plugins by (e.g., "embedding", "chat").
// Only plugins providing this capability appear in the dropdown.
Capability string
// SettingsKey is the key where the referenced plugin's settings are stored.
// If empty, defaults to "{capability}_provider_settings".
SettingsKey string
}
PluginRefConfig configures a plugin reference property. Used to embed another plugin's settings inline within this plugin's form.
type PluginsClient ¶
type PluginsClient struct {
// contains filtered or unexported fields
}
PluginsClient provides capability-based access to other plugins.
func NewPluginsClient ¶
func NewPluginsClient(conn *grpc.ClientConn) *PluginsClient
NewPluginsClient creates a new plugins client for capability discovery and invocation.
func (*PluginsClient) ClearCapabilityPreference ¶
func (c *PluginsClient) ClearCapabilityPreference(ctx context.Context, capability string) error
ClearCapabilityPreference removes the preference for a capability. After clearing, Invoke falls back to the first available provider.
Example:
err := plugins.ClearCapabilityPreference(ctx, "embedding")
func (*PluginsClient) Describe ¶
func (c *PluginsClient) Describe(ctx context.Context, capability string) (*CapabilityDescription, error)
Describe returns metadata about a capability's available methods.
Example:
desc, err := plugins.Describe(ctx, "embedding")
for _, method := range desc.Methods {
fmt.Printf("Method: %s (streaming: %v)\n", method.Name, method.IsStreaming)
}
func (*PluginsClient) FindSimilar ¶
func (c *PluginsClient) FindSimilar(ctx context.Context, entityType string, entityID int64, limit int, opts ...InvokeOption) ([]SemanticSearchResult, string, error)
FindSimilar finds items similar to a given entity using vector search. Returns results ordered by similarity (highest first).
Example:
results, provider, err := plugins.FindSimilar(ctx, "movie", movieID, 10)
for _, r := range results {
fmt.Printf("Similar %s %d (score: %.2f)\n", r.EntityType, r.EntityID, r.Similarity)
}
func (*PluginsClient) GetCapabilityPreferences ¶
GetCapabilityPreferences returns all configured capability preferences. Returns a map of capability name to preferred plugin ID.
Example:
prefs, err := plugins.GetCapabilityPreferences(ctx)
if embeddingPlugin, ok := prefs["embedding"]; ok {
fmt.Printf("Embedding provider: %s\n", embeddingPlugin)
}
func (*PluginsClient) Invoke ¶
func (c *PluginsClient) Invoke(ctx context.Context, capability, method string, req proto.Message, opts ...InvokeOption) ([]byte, *InvokeMetadata, error)
Invoke calls a method on a capability provider and returns the response payload. The caller is responsible for marshaling the request and unmarshaling the response.
Example:
req := &pluginv1.ProviderEmbeddingRequest{Text: "hello"}
respBytes, meta, err := plugins.Invoke(ctx, "embedding", "GenerateEmbedding", req)
if err != nil {
return err
}
var resp pluginv1.ProviderEmbeddingResponse
proto.Unmarshal(respBytes, &resp)
func (*PluginsClient) InvokeStream ¶
func (c *PluginsClient) InvokeStream(ctx context.Context, capability, method string, req proto.Message, opts ...InvokeOption) (<-chan *StreamChunk, error)
InvokeStream calls a streaming method on a capability provider. Returns a channel that receives response chunks until closed.
Example:
req := &pluginv1.ProviderChatRequest{...}
chunks, err := plugins.InvokeStream(ctx, "chat", "ChatStream", req)
if err != nil {
return err
}
for chunk := range chunks {
if chunk.Error != nil {
return chunk.Error
}
var resp pluginv1.ProviderChatStreamChunk
proto.Unmarshal(chunk.Payload, &resp)
// Process chunk
}
func (*PluginsClient) IsAvailable ¶
func (c *PluginsClient) IsAvailable(ctx context.Context, capability string) bool
IsAvailable checks if any plugin provides the specified capability.
Example:
if plugins.IsAvailable(ctx, "embedding") {
// Embedding capability is available
}
func (*PluginsClient) IsVectorSearchAvailable ¶
func (c *PluginsClient) IsVectorSearchAvailable(ctx context.Context) bool
IsVectorSearchAvailable returns true if any plugin provides vector_search capability. Use this to check before calling FindSimilar or SemanticSearch.
Example:
if plugins.IsVectorSearchAvailable(ctx) {
results, err := plugins.FindSimilar(ctx, "movie", 123, 10)
}
func (*PluginsClient) ListCapabilities ¶
func (c *PluginsClient) ListCapabilities(ctx context.Context) ([]Capability, error)
ListCapabilities returns all available capabilities and their providers. Useful for discovering what capabilities are available in the system.
Example:
caps, err := plugins.ListCapabilities(ctx)
for _, cap := range caps {
fmt.Printf("Capability: %s, Providers: %d\n", cap.Name, len(cap.Providers))
}
func (*PluginsClient) ListProviders ¶
func (c *PluginsClient) ListProviders(ctx context.Context, capability string) ([]PluginProvider, error)
ListProviders returns all plugins providing a specific capability. Includes both enabled and disabled plugins for UI display purposes.
Example:
providers, err := plugins.ListProviders(ctx, "embedding")
for _, p := range providers {
fmt.Printf("Provider: %s (enabled: %v)\n", p.Name, p.Enabled)
}
func (*PluginsClient) SemanticSearch ¶
func (c *PluginsClient) SemanticSearch(ctx context.Context, query string, entityTypes []string, limit int, userID string, opts ...InvokeOption) ([]SemanticSearchResult, string, error)
SemanticSearch performs semantic search across indexed media. Returns results ordered by relevance (highest first).
Example:
results, provider, err := plugins.SemanticSearch(ctx, "action movies with space battles", []string{"movie"}, 10, "user-123")
for _, r := range results {
fmt.Printf("Found %s %d (score: %.2f)\n", r.EntityType, r.EntityID, r.Similarity)
}
func (*PluginsClient) SetCapabilityPreference ¶
func (c *PluginsClient) SetCapabilityPreference(ctx context.Context, capability, pluginID string) error
SetCapabilityPreference sets the preferred plugin for a capability. Used by configuration plugins (e.g., ai-local) to route capabilities to specific providers. When other plugins invoke this capability, the preferred plugin will be used.
Example:
// Route all embedding requests to OpenAI err := plugins.SetCapabilityPreference(ctx, "embedding", "provider-openai")
type PluginsClientAware ¶
type PluginsClientAware interface {
// SetPluginsClient receives the PluginsClient for capability broker access.
// Called after Initialize() if the host provides the HostPlugins service.
SetPluginsClient(client *PluginsClient)
}
PluginsClientAware is an optional interface for providers that need access to the capability broker for discovering and routing to other plugins. Implement this interface to receive a PluginsClient during initialization.
Example use case: The ai-local plugin uses this to set capability preferences when configured, routing embedding/chat requests to the selected provider.
type ProgressClient ¶
type ProgressClient struct {
// contains filtered or unexported fields
}
ProgressClient wraps the HostProgress service for reading user watch history. Plugins use this to access watch progress for collaborative filtering and personalized recommendations.
func NewProgressClient ¶
func NewProgressClient(conn *grpc.ClientConn) *ProgressClient
NewProgressClient creates a new progress client.
func (*ProgressClient) GetWatchedEntityIDs ¶
func (c *ProgressClient) GetWatchedEntityIDs(ctx context.Context, userID, mediaType string, limit int) ([]int64, error)
GetWatchedEntityIDs returns just the entity IDs of watched items. More efficient than ListWatchedItems when only IDs are needed. Optional filter: mediaType (empty for all types).
func (*ProgressClient) HasWatchHistory ¶
HasWatchHistory returns whether a user has any watch history.
func (*ProgressClient) ListInProgressItems ¶
func (c *ProgressClient) ListInProgressItems(ctx context.Context, userID, mediaType string, limit, offset int) ([]*WatchProgress, error)
ListInProgressItems returns items the user is currently watching (partial progress). Optional filter: mediaType (empty for all types).
func (*ProgressClient) ListWatchedItems ¶
func (c *ProgressClient) ListWatchedItems(ctx context.Context, userID, mediaType string, limit, offset int) ([]*WatchProgress, error)
ListWatchedItems returns all watched items for a user. Optional filter: mediaType (empty for all types).
type Property ¶
type Property struct {
// contains filtered or unexported fields
}
Property represents a JSON Schema property (a settings field). Use String(), Number(), Boolean(), Integer(), or Array() to create one.
func Array ¶
func Array() *Property
Array creates an array property builder. Array properties can be used for multi-select with ItemsEnum().
Example:
sdk.Array().Title("Image Types").
ItemsEnum("poster", "backdrop", "logo").
Default([]string{"poster", "backdrop"})
func Boolean ¶
func Boolean() *Property
Boolean creates a boolean property builder. Boolean properties render as toggle switches.
Example:
sdk.Boolean().Title("Enable Feature").Default(true)
func Integer ¶
func Integer() *Property
Integer creates an integer property builder. Integer properties render as numeric inputs (whole numbers only).
Example:
sdk.Integer().Title("Max Tokens").Default(1000)
func Number ¶
func Number() *Property
Number creates a number property builder. Number properties render as numeric inputs (allows decimals).
Example:
sdk.Number().Title("Temperature").Default(0.7)
func PluginRef ¶
PluginRef creates a plugin reference property builder. This renders as a dropdown to select a provider plugin, with the selected plugin's settings shown inline below the dropdown.
Use this in configuration plugins (like ai-local) to let users select and configure provider plugins for specific capabilities.
The property value is the selected plugin ID (string). The referenced plugin's settings are stored separately under the settingsKey.
Example:
// In ai-local schema:
sdk.PluginRef("embedding").
Title("Embedding Provider").
Description("Select which plugin provides embeddings")
This generates a UI with:
- A dropdown listing all plugins providing the "embedding" capability
- When a plugin is selected, its settings form appears inline
- The selected plugin's settings are saved under "embedding_provider_settings"
func String ¶
func String() *Property
String creates a string property builder. String properties render as text inputs.
Example:
sdk.String().Title("API Key").Format("password").Required()
func (*Property) Default ¶
Default sets the default value for the property. This value is used when no value has been saved.
Example:
sdk.String().Title("Model").Default("gpt-4o-mini")
func (*Property) DependsOn ¶
DependsOn sets conditional visibility - this property only shows when the specified field has the specified value.
Example:
sdk.String().Title("API Key").DependsOn("enabled", true)
func (*Property) Description ¶
Description sets the property description shown as help text.
Example:
sdk.String().Title("API Key").Description("Get your key from the dashboard")
func (*Property) Enum ¶
Enum sets the allowed values for the property. When set, the field renders as a dropdown select.
Example:
sdk.String().Title("Model").Enum("gpt-4", "gpt-3.5-turbo")
func (*Property) EnumStrings ¶
EnumStrings sets the allowed string values for the property. Convenience method for string enums.
Example:
sdk.String().Title("Model").EnumStrings("gpt-4", "gpt-3.5-turbo")
func (*Property) Format ¶
Format sets the property format for special rendering. Common formats:
- "password": Renders as masked input
- "uri": Validates as URL
- "email": Validates as email
Example:
sdk.String().Title("API Key").Format("password")
func (*Property) ItemsEnum ¶
ItemsEnum sets the allowed values for array items (multi-select). When used with Array(), renders as a multi-select dropdown.
Example:
sdk.Array().Title("Image Types").
ItemsEnum("poster", "backdrop", "logo").
Default([]string{"poster"})
func (*Property) Max ¶
Max sets the maximum value for number/integer properties.
Example:
sdk.Number().Title("Similarity").Min(0.0).Max(1.0)
func (*Property) Min ¶
Min sets the minimum value for number/integer properties.
Example:
sdk.Integer().Title("Batch Size").Min(10).Max(200)
func (*Property) Required ¶
Required marks this property as required. Required fields must have a value before saving.
Example:
sdk.String().Title("API Key").Required()
func (*Property) SettingsKey ¶
SettingsKey sets the key where the referenced plugin's settings are stored. Default is "{capability}_provider_settings".
Example:
sdk.PluginRef("embedding").SettingsKey("custom_embedding_config")
type PropertyType ¶
type PropertyType string
PropertyType represents JSON Schema property types.
const ( TypeString PropertyType = "string" TypeNumber PropertyType = "number" TypeInteger PropertyType = "integer" TypeBoolean PropertyType = "boolean" TypeArray PropertyType = "array" TypeObject PropertyType = "object" )
type ProviderCapabilities ¶
type ProviderCapabilities struct {
// ProviderID is a unique identifier, e.g., "ollama", "openai", "anthropic"
ProviderID string
// DisplayName is the human-readable name, e.g., "Ollama (Local)"
DisplayName string
// Description describes the provider
Description string
// SupportsChat indicates if this provider supports chat completions
SupportsChat bool
// SupportsEmbedding indicates if this provider supports embedding generation
SupportsEmbedding bool
// SupportsStreaming indicates if this provider supports streaming responses
SupportsStreaming bool
// RequiresAPIKey indicates if this provider requires an API key
RequiresAPIKey bool
// RequiresURL indicates if this provider requires a custom URL (e.g., Ollama)
RequiresURL bool
// IsLocal indicates if this provider runs locally (affects UI display)
IsLocal bool
// DefaultChatModel is the default model ID for chat
DefaultChatModel string
// DefaultEmbeddingModel is the default model ID for embeddings
DefaultEmbeddingModel string
}
ProviderCapabilities describes what an AI provider supports.
type ProviderCoreGRPCPlugin ¶
type ProviderCoreGRPCPlugin struct {
plugin.Plugin
Impl ProviderPlugin
// contains filtered or unexported fields
}
ProviderCoreGRPCPlugin is the go-plugin for PluginCore service.
func (*ProviderCoreGRPCPlugin) GRPCClient ¶
func (p *ProviderCoreGRPCPlugin) GRPCClient(ctx context.Context, broker *plugin.GRPCBroker, c *grpc.ClientConn) (interface{}, error)
func (*ProviderCoreGRPCPlugin) GRPCServer ¶
func (p *ProviderCoreGRPCPlugin) GRPCServer(broker *plugin.GRPCBroker, s *grpc.Server) error
type ProviderHealth ¶
type ProviderHealth struct {
// Healthy indicates if the provider is ready to serve requests
Healthy bool
// Message is a human-readable status message
Message string
// Latency is the health check latency
Latency time.Duration
// Error is the error message if unhealthy
Error string
}
ProviderHealth indicates the health of a provider.
type ProviderModel ¶
type ProviderModel struct {
// ID is the model identifier, e.g., "llama3.2", "gpt-4o-mini"
ID string
// Name is the human-readable name
Name string
// Description describes the model
Description string
// IsChat indicates if this is a chat/completion model
IsChat bool
// IsEmbedding indicates if this is an embedding model
IsEmbedding bool
// ContextLength is the context window size (for chat models)
ContextLength int
// EmbeddingDimensions is the embedding vector size (for embedding models)
EmbeddingDimensions int
// Size is the model size for display, e.g., "7B", "3.8GB"
Size string
// Recommended indicates if this model is recommended
Recommended bool
}
ProviderModel describes a model available from a provider.
type ProviderPlugin ¶
type ProviderPlugin interface {
// GetProviderCapabilities returns what this provider supports.
GetProviderCapabilities() ProviderCapabilities
// Initialize is called when the plugin is loaded.
// Config contains the contents of config.yml passed by the host.
Initialize(ctx context.Context, dataDir string, config []byte, systemInfo *SystemInfo) error
// Shutdown is called before the plugin is unloaded.
Shutdown(ctx context.Context) error
// HealthCheck verifies the provider is working (API key valid, service reachable).
HealthCheck(ctx context.Context) (*ProviderHealth, error)
// ListModels returns available models from this provider.
ListModels(ctx context.Context) ([]ProviderModel, error)
// GenerateEmbedding generates an embedding for a single text.
GenerateEmbedding(ctx context.Context, text, model string) ([]float32, error)
// GenerateEmbeddingBatch generates embeddings for multiple texts.
GenerateEmbeddingBatch(ctx context.Context, texts []string, model string) ([][]float32, error)
// Chat sends a chat completion request.
Chat(ctx context.Context, req *ChatRequest) (*ChatResponse, error)
// ChatStream sends a streaming chat completion request.
// Implementations should send chunks to the provided channel and close it when done.
ChatStream(ctx context.Context, req *ChatRequest, chunks chan<- ChatChunk) error
// contains filtered or unexported methods
}
ProviderPlugin is the interface that AI provider plugins must implement. Providers offer LLM capabilities (embeddings, chat) to other plugins via the host.
Plugin identity comes from the plugin.yml manifest file.
type ProviderServiceGRPCPlugin ¶
type ProviderServiceGRPCPlugin struct {
plugin.Plugin
Impl ProviderPlugin
// contains filtered or unexported fields
}
ProviderServiceGRPCPlugin is the go-plugin for PluginProvider service.
func (*ProviderServiceGRPCPlugin) GRPCClient ¶
func (p *ProviderServiceGRPCPlugin) GRPCClient(ctx context.Context, broker *plugin.GRPCBroker, c *grpc.ClientConn) (interface{}, error)
func (*ProviderServiceGRPCPlugin) GRPCServer ¶
func (p *ProviderServiceGRPCPlugin) GRPCServer(broker *plugin.GRPCBroker, s *grpc.Server) error
type RateLimit ¶
type RateLimit struct {
// RequestsPerMinute is the maximum requests per minute (0 = no limit)
RequestsPerMinute int
// PerUser limits per-user if true, otherwise global for this route
PerUser bool
}
RateLimit configures rate limiting for a route.
type Rating ¶
type Rating struct {
ID int64
UserID string
EntityType string // "movie", "tv_show", "tv_episode"
EntityID int64
Rating string // "favorite", "up", "down"
CreatedAt time.Time
UpdatedAt time.Time
}
Rating represents a user's rating for a media item.
type RatingsClient ¶
type RatingsClient struct {
// contains filtered or unexported fields
}
RatingsClient wraps the HostRatings service for reading user ratings. Plugins use this to access user preferences (favorites, likes, dislikes) for generating personalized recommendations.
func NewRatingsClient ¶
func NewRatingsClient(conn *grpc.ClientConn) *RatingsClient
NewRatingsClient creates a new ratings client.
func (*RatingsClient) GetDownvotedIDs ¶
func (c *RatingsClient) GetDownvotedIDs(ctx context.Context, userID, entityType string, limit int) ([]int64, error)
GetDownvotedIDs returns entity IDs that the user has downvoted (disliked).
func (*RatingsClient) GetFavoriteIDs ¶
func (c *RatingsClient) GetFavoriteIDs(ctx context.Context, userID, entityType string, limit int) ([]int64, error)
GetFavoriteIDs returns entity IDs that the user has marked as favorite.
func (*RatingsClient) GetPositivelyRatedIDs ¶
func (c *RatingsClient) GetPositivelyRatedIDs(ctx context.Context, userID, entityType string, limit int) ([]int64, error)
GetPositivelyRatedIDs returns entity IDs that the user has rated positively (favorite or up). This is useful for recommendations that treat both ratings as positive signals.
func (*RatingsClient) GetUpvotedIDs ¶
func (c *RatingsClient) GetUpvotedIDs(ctx context.Context, userID, entityType string, limit int) ([]int64, error)
GetUpvotedIDs returns entity IDs that the user has upvoted (liked).
func (*RatingsClient) HasRatings ¶
HasRatings returns whether a user has any ratings.
func (*RatingsClient) ListRatings ¶
func (c *RatingsClient) ListRatings(ctx context.Context, userID, entityType, ratingType string) ([]*Rating, error)
ListRatings returns all ratings for a user. Optional filters: entityType (empty for all), ratingType (empty for all).
type Route ¶
type Route struct {
// Path is relative to the plugin namespace, e.g., "/search" or "/items/:id"
// Supports :param syntax for path parameters
Path string
// Methods lists HTTP methods this route handles: GET, POST, PUT, DELETE, PATCH
Methods []string
// AdminOnly restricts this route to admin users
AdminOnly bool
// Description is human-readable text for API docs
Description string
// Capability is the capability name this route provides (e.g., "search", "chat")
// Other plugins can invoke this capability via the host plugins service.
Capability string
// AliasPath is a stable URL alias for this route (e.g., "/api/search")
// If set, the host will create an alias at this path that proxies to this route.
// This allows plugins to claim well-known API paths.
AliasPath string
// Streaming indicates this route uses HandleHTTPStream instead of HandleHTTP
Streaming bool
// RateLimit optionally limits requests to this route
RateLimit *RateLimit
}
Route describes an HTTP route exposed by a plugin.
type Row ¶
type Row struct {
// contains filtered or unexported fields
}
Row is a single result row from QueryRow.
type Rows ¶
type Rows struct {
// contains filtered or unexported fields
}
Rows is an iterator over query results.
type SQLClient ¶
type SQLClient struct {
// contains filtered or unexported fields
}
SQLClient provides managed SQL storage for plugins. All table names are automatically prefixed by the host with plugin_{id}_
func (*SQLClient) Exec ¶
func (c *SQLClient) Exec(ctx context.Context, sql string, args ...any) (rowsAffected int64, lastInsertID int64, err error)
Exec executes a DDL or DML statement (CREATE, INSERT, UPDATE, DELETE). Returns the number of rows affected and the last insert ID (if applicable).
Example:
rowsAffected, lastID, err := db.Exec(ctx,
`INSERT INTO items (name, value) VALUES (?, ?)`,
"test", 42)
func (*SQLClient) Migrate ¶
Migrate runs schema migrations, applying any that haven't been run yet. Migrations are tracked in an _migrations table (auto-prefixed by host).
Example:
err := db.Migrate(ctx, []sdk.Migration{
{Version: 1, SQL: `CREATE TABLE items (id INTEGER PRIMARY KEY, name TEXT)`},
{Version: 2, SQL: `ALTER TABLE items ADD COLUMN created_at TIMESTAMP`},
{Version: 3, SQL: `CREATE INDEX idx_items_name ON items(name)`},
})
func (*SQLClient) Query ¶
Query executes a SELECT statement and returns an iterator over the results.
Example:
rows, err := db.Query(ctx, `SELECT id, name FROM items WHERE value > ?`, 10)
if err != nil {
return err
}
defer rows.Close()
for rows.Next() {
var id int64
var name string
if err := rows.Scan(&id, &name); err != nil {
return err
}
// use id, name
}
return rows.Err()
func (*SQLClient) QueryRow ¶
QueryRow executes a SELECT expected to return at most one row. Returns a Row that can be scanned. If the query returns no rows, Scan will return ErrNoRows.
Example:
var name string
err := db.QueryRow(ctx, `SELECT name FROM items WHERE id = ?`, 1).Scan(&name)
if errors.Is(err, sdk.ErrNoRows) {
// not found
}
type Schema ¶
type Schema struct {
// contains filtered or unexported fields
}
Schema builds a JSON Schema for plugin settings. Use NewSchema to create an instance and chain methods to configure it.
func NewSchema ¶
NewSchema creates a new schema builder with the given title. The title appears in the schema but is typically stripped by the UI since the plugin name is shown in the card header.
Example:
schema := sdk.NewSchema("My Plugin Settings")
func (*Schema) Action ¶
Action adds an action to the x-viewra-actions extension. Actions create interactive UI elements like buttons and lists.
Action types:
- TestAction: A "Test Connection" button
- ListAction: A list of items with actions (e.g., model list)
Example:
schema.Action(sdk.TestAction("test-connection", "/health"))
func (*Schema) Build ¶
Build serializes the schema to JSON bytes. Most plugins should use BuildSettingsSchema instead.
func (*Schema) BuildSettingsSchema ¶
func (s *Schema) BuildSettingsSchema() (*pluginv1.SettingsSchema, error)
BuildSettingsSchema builds and returns a SettingsSchema proto message. Deprecated: Use Build() instead for SDK-only plugins.
Example:
func (p *Plugin) GetSettingsSchema() ([]byte, error) {
return SettingsSchema().Build()
}
func (*Schema) Meta ¶
func (s *Schema) Meta(meta PluginMeta) *Schema
Meta sets the x-viewra-meta extension for the schema. This metadata controls how the plugin appears in the UI.
Example:
schema.Meta(sdk.PluginMeta{
DisplayName: "My Plugin",
Description: "Does useful things",
Icon: "star",
})
func (*Schema) Property ¶
Property adds a property (setting field) to the schema. Properties are rendered as form fields in the settings UI. Use sdk.String(), sdk.Number(), sdk.Boolean(), or sdk.Integer() to create the property builder.
Example:
schema.Property("api_key", sdk.String().
Title("API Key").
Format("password").
Required())
func (*Schema) Section ¶
Section adds a section to the x-viewra-sections extension. Sections group properties and actions by capability, allowing the UI to show only relevant settings based on context.
This is useful for plugins that support multiple capabilities (e.g., both embedding and chat) but have different settings for each.
Example:
schema.Section(sdk.NewSection("embedding").
Properties("embedding_model").
Actions("embedding-models").
Capabilities("embedding"))
func (*Schema) Widgets ¶
Widgets adds widgets to the x-viewra-widgets extension. Widgets are UI sections that the plugin provides for the home screen. Each widget has a type, location, and configuration that clients use to render the widget and fetch its data.
Example:
schema.Widgets([]sdk.Widget{
{
ID: "my-recommendations",
Type: sdk.WidgetTypeMediaRow,
Location: sdk.LocationHomepageSections,
ClientTypes: []string{sdk.ClientTypeAll},
Priority: 80,
CacheTTLSeconds: 600,
Config: map[string]any{
"endpoint": "/recommendations",
"title": "Recommended for You",
},
SettingsKey: "enabled",
},
})
type SearchProvider ¶
type SearchProvider interface {
// Search performs a search with the given request.
// This is called when users search via the search hero or global search.
Search(ctx context.Context, req *SearchProviderRequest) (*SearchProviderResponse, error)
// GetSuggestions returns contextual suggestions for the search hero.
// Suggestions can be personalized based on user, time, weather, etc.
GetSuggestions(ctx context.Context, req *SuggestionRequest) (*SuggestionResponse, error)
// GetSearchProviderInfo returns metadata about this search provider.
// Used for provider selection UI and priority ordering.
GetSearchProviderInfo(ctx context.Context) (*SearchProviderInfo, error)
// contains filtered or unexported methods
}
SearchProvider is the interface that search provider plugins must implement. Plugins providing this capability offer search functionality to the home screen and other parts of the application.
type SearchProviderInfo ¶
type SearchProviderInfo struct {
// ID is a unique identifier for this provider.
// Example: "semantic-search", "basic-search"
ID string
// Name is the human-readable name.
// Example: "AI-Powered Search", "Basic Search"
Name string
// Description describes what this provider does.
// Example: "Semantic search using AI embeddings"
Description string
// Icon is the icon name to display.
// Common icons: "sparkles", "search", "brain"
Icon string
// Priority determines which provider is used by default.
// Higher values = higher priority. Suggested ranges:
// 100+ = AI-powered providers (semantic search)
// 50 = Enhanced providers (fuzzy matching)
// 10 = Basic providers (text search)
Priority int
// Capabilities lists what this provider supports.
// Values:
// "natural_language" - Understands natural language queries
// "suggestions" - Provides contextual suggestions
// "context_aware" - Uses user context (time, weather, etc.)
// "fuzzy_matching" - Handles typos and variations
Capabilities []string
}
SearchProviderInfo contains metadata about a search provider.
type SearchProviderRequest ¶
type SearchProviderRequest struct {
// Query is the search query text.
Query string
// EntityTypes filters results by media types.
// Empty means all types. Example: ["movie", "tv_show"]
EntityTypes []string
// Limit is the maximum number of results to return.
Limit int
// UserID is the requesting user (for context enrichment).
UserID string
}
SearchProviderRequest contains parameters for a search request.
type SearchProviderResponse ¶
type SearchProviderResponse struct {
// Results is the list of search results.
Results []SearchResult
// Total is the total number of results (may be more than len(Results)).
Total int
// Provider is the ID of the provider that served this result.
Provider string
// Fallback indicates if this is a fallback result (basic text search).
Fallback bool
}
SearchProviderResponse contains search results.
type SearchResult ¶
type SearchResult struct {
// EntityType is the media type: "movie", "tv_show", "tv_episode", etc.
EntityType string
// EntityID is the database ID of the media item.
EntityID int64
// Title is the display title.
Title string
// Year is the release/air year.
Year int
// Poster is the URL to the poster image.
Poster string
// Score is the relevance score (0.0-1.0).
Score float32
// Reason is an optional explanation for why this result matched.
// Example: "Matches your search for 'sci-fi adventure'"
Reason string
}
SearchResult represents a single search result.
type Section ¶
type Section struct {
// contains filtered or unexported fields
}
Section represents an x-viewra-sections entry. Sections group properties and actions by capability, allowing the host UI to filter what's shown based on context.
For example, an AI provider plugin might have sections for:
- "connection": base_url, test-connection (shown for both embedding and chat)
- "embedding": embedding_model (shown only when used as embedding provider)
- "chat": chat_model (shown only when used as chat provider)
func NewSection ¶
NewSection creates a section builder. The ID should be unique within the schema.
Example:
sdk.NewSection("connection")
func (*Section) Actions ¶
Actions sets which action IDs belong to this section. These should match action IDs defined with schema.Action().
Example:
sdk.NewSection("connection").Actions("test-connection")
func (*Section) Capabilities ¶
Capabilities sets which capabilities this section applies to. The host UI uses this to filter sections based on context.
Standard capabilities:
- "embedding": Show when plugin is used as embedding provider
- "chat": Show when plugin is used as chat provider
A section can belong to multiple capabilities.
Example:
// Connection settings shown for both embedding and chat
sdk.NewSection("connection").
Properties("base_url").
Actions("test-connection").
Capabilities("embedding", "chat")
// Embedding model only shown for embedding capability
sdk.NewSection("embedding").
Properties("embedding_model").
Capabilities("embedding")
func (*Section) DependsOn ¶
DependsOn sets conditional visibility - this section only shows when the specified field has the specified value.
Example:
sdk.NewSection("advanced").
Properties("timeout", "retries").
DependsOn("enabled", true)
func (*Section) Properties ¶
Properties sets which property names belong to this section. These should match property names defined with schema.Property().
Example:
sdk.NewSection("connection").Properties("base_url", "timeout")
type SemanticSearchRequest ¶
type SemanticSearchRequest struct {
Query string // Natural language search query
EntityTypes []string // Filter by entity types: "movie", "tv_show", "tv_episode", etc.
Limit int // Maximum number of results
UserID string // Optional user ID for context enrichment (location, time)
}
SemanticSearchRequest contains parameters for semantic search.
type SemanticSearchResponse ¶
type SemanticSearchResponse struct {
Results []SemanticSearchResult
Total int
}
SemanticSearchResponse contains search results.
type SemanticSearchResult ¶
type SemanticSearchResult struct {
EntityType string // "movie", "tv_show", etc.
EntityID int64 // Database ID of the entity
Similarity float32 // Cosine similarity score (0.0 to 1.0)
Text string // The indexed text that matched
}
SemanticSearchResult represents a single semantic search result.
type StorageClient ¶
type StorageClient struct {
// contains filtered or unexported fields
}
StorageClient wraps the HostStorage service for plugin storage.
func NewStorageClient ¶
func NewStorageClient(conn *grpc.ClientConn) *StorageClient
NewStorageClient creates a new storage client.
func (*StorageClient) Delete ¶
func (c *StorageClient) Delete(ctx context.Context, key string) error
Delete removes a value from the plugin's key-value store.
func (*StorageClient) GetDatabasePath
deprecated
func (c *StorageClient) GetDatabasePath(ctx context.Context) (string, error)
GetDatabasePath returns the path to the plugin's SQLite database.
Deprecated: Use SQL() instead for managed storage. Direct database access requires plugins to bundle their own SQLite driver and manage connections.
func (*StorageClient) SQL ¶
func (c *StorageClient) SQL() *SQLClient
SQL returns a client for managed SQL storage. All table names are automatically prefixed with plugin_{id}_ by the host.
Example:
db := storage.SQL() db.Exec(ctx, `CREATE TABLE items (id INTEGER PRIMARY KEY, name TEXT)`) db.Exec(ctx, `INSERT INTO items (name) VALUES (?)`, "test") rows, _ := db.Query(ctx, `SELECT id, name FROM items`)
func (*StorageClient) Set ¶
Set stores a value in the plugin's key-value store. Use ttlSeconds=0 for no expiration.
func (*StorageClient) Vector ¶
func (c *StorageClient) Vector() *VectorClient
Vector returns a client for managed vector storage. Embeddings are automatically indexed for fast similarity search. Uses pgvector (Postgres) or sqlite-vec (SQLite) under the hood.
Example:
vec := storage.Vector()
vec.Store(ctx, sdk.Embedding{EntityType: "movie", EntityID: 123, Vector: embedding})
results, _ := vec.Search(ctx, sdk.VectorSearchRequest{QueryVector: query, Limit: 10})
type StreamChunk ¶
type StreamChunk struct {
Payload []byte // Serialized response proto
ProviderPlugin string // Which plugin is streaming
Metadata map[string]string // Chunk metadata
Error error // Error if chunk failed
}
StreamChunk represents a chunk from a streaming response.
type StreamingItemAction ¶
type StreamingItemAction struct {
// contains filtered or unexported fields
}
StreamingItemAction represents a streaming action (e.g., model pull). The endpoint should return Server-Sent Events with progress updates.
func NewStreamingAction ¶
func NewStreamingAction(id, label, endpoint string) *StreamingItemAction
NewStreamingAction creates a streaming item action. Use this for long-running operations like downloads.
The endpoint receives POST with item data and should return SSE:
data: {"status": "Downloading...", "percent": 50}
data: {"done": true}
Example:
sdk.NewStreamingAction("pull", "Pull", "/models/pull")
func (*StreamingItemAction) ShowWhen ¶
func (a *StreamingItemAction) ShowWhen(field string, value any) *StreamingItemAction
ShowWhen sets a condition for showing this action. The action only appears on items where item[field] == value.
Example:
// Only show "Pull" on items that aren't installed
sdk.NewStreamingAction("pull", "Pull", "/models/pull").
ShowWhen("installed", false)
type SubtitleTrack ¶
type SubtitleTrack struct {
Language string // ISO 639-1/2 code
Codec string // "srt", "ass", "pgs", "vobsub"
IsForced bool
IsSDH bool // Subtitles for Deaf/Hard of Hearing
IsExternal bool // External file vs embedded
}
SubtitleTrack represents a subtitle stream in a media file.
type Suggestion ¶
type Suggestion struct {
// ID is a unique identifier for this suggestion.
ID string `json:"id"`
// Label is the display text.
Label string `json:"label"`
// Icon is the icon name to display.
// Common icons: "fire", "cloud-rain", "sun", "moon", "snowflake", "heart"
Icon string `json:"icon,omitempty"`
// Description is an optional subtitle.
Description string `json:"description,omitempty"`
// Style affects rendering: "primary", "secondary", "accent".
Style string `json:"style,omitempty"`
// Action defines what happens when the suggestion is clicked.
Action SuggestionAction `json:"action"`
}
Suggestion represents a search suggestion in the search hero widget.
type SuggestionAction ¶
type SuggestionAction struct {
// Type is the action type: "search", "filter", "navigate".
Type string `json:"type"`
// Query is the search query for Type="search".
Query string `json:"query,omitempty"`
// Filter is filter parameters for Type="filter".
Filter map[string]string `json:"filter,omitempty"`
// URL is the navigation URL for Type="navigate".
URL string `json:"url,omitempty"`
}
SuggestionAction defines the action for a search suggestion.
type SuggestionRequest ¶
type SuggestionRequest struct {
// UserID is the requesting user (for personalization).
UserID string
// Context describes where suggestions will be shown.
// Values: "homepage" (search hero), "search_focus" (focused search input)
Context string
// Limit is the maximum number of suggestions to return.
Limit int
}
SuggestionRequest contains parameters for getting search suggestions.
type SuggestionResponse ¶
type SuggestionResponse struct {
// Suggestions is the list of suggestions to display.
Suggestions []Suggestion
}
SuggestionResponse contains search suggestions.
type SystemInfo ¶
type SystemInfo struct {
// RAM in bytes
RAMBytes uint64
// Available RAM in bytes
RAMAvailableBytes uint64
// Whether the system has a GPU
HasGPU bool
// VRAM in bytes
VRAMBytes uint64
// GPU name
GPUName string
// CPU core count
CPUCores int
// CPU model name
CPUModel string
// Operating system: "linux", "darwin", "windows"
OS string
// Architecture: "amd64", "arm64"
Arch string
}
SystemInfo contains host system resource information. Useful for providers that need to recommend models based on available resources.
type TestActionDef ¶
type TestActionDef struct {
// contains filtered or unexported fields
}
TestActionDef defines a test/health-check action. This renders as a "Test Connection" button that calls your health endpoint.
func TestAction ¶
func TestAction(id, endpoint string) *TestActionDef
TestAction creates a test connection action. The endpoint should return a JSON response with:
{"success": true, "message": "Connected successfully"}
or on failure:
{"success": false, "error": "Connection failed"}
Example:
sdk.TestAction("test-connection", "/health")
func (*TestActionDef) Title ¶
func (a *TestActionDef) Title(title string) *TestActionDef
Title sets the action button label. Default is "Test Connection".
Example:
sdk.TestAction("test-connection", "/health").Title("Verify API Key")
type TrendingItem ¶
type TrendingItem struct {
// ExternalID is the external identifier in format "source:id".
// Example: "tmdb:12345", "imdb:tt1234567"
ExternalID string `json:"external_id"`
// MediaType is "movie" or "tv".
MediaType string `json:"media_type"`
// Title is the display title.
Title string `json:"title"`
// Year is the release/air year.
Year int `json:"year"`
// Popularity is the provider-specific popularity score.
// Higher is more popular. Scale varies by provider.
Popularity float32 `json:"popularity"`
// PosterPath is the external URL to the poster image.
// Example: "https://image.tmdb.org/t/p/w500/abc123.jpg"
PosterPath string `json:"poster_path,omitempty"`
// Overview is a brief description/plot summary.
Overview string `json:"overview,omitempty"`
// LocalID is the matched local library ID (filled in by the core service).
// Nil if not matched to local library.
LocalID *int64 `json:"local_id,omitempty"`
// LocalMatched indicates whether this item was matched to the local library.
LocalMatched bool `json:"local_matched"`
}
TrendingItem represents a single trending item from an external source.
type TrendingProvider ¶
type TrendingProvider interface {
// GetTrending returns currently trending items from this provider.
// The response contains external IDs that the core service matches
// against the user's local library.
GetTrending(ctx context.Context, req *TrendingRequest) (*TrendingResponse, error)
// GetTrendingProviderInfo returns metadata about this trending source.
// Used for provider selection and capability discovery.
GetTrendingProviderInfo(ctx context.Context) (*TrendingProviderInfo, error)
// contains filtered or unexported methods
}
TrendingProvider is the interface that trending provider plugins must implement. Plugins providing this capability offer trending/popular content data from external sources (TMDb, Trakt, etc.).
type TrendingProviderGRPCPlugin ¶
type TrendingProviderGRPCPlugin struct {
plugin.Plugin
Impl TrendingProvider
}
TrendingProviderGRPCPlugin is the go-plugin for TrendingProviderService.
func (*TrendingProviderGRPCPlugin) GRPCClient ¶
func (p *TrendingProviderGRPCPlugin) GRPCClient(ctx context.Context, broker *plugin.GRPCBroker, c *grpc.ClientConn) (interface{}, error)
func (*TrendingProviderGRPCPlugin) GRPCServer ¶
func (p *TrendingProviderGRPCPlugin) GRPCServer(broker *plugin.GRPCBroker, s *grpc.Server) error
type TrendingProviderInfo ¶
type TrendingProviderInfo struct {
// ID is a unique identifier for this provider.
// Example: "tmdb", "trakt"
ID string
// Name is the human-readable name.
// Example: "TMDb Trending", "Trakt Popular"
Name string
// Description describes what this provider offers.
// Example: "Trending movies and TV shows from The Movie Database"
Description string
// Windows lists supported time windows.
// Example: ["day", "week"]
Windows []string
// MediaTypes lists supported media types.
// Example: ["movie", "tv", "all"]
MediaTypes []string
// UpdateFreq describes how often data is updated.
// Values: "hourly", "daily", "weekly"
UpdateFreq string
}
TrendingProviderInfo contains metadata about a trending provider.
type TrendingRequest ¶
type TrendingRequest struct {
// MediaType filters by media type.
// Values: "movie", "tv", "all" (default: "all")
MediaType string
// Window is the time window for trending.
// Values: "day", "week" (default: "week")
Window string
// Limit is the maximum number of items to return.
// Default: 20
Limit int
// Region is an optional ISO 3166-1 country code for regional trending.
// Example: "US", "GB", "DE"
Region string
}
TrendingRequest contains parameters for a trending request.
type TrendingResponse ¶
type TrendingResponse struct {
// Items is the list of trending items.
Items []TrendingItem
// Window is the time window used.
Window string
// Source is the provider that served this data.
// Example: "tmdb", "trakt"
Source string
// CachedAt is the Unix timestamp when this data was fetched.
// Used for cache management.
CachedAt int64
}
TrendingResponse contains trending items from a provider.
type TrendingResult ¶
type TrendingResult struct {
// Items contains trending items matched to the local library.
Items []TrendingItem
// Source is the provider that served the original data.
Source string
// Window is the time window used.
Window string
// TotalMatched is the number of items matched to local library.
TotalMatched int
// TotalTrending is the total trending items from the provider.
TotalTrending int
}
TrendingResult is the processed trending data with local library matches. Returned by the core TrendingService after matching.
type VectorClient ¶
type VectorClient struct {
// contains filtered or unexported fields
}
VectorClient provides managed vector storage for plugins. Embeddings are automatically indexed for fast similarity search.
func (*VectorClient) Count ¶
Count returns the number of embeddings. If entityType is empty, returns total count across all types.
Example:
total, _ := vec.Count(ctx, "") movies, _ := vec.Count(ctx, "movie")
func (*VectorClient) Delete ¶
Delete removes an embedding.
Example:
err := vec.Delete(ctx, "movie", 123)
func (*VectorClient) DeleteAll ¶
func (c *VectorClient) DeleteAll(ctx context.Context) (int64, error)
DeleteAll removes all embeddings for this plugin. Returns the number of deleted embeddings.
func (*VectorClient) DeleteByType ¶
DeleteByType removes all embeddings for an entity type. Returns the number of deleted embeddings.
Example:
count, err := vec.DeleteByType(ctx, "movie")
fmt.Printf("Deleted %d embeddings\n", count)
func (*VectorClient) Get ¶
func (c *VectorClient) Get(ctx context.Context, entityType string, entityID int64) (*Embedding, error)
Get retrieves an embedding by entity type and ID. Returns nil if the embedding doesn't exist.
Example:
emb, err := vec.Get(ctx, "movie", 123)
if emb != nil {
fmt.Printf("Found embedding with %d dimensions\n", len(emb.Vector))
}
func (*VectorClient) Search ¶
func (c *VectorClient) Search(ctx context.Context, req VectorSearchRequest) (*VectorSearchResponse, error)
Search performs similarity search using the query vector. Returns results ordered by similarity (highest first).
Example:
results, err := vec.Search(ctx, sdk.VectorSearchRequest{
QueryVector: queryEmbedding,
EntityTypes: []string{"movie", "tv_show"},
Limit: 10,
MinSimilarity: 0.5,
})
for _, r := range results.Results {
fmt.Printf("%s %d: %.2f - %s\n", r.EntityType, r.EntityID, r.Similarity, r.Text)
}
func (*VectorClient) SearchText ¶
func (c *VectorClient) SearchText(ctx context.Context, query string, entityTypes []string, limit int) (*VectorSearchResponse, error)
SearchText performs text-based search on embedding text field. This is useful for name/title searches where semantic search may fail.
Example:
results, err := vec.SearchText(ctx, "Christopher Nolan", []string{"movie"}, 50)
for _, r := range results.Results {
fmt.Printf("%s %d: %s\n", r.EntityType, r.EntityID, r.Text)
}
func (*VectorClient) Store ¶
func (c *VectorClient) Store(ctx context.Context, emb Embedding) error
Store saves or updates an embedding for an entity. If an embedding already exists for the entity, it is replaced.
Example:
err := vec.Store(ctx, sdk.Embedding{
EntityType: "movie",
EntityID: 123,
Vector: embedding,
Text: "The Matrix (1999)",
Model: "nomic-embed-text",
})
func (*VectorClient) StoreBatch ¶
func (c *VectorClient) StoreBatch(ctx context.Context, embeddings []Embedding) error
StoreBatch saves multiple embeddings in a single transaction. This is more efficient than calling Store multiple times.
Example:
err := vec.StoreBatch(ctx, []sdk.Embedding{
{EntityType: "movie", EntityID: 1, Vector: emb1},
{EntityType: "movie", EntityID: 2, Vector: emb2},
})
type VectorSearchEnricherPlugin ¶
type VectorSearchEnricherPlugin interface {
EnricherPlugin
VectorSearchPlugin
}
VectorSearchEnricherPlugin combines EnricherPlugin and VectorSearchPlugin interfaces. Plugins should implement this combined interface for full functionality.
type VectorSearchGRPCPlugin ¶
type VectorSearchGRPCPlugin struct {
plugin.Plugin
Impl VectorSearchPlugin
}
VectorSearchGRPCPlugin implements plugin.GRPCPlugin for the VectorSearch service.
func (*VectorSearchGRPCPlugin) GRPCClient ¶
func (p *VectorSearchGRPCPlugin) GRPCClient(ctx context.Context, broker *plugin.GRPCBroker, c *grpc.ClientConn) (interface{}, error)
func (*VectorSearchGRPCPlugin) GRPCServer ¶
func (p *VectorSearchGRPCPlugin) GRPCServer(broker *plugin.GRPCBroker, s *grpc.Server) error
type VectorSearchPlugin ¶
type VectorSearchPlugin interface {
// Search performs semantic search across indexed media.
// The query is converted to an embedding and matched against stored embeddings.
Search(ctx context.Context, req *SemanticSearchRequest) (*SemanticSearchResponse, error)
// FindSimilar finds items similar to a given entity.
// Uses the entity's stored embedding to find similar items.
FindSimilar(ctx context.Context, req *FindSimilarRequest) (*SemanticSearchResponse, error)
// GetStatus returns the current indexing status and statistics.
GetStatus(ctx context.Context) (*VectorSearchStatus, error)
// IndexLibrary triggers indexing for all media in a library.
// Indexing runs in the background; use GetStatus to monitor progress.
IndexLibrary(ctx context.Context, req *IndexLibraryRequest) (*IndexLibraryResponse, error)
// CancelIndexing cancels any running indexing operation.
CancelIndexing(ctx context.Context) error
// contains filtered or unexported methods
}
VectorSearchPlugin is the interface that vector search plugins must implement. Plugins implementing this interface should also implement EnricherPlugin for auto-indexing support in the enrichment pipeline.
type VectorSearchRequest ¶
type VectorSearchRequest struct {
// QueryVector is the embedding to search for similar items
QueryVector []float32
// EntityTypes filters results by type (empty = all types)
EntityTypes []string
// Limit is the maximum number of results (default: 20)
Limit int
// Offset for pagination
Offset int
// MinSimilarity filters results below this threshold (0.0-1.0)
MinSimilarity float32
}
VectorSearchRequest specifies search parameters.
type VectorSearchResponse ¶
type VectorSearchResponse struct {
// Results ordered by similarity (highest first)
Results []VectorSearchResult
// TotalCount is the total number of matching embeddings
TotalCount int
}
VectorSearchResponse contains search results.
type VectorSearchResult ¶
type VectorSearchResult struct {
// EntityType of the matched embedding
EntityType string
// EntityID of the matched embedding
EntityID int64
// Similarity score (0.0-1.0, higher is more similar)
Similarity float32
// Text that was embedded
Text string
}
VectorSearchResult represents a search result.
type VectorSearchStatus ¶
type VectorSearchStatus struct {
IsIndexing bool // Whether indexing is currently running
Progress *IndexingProgress // Current operation progress (if indexing)
Stats []EntityTypeStats // Per-entity-type statistics
TotalIndexed int64 // Total embeddings stored
}
VectorSearchStatus contains the current indexing status.
type WatchProgress ¶
type WatchProgress struct {
MediaID int64
MediaType string // "movie", "tv_episode"
ProgressSeconds float64 // Current playback position
DurationSeconds float64 // Total duration
ProgressPercent float64 // Progress as percentage (0-100)
IsWatched bool // True if marked as watched
LastWatchedAt time.Time
}
WatchProgress represents a user's watch progress for a media item.
type Weather ¶
type Weather struct {
Temperature float32 // Celsius
Humidity int // Percentage
IsDay bool
Precipitation float32 // mm
CloudCover int // Percentage
WeatherCode int // WMO code
Condition string // sunny, cloudy, rainy, snowy, stormy, foggy
TimeOfDay string // morning, afternoon, evening, night
Season string // spring, summer, fall, winter
}
Weather contains current weather and time context.
type WeatherClient ¶
type WeatherClient struct {
// contains filtered or unexported fields
}
WeatherClient wraps the HostWeather service for context enrichment.
func NewWeatherClient ¶
func NewWeatherClient(conn *grpc.ClientConn) *WeatherClient
NewWeatherClient creates a new weather client.
func (*WeatherClient) GetWeather ¶
GetWeather returns current weather for a user's location. Returns nil if the user hasn't enabled location sharing.
type Widget ¶
type Widget struct {
// ID is a unique identifier for this widget within the plugin.
// Example: "rec-for-you", "search-hero"
ID string `json:"id"`
// Type determines how the widget is rendered.
// Use WidgetTypeSearchHero, WidgetTypeMediaRow, etc.
Type string `json:"type"`
// Location specifies where on the home screen this widget appears.
// Use LocationHomepageTop or LocationHomepageSections.
Location string `json:"location"`
// ClientTypes specifies which clients should render this widget.
// Use ["all"] for all clients, or specific types like ["web", "ios"].
// Clients filter widgets by their type and only render matching ones.
ClientTypes []string `json:"client_types"`
// Priority determines order within a location (higher = rendered first).
// Use 100 for critical widgets, 50 for normal, 0 for fallback.
Priority int `json:"priority"`
// CacheTTLSeconds is how long clients should cache this widget's data.
// Use 60 for frequently changing data, 3600 for stable data.
CacheTTLSeconds int `json:"cache_ttl_seconds,omitempty"`
// Config contains widget-specific configuration passed to the client.
// Common fields:
// - endpoint: HTTP endpoint to fetch widget data (e.g., "/recommendations")
// - title: Default title for the widget
// - show_suggestions: For search-hero, whether to show suggestion chips
Config map[string]any `json:"config,omitempty"`
// RequiredCapability makes this widget only appear when a capability is available.
// Example: "search_provider" - only show if semantic search is enabled.
RequiredCapability string `json:"required_capability,omitempty"`
// SettingsKey references a boolean setting that controls widget visibility.
// When the setting is false, the widget is hidden.
// Example: "enabled", "show_recommendations"
SettingsKey string `json:"settings_key,omitempty"`
}
Widget defines a UI section that a plugin provides for the home screen. Widgets are registered via the settings schema and rendered by clients.
type WidgetCoreGRPCPlugin ¶
type WidgetCoreGRPCPlugin struct {
plugin.Plugin
Impl WidgetPlugin
// contains filtered or unexported fields
}
WidgetCoreGRPCPlugin implements plugin.GRPCPlugin for WidgetPlugin.
func (*WidgetCoreGRPCPlugin) GRPCClient ¶
func (p *WidgetCoreGRPCPlugin) GRPCClient(ctx context.Context, broker *plugin.GRPCBroker, c *grpc.ClientConn) (interface{}, error)
func (*WidgetCoreGRPCPlugin) GRPCServer ¶
func (p *WidgetCoreGRPCPlugin) GRPCServer(broker *plugin.GRPCBroker, s *grpc.Server) error
type WidgetDataRequest ¶
type WidgetDataRequest struct {
// WidgetID is the widget being requested.
WidgetID string
// UserID is the requesting user (for personalization).
UserID string
// ClientType is the type of client making the request.
ClientType string
// ImageSize is the preferred image size ("small", "medium", "large").
ImageSize string
}
WidgetDataRequest contains parameters for fetching widget data. This is passed to plugins when the home service requests widget data.
type WidgetDataResponse ¶
type WidgetDataResponse struct {
// Data is the widget-specific data to render.
// Shape depends on widget type (see WidgetType* constants).
Data map[string]any `json:"data"`
// CacheTTLSeconds overrides the widget's default cache TTL.
CacheTTLSeconds int `json:"cache_ttl_seconds,omitempty"`
}
WidgetDataResponse is the response from a plugin for widget data.
type WidgetError ¶
type WidgetError struct {
// WidgetID is the widget that failed.
WidgetID string
// PluginID is the plugin that provides the widget.
PluginID string
// Error is the error message.
Error string
// Timestamp is when the error occurred.
Timestamp int64
}
WidgetError represents an error from widget data fetching. Errors are logged but widgets with errors are silently omitted from the response.
type WidgetPlugin ¶
type WidgetPlugin interface {
// Initialize is called when the plugin is loaded.
// Config is the contents of config.yml passed by the host.
// Services provides access to host services (storage, data, etc.) - may have nil fields.
Initialize(ctx context.Context, dataDir string, config []byte, services *HostServices) error
// Shutdown is called before the plugin is unloaded.
// Use this to clean up any resources.
Shutdown(ctx context.Context) error
// GetSettingsSchema returns a JSON Schema describing the plugin's configurable settings.
// Use Schema.Build() to generate this from your schema definition.
// Include Widgets() to register home screen widgets.
GetSettingsSchema() ([]byte, error)
// Configure applies new settings to the plugin.
Configure(settings []byte) error
// IsConfigured returns whether the plugin is properly configured.
// Plugins requiring API keys should return false until the key is set.
// The host uses this to exclude unconfigured plugins from capability resolution.
IsConfigured() bool
// GetRoutes returns HTTP routes this plugin exposes.
GetRoutes() []Route
// HandleHTTP handles a non-streaming HTTP request.
HandleHTTP(ctx context.Context, req *HTTPRequest) (*HTTPResponse, error)
// contains filtered or unexported methods
}
WidgetPlugin is the interface that widget plugins must implement. Widget plugins provide HTTP routes and home screen widgets but don't enrich media.
Plugin identity comes from plugin.yml manifest file, not code.