Help us shape the future of Go! Take the 2026 Go Developer Survey

stremio

package module
v0.0.0-...-43d10ff Latest Latest
Warning

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

Go to latest
Published: May 11, 2025 License: AGPL-3.0 Imports: 23 Imported by: 0

README

go-stremio

Stremio addon SDK for Go

Contents

  1. Introduction
  2. About this SDK
  3. Features
  4. Example
  5. Advantages
  6. Related projects

Introduction

Stremio is a modern media center that's a one-stop solution for your video entertainment. You discover, watch and organize video content from easy to install addons.

These addons run remotely as a web service, so they can't do any harm to your computer. This is different from how addons work for Kodi for example, where they run locally on your computer and have dozens of third party dependencies. There have been several security incidents with Kodi addons like this one and even the Kodi developers themselves warn of the dangers of third party Kodi addons.

About this SDK

When developing a Stremio addon, you're essentially developing a web service. But there are some defined routes, expected behavior, JSON structure etc., so instead of having to figure all of this out on your own before you've got even a basic addon running, using an SDK can get you up to speed much faster, as it takes care of all of this automatically.

But the official Stremio addon SDK is for Node.js only.

This SDK is for Go!

It provides the most important parts of the Node.js SDK and depending on the requirements of you, the libary users, it will be extended to provide more in the future.

Features

  • All required types for building catalog and stream addons
  • Graceful server shutdown
    • With optional channel to be notified about the shutdown
  • CORS middleware to allow requests from Stremio
  • Health check endpoint
  • Optional profiling endpoints (for go pprof)
  • Optional request logging
    • With optional movie / TV show name in the log (instead of just the IMDb ID)
    • With optional client IP address and user agent logging to create privacy-preserving addons
  • Optional cache control and ETag handling
  • Optional custom middlewares
  • Optional custom endpoints
  • Custom user data (users can have settings for your addon!)
    • Including the handling of Stremio's requests to the "/configure" endpoint to show a webpage for the addon's configuration
    • With optional URL-safe Base64 decoding and JSON unmarshalling
  • Addon installation callback (manifest endpoint)
  • Cinemeta client in the independent cinemeta package
  • Optional stream ID filtering via regex
  • Optional collection and export of basic metrics for Prometheus

Current non-features, as they're usually part of a reverse proxy deployed in front of the service:

  • TLS termination (for using HTTPS)
  • Rate limiting (against DoS attacks)
  • Compression (like gzip)

Example

Full examples can be found in examples. Here's a part of the one for a stream addon:

package main

import (
    "context"

    "github.com/Dasio/go-stremio"
)

var (
    manifest = stremio.Manifest{
        ID:          "com.example.blender-streams",
        Name:        "Blender movie streams",
        Description: "Stream addon for free movies that were made with Blender",
        // ...
    }
)

func main() {
    // Let the movieHandler handle the "movie" type
    streamHandlers := map[string]stremio.StreamHandler{"movie": movieHandler}

    addon, err := stremio.NewAddon(manifest, nil, streamHandlers, stremio.DefaultOptions)
    if err != nil {
        panic(err)
    }

    addon.Run(nil)
}

func movieHandler(ctx context.Context, id string, userData interface{}) ([]stremio.StreamItem, error) {
    // We only serve Big Buck Bunny and Sintel
    if id == "tt1254207" {
        return []stremio.StreamItem{
            // Torrent stream
            {
                InfoHash: "dd8255ecdc7ca55fb0bbf81323d87062db1f6d1c",
                // Stremio recommends to set the quality as title, as the streams
                // are shown for a specific movie so the user knows the title.
                Title:     "1080p (torrent)",
                FileIndex: 1,
            },
            // HTTP stream
            {
                URL:   "https://ftp.halifax.rwth-aachen.de/blender/demo/movies/BBB/bbb_sunflower_1080p_30fps_normal.mp4",
                Title: "1080p (HTTP stream)",
            },
        }, nil
    } else if id == "tt1727587" {
        // ...
    }
    return nil, stremio.NotFound
}

Advantages

Some reasons why you might want to consider developing an addon in Go with this SDK:

Criterium Node.js addon Go addon
Direct SDK dependencies 9 5
Transitive SDK dependencies 90¹ 36²
Size of a runnable addon 27 MB³ 11-15 MB⁴
Number of artifacts to deploy depends⁵ 1
Runtime dependencies Node.js -
Concurrency Single-threaded Multi-threaded

¹) ls -l node_modules | wc -l - 1
²) go list -m all | wc -l - 1 - (number of direct dependencies)
³) du -h --max-depth=0 node_modules
⁴) The smaller binary is easily achieved by compiling with -ldflags "-s -w"
⁵) All your JavaScript files and the package.json if you can install the depencencies with npm on the server, otherwise (like in a Docker container) you also need all the node_modules, which are hundreds to thousands of files.

Looking at the performance it depends a lot on what your addon does. Due to the single-threaded nature of Node.js, the more CPU-bound tasks your addon does, the bigger the performance difference will be (in favor of Go). Here we compare the simplest possible addon to be able to compare just the SDKs and not any additional overhead (like DB access):

On a DigitalOcean "Droplet" of type "Basic" (shared CPU) with 2 cores and 2 GB RAM, which costs $15/month:

Criterium Node.js addon Go addon
Startup time to 1st request¹ 400ms-4s 20-30ms
Max rps² @ 1000 connections Local³: 1,000
Remote⁴: 1,000
Local³: 17,000
Remote⁴: 29,000
Memory usage @ 1000 connections Idle: 42 MB
Load⁵: 73 MB
Idle: 11 MB
Load⁵: 45 MB

On a DigitalOcean "Droplet" of type "CPU-Optimized" (dedicated CPU) with 2 cores and 4 GB RAM, which costs $40/month:

Criterium Node.js addon Go addon
Startup time to 1st request¹ 200-400ms 9-20ms
Max rps² @ 1000 connections Local³: 5,000
Remote⁴: 1,000
Local³: 39,000
Remote⁴: 39,000
Memory usage @ 1000 connections Idle: 42 MB
Load⁵: 90 MB
Idle: 11 MB
Load⁵: 47 MB

¹) Measured using ttfok and the code in benchmark. This metric is relevant in case you want to use a "serverless functions" service (like AWS Lambda or Vercel (former ZEIT Now)) that doesn't keep your service running between requests.
²) Max number of requests per second where the p99 latency is still < 100ms
³) The load testing tool ran on a different server, but in the same datacenter and the requests were sent within a private network. Note that DigitalOcean seems to have performance issues with their local "VPC Network" (which didn't affect the Node.js service as it maxed out the CPU, but the Go service maxed out the network before the CPU).
⁴) The load testing tool ran on a different server in a different datacenter of another cloud provider in another city for more real world-like circumstances
⁵) Resident size (RES in htop) at a request rate half of what we measured as maximum

The load tests were run under the following circumstances:

  • We used the addon code, load testing tool and setup described in benchmark
  • We ran the Node.js and Go service on the same Droplet and conducted the benchmark on the same day, several minutes apart, so that the resource sharing of the VPS is about the same. Note that when you try to reproduce the benchmark results, a different VPS could be subject to more or less resource sharing with other VPS on the virtualization host. Other times of day can also lead to differing benchmark results (e.g. low traffic on a Monday morning, high traffic on a Saturday evening).
  • The load tests ran for 60s (to have a somewhat meaningful p99 value), with previous warmup
  • The client servers (both the one in the same DC and the one in a different DC of another cloud provider in another city) used to run the load testing tool were high-powered (8 dedicated cores, 32 GB RAM)

Additional observations:

  • The Go service's response times were generally lower across all request rates
  • The Go service's response times had a much lower deviation, i.e. they were more stable. With less than 60s of time for the load test the Node.js service fared even worse, because outliers lead to a higher p99 latency.
  • We also tested on a lower-powered server by a cheap cloud provider (also 2 core, 2 GB RAM, but the CPU was generally worse). In this case the difference between the Node.js and the Go service was even higher. The Go service is perfectly fitted for scaling out with multiple cheap servers.
  • We also tested with different amounts of connections. With more connections the difference between the Node.js and the Go service was also higher. In a production deployment you want to be able to serve as many users as possible, so this goes in favor of the Go service as well.

Note:

  • This Go SDK is still young. Some features will be added in the future that might decrease its performance, while others will increase it.
  • The Node.js addon was run as a single instance. You can do more complex deployments with a load balancer like HAProxy and multiple instances of the same Node.js service on a single machine to take advantage of multiple CPU cores. But then you should also activate preforking in the Go addon for using several OS processes in parallel, which we didn't do.

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrBadRequest signals that the client sent a bad request.
	// It leads to a "400 Bad Request" response.
	ErrBadRequest = errors.New("bad request")
	// ErrNotFound signals that the catalog/meta/stream was not found.
	// It leads to a "404 Not Found" response.
	ErrNotFound = errors.New("not found")
)
View Source
var DefaultOptions = Options{
	BindAddr:     "0.0.0.0",
	Port:         8080,
	LoggingLevel: "info",
	LogEncoding:  "console",
}

DefaultOptions contains the default values for Options.

Functions

func NewLogger

func NewLogger(level string, encoding string) *slog.Logger

NewLogger creates a new logger with the specified level and encoding. The level can be "debug", "info", "warn", or "error". The encoding can be "json" or "console".

Types

type Addon

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

Addon represents a remote addon. You can create one with NewAddon() and then run it with Run().

func NewAddon

func NewAddon(manifest Manifest, catalogHandlers map[string]CatalogHandler, streamHandlers map[string]StreamHandler, opts Options) (*Addon, error)

NewAddon creates a new Addon object that can be started with Run(). A proper manifest must be supplied, but manifestCallback and all but one handler can be nil in case you only want to handle specific requests and opts can be the zero value of Options.

func (*Addon) AddEndpoint

func (a *Addon) AddEndpoint(method, path string, handler http.HandlerFunc)

AddEndpoint adds a custom endpoint (a route and its handler). If you want to be able to access custom user data, you can use a path like this: "/:userData/foo" and then either deal with the data yourself by using `r.URL.Query().Get("userData")` in the handler, or use the convenience method `DecodeUserData("userData", r)`.

func (*Addon) AddSubtitleHandler

func (a *Addon) AddSubtitleHandler(handler SubtitleHandler)

AddSubtitleHandler adds a subtitle handler to the addon

func (*Addon) DecodeUserData

func (a *Addon) DecodeUserData(param string, r *http.Request) (any, error)

DecodeUserData decodes the request's user data and returns the result. It's useful when you add custom endpoints to the addon that don't have a userData parameter like the ManifestCallback, CatalogHandler and StreamHandler have. The param value must match the URL parameter you used when creating the custom endpoint, for example when using `AddEndpoint("GET", "/:userData/ping", customEndpoint)` you must pass "userData".

func (*Addon) RegisterUserData

func (a *Addon) RegisterUserData(userDataObject any)

RegisterUserData registers the type of userData, so the addon can automatically unmarshal user data into an object of this type and pass the object into the manifest callback or catalog and stream handlers.

func (*Addon) Run

func (a *Addon) Run(stoppingChan chan bool)

Run starts the remote addon. It sets up an HTTP server that handles requests to "/manifest.json" etc. and gracefully handles shutdowns. The call is *blocking*, so use the stoppingChan param if you want to be notified when the addon is about to shut down because of a system signal like Ctrl+C or `docker stop`. It should be a buffered channel with a capacity of 1.

func (*Addon) SetConfigurationHandler

func (a *Addon) SetConfigurationHandler(handler ConfigurationHandler)

SetConfigurationHandler sets the configuration handler

func (*Addon) SetConfigurationUI

func (a *Addon) SetConfigurationUI(ui *ConfigurationUI)

SetConfigurationUI sets the configuration UI for the addon

func (*Addon) SetManifestCallback

func (a *Addon) SetManifestCallback(callback ManifestCallback)

SetManifestCallback sets the manifest callback

type BehaviorHints

type BehaviorHints struct {
	// Note: Must include `omitempty`, otherwise it will be included if this struct is used in another one, even if the field of the containing struct is marked as `omitempty`
	Adult        bool `json:"adult,omitempty"`
	P2P          bool `json:"p2p,omitempty"`
	Configurable bool `json:"configurable,omitempty"`
	// If you set this to true, it will be true for the "/manifest.json" endpoint, but false for the "/:userData/manifest.json" endpoint, because otherwise Stremio won't show the "Install" button in its UI.
	ConfigurationRequired bool `json:"configurationRequired,omitempty"`
}

type CatalogHandler

type CatalogHandler func(ctx context.Context, id string, userData any) ([]MetaPreviewItem, error)

CatalogHandler is the callback for catalog requests for a specific type (like "movie"). The id parameter is the catalog ID that you specified yourself in the CatalogItem objects in the Manifest. The userData parameter depends on whether you called `RegisterUserData()` before: If not, a simple string will be passed. It's empty if the user didn't provide user data. If yes, a pointer to an object you registered will be passed. It's nil if the user didn't provide user data.

type CatalogItem

type CatalogItem struct {
	Type string `json:"type"`
	ID   string `json:"id"`
	Name string `json:"name"`

	// Optional
	Extra []ExtraItem `json:"extra,omitempty"`
}

CatalogItem represents a catalog.

type ConfigurationField

type ConfigurationField struct {
	Type        string `json:"type"`                  // The type of the field (e.g. "text", "number", "boolean", etc.)
	Label       string `json:"label"`                 // The label of the field
	Description string `json:"description,omitempty"` // The description of the field
	Default     any    `json:"default,omitempty"`     // The default value of the field
	Required    bool   `json:"required,omitempty"`    // Whether the field is required
	Options     []any  `json:"options,omitempty"`     // The options for the field (for select fields)
	Min         any    `json:"min,omitempty"`         // The minimum value (for number fields)
	Max         any    `json:"max,omitempty"`         // The maximum value (for number fields)
	Step        any    `json:"step,omitempty"`        // The step value (for number fields)
	Pattern     string `json:"pattern,omitempty"`     // The pattern for validation (for text fields)
	Placeholder string `json:"placeholder,omitempty"` // The placeholder text (for text fields)
}

ConfigurationField represents a field in the configuration UI

func NewConfigurationField

func NewConfigurationField(fieldType string, label string) *ConfigurationField

NewConfigurationField creates a ConfigurationField with the given type and label

func (*ConfigurationField) SetDefault

func (f *ConfigurationField) SetDefault(defaultValue any) *ConfigurationField

SetDefault sets the default value of the field

func (*ConfigurationField) SetDescription

func (f *ConfigurationField) SetDescription(description string) *ConfigurationField

SetDescription sets the description of the field

func (*ConfigurationField) SetMax

func (f *ConfigurationField) SetMax(max any) *ConfigurationField

SetMax sets the maximum value for the field

func (*ConfigurationField) SetMin

func (f *ConfigurationField) SetMin(min any) *ConfigurationField

SetMin sets the minimum value for the field

func (*ConfigurationField) SetOptions

func (f *ConfigurationField) SetOptions(options []any) *ConfigurationField

SetOptions sets the options for the field

func (*ConfigurationField) SetPattern

func (f *ConfigurationField) SetPattern(pattern string) *ConfigurationField

SetPattern sets the pattern for validation

func (*ConfigurationField) SetPlaceholder

func (f *ConfigurationField) SetPlaceholder(placeholder string) *ConfigurationField

SetPlaceholder sets the placeholder text

func (*ConfigurationField) SetRequired

func (f *ConfigurationField) SetRequired(required bool) *ConfigurationField

SetRequired sets whether the field is required

func (*ConfigurationField) SetStep

func (f *ConfigurationField) SetStep(step any) *ConfigurationField

SetStep sets the step value for the field

type ConfigurationHandler

type ConfigurationHandler func(ctx context.Context, userData any) (map[string]any, error)

ConfigurationHandler is the callback for configuration requests. The userData parameter depends on whether you called `RegisterUserData()` before: If not, a simple string will be passed. It's empty if the user didn't provide user data. If yes, a pointer to an object you registered will be passed. It's nil if the user didn't provide user data.

type ConfigurationUI

type ConfigurationUI struct {
	Type       string         `json:"type"`               // The type of configuration UI (e.g. "form", "list", etc.)
	Properties map[string]any `json:"properties"`         // The properties of the configuration UI
	Required   []string       `json:"required,omitempty"` // The required fields
	Default    any            `json:"default,omitempty"`  // The default values
}

ConfigurationUI represents the configuration UI for the addon

func NewConfigurationUI

func NewConfigurationUI(uiType string, properties map[string]any) *ConfigurationUI

NewConfigurationUI creates a ConfigurationUI with the given type and properties

func (*ConfigurationUI) AddRequiredField

func (c *ConfigurationUI) AddRequiredField(field string)

AddRequiredField adds a required field to the configuration UI

func (*ConfigurationUI) SetDefault

func (c *ConfigurationUI) SetDefault(defaultValue any)

SetDefault sets the default value for the configuration UI

type ExtraItem

type ExtraItem struct {
	Name string `json:"name"`

	// Optional
	IsRequired   bool     `json:"isRequired,omitempty"`
	Options      []string `json:"options,omitempty"`
	OptionsLimit int      `json:"optionsLimit,omitempty"`
}

type Manifest

type Manifest struct {
	ID          string `json:"id"`
	Name        string `json:"name"`
	Description string `json:"description"`
	Version     string `json:"version"`

	// One of the following is required
	// Note: Can only have one in code because of how Go (de-)serialization works
	//Resources     []string       `json:"resources,omitempty"`
	ResourceItems []ResourceItem `json:"resources,omitempty"`

	Types    []string      `json:"types"` // Stremio supports "movie", "series", "channel" and "tv"
	Catalogs []CatalogItem `json:"catalogs"`

	// Optional
	IDprefixes    []string      `json:"idPrefixes,omitempty"`
	Background    string        `json:"background,omitempty"` // URL
	ContactEmail  string        `json:"contactEmail,omitempty"`
	BehaviorHints BehaviorHints `json:"behaviorHints,omitempty"`
}

Manifest describes the capabilities of the addon. See https://github.com/Stremio/stremio-addon-sdk/blob/f6f1f2a8b627b9d4f2c62b003b251d98adadbebe/docs/api/responses/manifest.md

type ManifestCallback

type ManifestCallback func(ctx context.Context, manifest *Manifest, userData any) int

ManifestCallback is the callback for manifest requests, so mostly addon installations. You can use the callback for two things:

  1. To *prevent* users from installing your addon in Stremio. The userData parameter depends on whether you called `RegisterUserData()` before: If not, a simple string will be passed. It's empty if the user didn't provide user data. If yes, a pointer to an object you registered will be passed. It's nil if the user didn't provide user data. Return an HTTP status code >= 400 to stop further processing and let the addon return that exact status code. Any status code < 400 will lead to the manifest being returned with a 200 OK status code in the response.
  2. To *alter* the manifest before it's returned. This can be useful for example if you want to return some catalogs depending on the userData. Note that the manifest is only returned if the first return value is < 400 (see point 1.).

type MetaBehaviorHints

type MetaBehaviorHints struct {
	DefaultVideoID string `json:"defaultVideoId,omitempty"` // ID of the default video to play
	DefaultSeason  string `json:"defaultSeason,omitempty"`  // Default season for TV shows
	DefaultEpisode string `json:"defaultEpisode,omitempty"` // Default episode for TV shows
	AutoPlay       bool   `json:"autoPlay,omitempty"`       // Whether to auto-play the content
	BingeWatch     bool   `json:"bingeWatch,omitempty"`     // Whether the content supports binge watching
	Proxy          bool   `json:"proxy,omitempty"`          // Whether the content should be proxied
}

MetaBehaviorHints provides additional information about the meta item

type MetaFetcher

type MetaFetcher interface {
	GetMovie(ctx context.Context, imdbID string) (cinemeta.Meta, error)
	GetTVShow(ctx context.Context, imdbID string, season int, episode int) (cinemeta.Meta, error)
}

MetaFetcher returns metadata for movies and TV shows. It's used when you configure that the media name should be logged or that metadata should be put into the context.

type MetaItem

type MetaItem struct {
	ID   string `json:"id"`
	Type string `json:"type"`
	Name string `json:"name"`

	// Optional
	Genres           []string          `json:"genres,omitempty"`   // Will be replaced by Links at some point
	Director         []string          `json:"director,omitempty"` // Will be replaced by Links at some point
	Cast             []string          `json:"cast,omitempty"`     // Will be replaced by Links at some point
	Links            []MetaLinkItem    `json:"links,omitempty"`    // For genres, director, cast and potentially more
	Poster           string            `json:"poster,omitempty"`   // URL
	PosterShape      string            `json:"posterShape,omitempty"`
	Background       string            `json:"background,omitempty"` // URL
	Description      string            `json:"description,omitempty"`
	ReleaseInfo      string            `json:"releaseInfo,omitempty"` // E.g. "2000" for movies and "2000-2014" or "2000-" for TV shows
	IMDbRating       string            `json:"imdbRating,omitempty"`
	Released         string            `json:"released,omitempty"` // Must be ISO 8601, e.g. "2010-12-06T05:00:00.000Z"
	Videos           []VideoItem       `json:"videos,omitempty"`
	Runtime          string            `json:"runtime,omitempty"`
	Language         string            `json:"language,omitempty"`
	Country          string            `json:"country,omitempty"`
	Awards           string            `json:"awards,omitempty"`
	Website          string            `json:"website,omitempty"` // URL
	BehaviorHints    MetaBehaviorHints `json:"behaviorHints,omitempty"`
	Popularity       float64           `json:"popularity,omitempty"`
	VoteAverage      float64           `json:"voteAverage,omitempty"`
	VoteCount        int               `json:"voteCount,omitempty"`
	Status           string            `json:"status,omitempty"`           // For TV shows: "Returning Series", "Ended", etc.
	Network          string            `json:"network,omitempty"`          // For TV shows
	EpisodeRunTime   []int             `json:"episodeRunTime,omitempty"`   // For TV shows
	InProduction     bool              `json:"inProduction,omitempty"`     // For TV shows
	LastAirDate      string            `json:"lastAirDate,omitempty"`      // For TV shows
	NumberOfSeasons  int               `json:"numberOfSeasons,omitempty"`  // For TV shows
	NumberOfEpisodes int               `json:"numberOfEpisodes,omitempty"` // For TV shows
	CreatedBy        []string          `json:"createdBy,omitempty"`        // For TV shows
	Seasons          []SeasonItem      `json:"seasons,omitempty"`          // For TV shows
}

MetaItem represents a meta item and is meant to be used when info for a specific item was requested. See https://github.com/Stremio/stremio-addon-sdk/blob/f6f1f2a8b627b9d4f2c62b003b251d98adadbebe/docs/api/responses/meta.md

type MetaLinkItem

type MetaLinkItem struct {
	Name     string `json:"name"`
	Category string `json:"category"`
	URL      string `json:"url"` //  // URL. Can be "Meta Links" (see https://github.com/Stremio/stremio-addon-sdk/blob/f6f1f2a8b627b9d4f2c62b003b251d98adadbebe/docs/api/responses/meta.links.md)
}

MetaLinkItem links to a page within Stremio. It will at some point replace the usage of `genres`, `director` and `cast`. Note: It's not fully supported by Stremio yet (not fully on PC and not at all on Android)!

type MetaPreviewItem

type MetaPreviewItem struct {
	ID     string `json:"id"`
	Type   string `json:"type"`
	Name   string `json:"name"`
	Poster string `json:"poster"` // URL

	// Optional
	PosterShape string `json:"posterShape,omitempty"`

	// Optional, used for the "Discover" page sidebar
	Genres        []string          `json:"genres,omitempty"`   // Will be replaced by Links at some point
	Director      []string          `json:"director,omitempty"` // Will be replaced by Links at some point
	Cast          []string          `json:"cast,omitempty"`     // Will be replaced by Links at some point
	Links         []MetaLinkItem    `json:"links,omitempty"`    // For genres, director, cast and potentially more
	IMDbRating    string            `json:"imdbRating,omitempty"`
	ReleaseInfo   string            `json:"releaseInfo,omitempty"` // E.g. "2000" for movies and "2000-2014" or "2000-" for TV shows
	Description   string            `json:"description,omitempty"`
	Released      string            `json:"released,omitempty"` // Must be ISO 8601, e.g. "2010-12-06T05:00:00.000Z"
	Runtime       string            `json:"runtime,omitempty"`
	Language      string            `json:"language,omitempty"`
	Country       string            `json:"country,omitempty"`
	Awards        string            `json:"awards,omitempty"`
	Website       string            `json:"website,omitempty"` // URL
	BehaviorHints MetaBehaviorHints `json:"behaviorHints,omitzero"`
}

MetaPreviewItem represents a meta preview item and is meant to be used within catalog responses. See https://github.com/Stremio/stremio-addon-sdk/blob/f6f1f2a8b627b9d4f2c62b003b251d98adadbebe/docs/api/responses/meta.md#meta-preview-object

type Options

type Options struct {
	// Server options
	BindAddr string
	Port     int

	// Logging options
	Logger                *slog.Logger
	LoggingLevel          string // "debug", "info", "warn", "error"
	LogEncoding           string // "json", "console"
	DisableRequestLogging bool
	LogIPs                bool
	LogUserAgent          bool
	LogMediaName          bool

	// Caching options
	CacheAgeCatalogs time.Duration
	CacheAgeStreams  time.Duration
	// If true, the addon will send Cache-Control headers with the max-age set to CacheAgeCatalogs/Streams.
	// This is useful when you have a CDN in front of your addon.
	CachePublicCatalogs bool
	CachePublicStreams  bool
	// If true, the addon will handle ETag headers for catalogs and streams.
	// This is useful when you have a CDN in front of your addon.
	HandleEtagCatalogs bool
	HandleEtagStreams  bool

	// Meta options
	MetaClient       MetaFetcher
	CinemetaTimeout  time.Duration
	PutMetaInContext bool

	// Configuration options
	ConfigureHTMLfs http.FileSystem

	// Other options
	Metrics     bool
	Profiling   bool
	RedirectURL string
	// If true, the addon will expect user data to be base64 encoded.
	UserDataIsBase64 bool
	// If set, the addon will only handle stream requests with IDs matching this regex.
	StreamIDregex string
}

Options contains all options for creating a new addon.

type PrefixedFS

type PrefixedFS struct {
	// Prefix for adding to the filename before looking it up in the FS.
	// Forward slashes are added before and after the prefix and then the file name is cleaned up (removing duplicate slashes).
	Prefix string
	// Regular HTTP FS which you can create with `http.FS(embedFS)` for example.
	FS http.FileSystem
}

PrefixedFS is a wrapper around a http.FileSystem which adds a prefix before looking up the file. This is useful if you use the Go 1.16 embed feature and the directory name doesn't match the request URL. For example if your embed.FS contains a "/web/index.html", but you want to serve it for "/configure" requests, the filesystem middleware already takes care of stripping the "/configure" prefix, but then we also need to add the "/web" prefix. This wrapper does that.

func (*PrefixedFS) Open

func (fs *PrefixedFS) Open(name string) (http.File, error)

Open adds a prefix to the name and then calls the wrapped FS' Open method.

type ResourceItem

type ResourceItem struct {
	Name  string   `json:"name"`
	Types []string `json:"types"` // Stremio supports "movie", "series", "channel" and "tv"

	// Optional
	IDprefixes []string `json:"idPrefixes,omitempty"`
}

type SeasonItem

type SeasonItem struct {
	ID           string `json:"id"`
	Season       int    `json:"season"`
	Name         string `json:"name"`
	Overview     string `json:"overview,omitempty"`
	Poster       string `json:"poster,omitempty"`  // URL
	AirDate      string `json:"airDate,omitempty"` // Must be ISO 8601
	EpisodeCount int    `json:"episodeCount,omitempty"`
}

SeasonItem represents a season in a TV show

type StreamBehaviorHints

type StreamBehaviorHints struct {
	CountryWhitelist []string       `json:"countryWhitelist,omitempty"` // Array of ISO 3166-1 alpha-3 country codes in lowercase in which the stream is accessible
	NotWebReady      bool           `json:"notWebReady,omitempty"`      // Set to true if the URL does not support https or is not an MP4 file
	BingeGroup       string         `json:"bingeGroup,omitempty"`       // Identifies the stream's nature within the addon for binge watching
	ProxyHeaders     map[string]any `json:"proxyHeaders,omitempty"`     // Headers that should be used for the stream
	VideoHash        string         `json:"videoHash,omitempty"`        // Calculated OpenSubtitles hash of the video
	VideoSize        int64          `json:"videoSize,omitempty"`        // Size of the video file in bytes
	Filename         string         `json:"filename,omitempty"`         // Filename of the video file
	BingeWatch       bool           `json:"bingeWatch,omitempty"`       // Whether the stream supports binge watching
	AutoPlay         bool           `json:"autoPlay,omitempty"`         // Whether the stream should auto-play
	Proxy            bool           `json:"proxy,omitempty"`            // Whether the stream should be proxied
}

StreamBehaviorHints provides additional information about the stream

type StreamHandler

type StreamHandler func(ctx context.Context, id string, userData any) ([]StreamItem, error)

StreamHandler is the callback for stream requests for a specific type (like "movie"). The context parameter contains a meta object under the key "meta" if PutMetaInContext was set to true in the addon options. The id parameter can be for example an IMDb ID if your addon handles the "movie" type. The userData parameter depends on whether you called `RegisterUserData()` before: If not, a simple string will be passed. It's empty if the user didn't provide user data. If yes, a pointer to an object you registered will be passed. It's nil if the user didn't provide user data.

type StreamItem

type StreamItem struct {
	// One of the following is required
	URL         string `json:"url,omitempty"`         // Direct URL to a video stream - must be an MP4 through https; others supported (other video formats over http/rtmp supported if notWebReady is set)
	YoutubeID   string `json:"ytId,omitempty"`        // YouTube video ID, plays using the built-in YouTube player
	InfoHash    string `json:"infoHash,omitempty"`    // Info hash of a torrent file
	ExternalURL string `json:"externalUrl,omitempty"` // Meta Link or an external URL to the video, which should be opened in a browser

	// Optional
	Name          string              `json:"name,omitempty"`        // Name of the stream; usually used for stream quality
	Title         string              `json:"title,omitempty"`       // Description of the stream (warning: will soon be deprecated in favor of description)
	Description   string              `json:"description,omitempty"` // Description of the stream (previously stream.title)
	FileIndex     uint8               `json:"fileIdx,omitempty"`     // Index of the video file within the torrent (from infoHash); if not specified, the largest file will be selected
	Subtitles     []SubtitleItem      `json:"subtitles,omitempty"`   // Array of Subtitle objects representing subtitles for this stream
	Sources       []string            `json:"sources,omitempty"`     // Array of strings representing torrent tracker URLs and DHT network nodes
	BehaviorHints StreamBehaviorHints `json:"behaviorHints,omitzero"`
}

StreamItem represents a stream for a MetaItem. See https://github.com/Stremio/stremio-addon-sdk/blob/f6f1f2a8b627b9d4f2c62b003b251d98adadbebe/docs/api/responses/stream.md

type SubtitleHandler

type SubtitleHandler func(ctx context.Context, videoID string, userData any) ([]SubtitleItem, error)

SubtitleHandler is the callback for subtitle requests

type SubtitleItem

type SubtitleItem struct {
	ID       string `json:"id"`
	URL      string `json:"url"`      // URL to the subtitle file
	Language string `json:"language"` // ISO 639-1 language code
	Label    string `json:"label"`    // Human readable label
}

SubtitleItem represents a subtitle track for a stream

type SubtitleProvider

type SubtitleProvider interface {
	// GetSubtitles returns subtitles for a given video ID
	GetSubtitles(ctx context.Context, videoID string) ([]SubtitleItem, error)
}

SubtitleProvider represents a provider of subtitles

type VideoItem

type VideoItem struct {
	ID       string `json:"id"`
	Title    string `json:"title"`
	Released string `json:"released"` // Must be ISO 8601, e.g. "2010-12-06T05:00:00.000Z"

	// Optional
	Thumbnail string       `json:"thumbnail,omitempty"` // URL
	Streams   []StreamItem `json:"streams,omitempty"`
	Available bool         `json:"available,omitempty"`
	Episode   string       `json:"episode,omitempty"`
	Season    string       `json:"season,omitempty"`
	Trailer   string       `json:"trailer,omitempty"` // Youtube ID
	Overview  string       `json:"overview,omitempty"`
}

Directories

Path Synopsis
examples
advanced command
catalog command
complete command
stream command
pkg

Jump to

Keyboard shortcuts

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