stremio

package module
v0.15.0 Latest Latest
Warning

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

Go to latest
Published: Jul 22, 2026 License: MIT Imports: 14 Imported by: 0

README

module-stremio-addons

Stremio addon-source module for the Mosaic platform — a Go client of the Stremio addon protocol, built against the Mosaic SDK.

It is an optional Mosaic module: its own Go module that imports only sdk and the standard library, compiled into a Mosaic Platform binary and invoked through the Platform's capability registry. It owns no schema; everything it does goes through the published ContentService.

What it does

Given one or more Stremio addon base URLs (configured at runtime as module settings), it consumes the addon protocol as a client and reflects content into a Mosaic library:

  • Metadata (the addon meta resource) creates the Work and its season/episode tree with an external-id source binding.
  • Streams (the addon stream resource) attach a RemoteLocation Part.

The two are independent and driven by what each addon's manifest declares: a metadata-only addon yields a library with no stream Parts, so it can enrich local media without any remote streaming. Movies and TV series are both supported.

Configuration

Addons are user-managed settings, set through the Platform at runtime — a JSON document naming the addons. Either an addon's base URL or the …/manifest.json URL you copy from Stremio works (the stremio:// install scheme is accepted too); they are normalised to the same base.

{
  "addons": [
    "https://v3-cinemeta.strem.io/manifest.json",
    "https://torrentio.strem.fun/manifest.json"
  ]
}

Metadata and streams come from different addons. A metadata addon (e.g. Cinemeta) serves the meta resource and builds the library — Works, seasons, episodes — but no playable Parts. A stream addon (e.g. Torrentio) serves the stream resource and adds RemoteLocation Parts. Configure a metadata addon to see a library at all, and add a stream addon as well if you want stream references. With only a metadata addon, an import is complete but has no streams — that is the meta-only case working as intended, not a failure.

Build

Requires a sibling checkout of sdk (a replace directive in go.mod points at ../sdk) until the SDK is published.

go build ./...
go test ./...

A note on Stremio

This is an unofficial module. It is not affiliated with, sponsored by, or endorsed by Stremio or SmartCode OOD. "Stremio" is used only nominatively, to describe the addon protocol this module is compatible with. The module contains no Stremio source code; it is an independent implementation of the publicly documented addon protocol, which is itself published under the MIT License.

License

MIT (see LICENSE). This module depends only on the Apache-2.0 Mosaic SDK; it may be compiled into a Mosaic Platform binary under the Platform's Module Linking Exception.

Documentation

Overview

Package stremio is the Stremio addon-source module: the first official optional Module, built exactly as a third party would build one. It is its own Go module (github.com/mosaic-media/module-stremio-addons) importing only the published SDK (contracts/platform/v1) and the standard library, and it is compiled into the Platform binary and invoked through the capability registry (ADR 0007, ADR 0008).

It consumes the Stremio addon protocol as a client: it points at one or more addon HTTP endpoints and, guided by each addon's manifest, uses whatever resources that addon declares. Metadata (the meta resource) creates the Work and its season/episode tree with an external-id source binding; streams (the stream resource) attach a RemoteLocation Part. The two are independent — a meta-only addon yields metadata with no Parts, so a user can enrich local media through Stremio addons without adopting remote streaming. Streams are opt-in by which addons are configured, not by the module.

It owns no schema (ADR 0012): everything it does to the graph goes through ContentService, acting as the Caller the Platform hands it (ADR 0017). Stream locations are snapshotted at import; resolving or transcoding them at play time is a separate, future concern (the Remote Media module), deliberately not here.

Index

Constants

View Source
const (
	// CapabilityID is the id the Platform registers this module under and a
	// caller names to invoke it.
	CapabilityID = "stremio"
)

Variables

This section is empty.

Functions

This section is empty.

Types

type AddonCatalogEntry

type AddonCatalogEntry struct {
	TransportURL string   `json:"transportUrl"`
	Manifest     Manifest `json:"manifest"`
}

AddonCatalogEntry is one installable addon a catalog of addons lists (ADR 0038): its transport (manifest) URL and enough of its manifest to name it.

type AddonInfo

type AddonInfo struct {
	Base         string
	Name         string
	Description  string
	Configurable bool
}

AddonInfo is the display detail for one configured addon (ADR 0038): the name, logo and description from its manifest, whether it is configurable, and the normalised base URL that identifies it. An addon whose manifest cannot be fetched still yields an entry (named by its URL) so a user can remove it.

type AppExtras added in v0.15.0

type AppExtras struct {
	Cast      []Credit `json:"cast"`
	Directors []Credit `json:"directors"`
	Writers   []Credit `json:"writers"`
}

AppExtras is the richer credit block some addons attach alongside the standard meta fields.

type Capability

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

Capability is the Stremio addon-source module (ADR 0008's capability surface, first populated). It holds only an HTTP client; the addons it sources from are the bundled default (Cinemeta) plus whatever a user adds through its settings at invocation time (ADR 0021), so metadata and search work out of the box and the same registered module serves whatever else each user configures. It owns no schema and imports no Platform internals.

func New

func New(httpClient *http.Client) *Capability

New builds the capability over an HTTP client (nil for a default). Addon URLs are not supplied here — the bundled default is always present and user addons arrive as settings on each invocation.

func (*Capability) CatalogItems

CatalogItems lists one collection's entries as virtual candidates the admin can select to publish (ADR 0028). It does not touch the object graph.

func (*Capability) Catalogs

Catalogs lists the collections the configured addons expose (RoleCatalog — the addon `catalog` resource), for the admin collection browser.

func (*Capability) Import

Import materialises the virtual item named by req.Ref — a result a search or catalog browse produced (ADR 0028) — from the configured addons into the Platform. It fetches metadata (required), searches to avoid duplicating, creates the Work with an external-id binding, builds the tree, and attaches a RemoteLocation Part wherever a stream addon serves one. Metadata alone is a complete import; streams are additive.

func (*Capability) Manifest

func (c *Capability) Manifest() v1.Manifest

Manifest is the module's self-declaration, including the provider roles it fills (ADR 0027). It sources metadata and searches and browses catalogs, and resolves streams — the four Stremio addon resources.

func (*Capability) Metadata

Metadata resolves descriptive detail for a ref (RoleMetadata — the addon `meta` resource). It is the enrichment surface: the descriptive fields, not the containment tree, which Import builds where the source's structure is known (ADR 0027).

func (*Capability) Search

Search returns virtual candidates for free text (RoleSearch — the addon `catalog/…/search` resource). No raw id: this is what makes user search in Mosaic work over source content that is not in the library (ADR 0028).

func (*Capability) SettingsUI

SettingsUI renders the module's own settings screen as SDUI (RoleSettingsUI, ADR 0038): add an addon by manifest URL, view the installed addons as cards (name, logo, description) with a way to configure or remove them, toggle the bundled Cinemeta default, and browse a grid of installable addons (the addon_catalog resource) to add without a URL. Every mutating control is an Invoke of the Platform's configureModule command with the complete new settings document, so the Platform stays the one that persists them. The screen is returned as serialised UINode JSON — the SDK stays SDUI-agnostic.

func (*Capability) Streams

func (c *Capability) Streams(ctx context.Context, req v1.StreamRequest) (v1.StreamResponse, error)

Streams resolves playable locations for a materialised item's ref (RoleStream — the addon `stream` resource). Import snapshots streams at materialise time; this exposes the same resolution as a role other flows can call. It returns an empty response, no error, when no addon serves a stream (the meta-only case).

func (*Capability) Subtitles

Subtitles resolves subtitle tracks for a materialised item's ref (RoleSubtitles — the addon `subtitles` resource, ADR 0037). Like Streams it is a source role; the consumer is a player that does not exist yet, so this is built ahead of it. It returns an empty response, no error, when no addon serves subtitles.

type CatalogDecl

type CatalogDecl struct {
	Type string `json:"type"`
	ID   string `json:"id"`
	Name string `json:"name"`
	// Extra is the modern shape: a list of accepted parameters, each named.
	Extra []ExtraDecl `json:"extra"`
	// ExtraSupported is the older shape: a bare list of accepted parameter
	// names. Both are read so search is detected whichever an addon uses.
	ExtraSupported []string `json:"extraSupported"`
}

CatalogDecl is one entry of a manifest's catalogs array — a collection the addon exposes (Popular, Top). A catalog is typed and addressed by its id; the extra declarations say which query parameters it accepts, the one that matters here being "search".

func (CatalogDecl) SupportsSearch

func (c CatalogDecl) SupportsSearch() bool

SupportsSearch reports whether the catalog accepts a search query.

type Client

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

Client is a minimal client of the Stremio addon protocol — the HTTP contract documented at stremio.github.io/stremio-addon-sdk. It talks to one or more addons and routes each request to an addon whose manifest declares the needed resource and type. A meta-only addon therefore serves metadata and a stream addon serves streams, and neither resource depends on the other.

func NewClient

func NewClient(httpClient *http.Client, addonURLs ...string) *Client

NewClient builds a client over the given addon URLs. A nil httpClient gets a default with a sane timeout. Each URL is normalised to the addon's base URL (see normaliseAddonURL) so that either the base URL or the manifest URL a user copies from Stremio works. Manifests are not fetched here; they are fetched on first use so construction stays offline.

func (*Client) AddonCatalog

func (c *Client) AddonCatalog(ctx context.Context) ([]AddonCatalogEntry, error)

AddonCatalog fetches the union of every configured addon's addon catalogs — the installable addons a user can add without pasting a manifest URL. Addons that do not serve the resource contribute nothing; a fetch that errors is skipped rather than failing the whole browse. De-duped by transport URL.

func (*Client) CatalogItems

func (c *Client) CatalogItems(ctx context.Context, typ, id string, skip int) ([]MetaPreview, error)

CatalogItems lists one catalog's entries, from the first addon whose manifest declares a catalog of that type and id. skip pages through a large catalog (0 for the first page). It returns nil, no error, when no configured addon declares the catalog.

func (*Client) Catalogs

func (c *Client) Catalogs(ctx context.Context) ([]CatalogDecl, error)

func (*Client) InstalledAddons

func (c *Client) InstalledAddons(ctx context.Context) []AddonInfo

InstalledAddons returns display detail for each configured addon, in the client's effective (deduped, default-first) order. Manifests are fetched and cached; an unreachable addon is named by its URL rather than dropped, so it stays removable.

func (*Client) Meta

func (c *Client) Meta(ctx context.Context, typ, id string) (Meta, bool, error)

Meta fetches metadata for a content id from the first configured addon whose manifest serves the meta resource for the type. It returns ok=false, no error, when no configured addon serves meta for it.

func (*Client) MetaMerged added in v0.13.0

func (c *Client) MetaMerged(ctx context.Context, typ, id string) (Meta, MetaProvenance, bool, error)

MetaMerged asks every addon that serves `meta` and combines their answers by the tiered rule above. It also reports which addon supplied each tier, so an odd-looking detail screen is an answerable question rather than a guess.

func (*Client) Search

func (c *Client) Search(ctx context.Context, query string) ([]MetaPreview, error)

Search queries every search-capable catalog across every configured addon and returns the union, de-duplicated by content id. A catalog that errors on the search query is skipped rather than failing the whole search, so one broken addon does not blank the results. It returns nil, no error, when nothing matches or no addon offers search.

func (*Client) Stream

func (c *Client) Stream(ctx context.Context, typ, id string) (Stream, bool, error)

func (*Client) Streams added in v0.10.0

func (c *Client) Streams(ctx context.Context, typ, id string) ([]Stream, error)

Stream fetches the best stream for a content id (a movie id, or an episode id of the form tt...:season:episode) from the first addon whose manifest serves the stream resource for the type. Stremio ranks streams best-first, so the first entry is taken. It returns ok=false, no error, when no configured addon serves a stream — the metadata-only case. Streams fetches every stream a configured addon offers for a content id.

Import stores all of them (ADR 0049): a candidate never expires, so keeping the set costs nothing to keep correct, and it is what lets a consumer choose a release the calling client can actually play instead of being handed whatever happened to be first. Only the resolved URL is perishable, and that is cached separately.

func (*Client) Subtitles

func (c *Client) Subtitles(ctx context.Context, typ, id string) ([]Subtitle, bool, error)

Subtitles fetches subtitle tracks for a content id (a movie id or an episode id of the form tt...:season:episode) from the first addon whose manifest serves the subtitles resource for the type. It returns ok=false, no error, when no configured addon serves subtitles (ADR 0037).

type Credit added in v0.15.0

type Credit struct {
	Name      string `json:"name"`
	Character string `json:"character"`
	Photo     string `json:"photo"`
}

Credit is one person with the two things `links` cannot express: the character they played, and a photograph of them.

type ExtraDecl

type ExtraDecl struct {
	Name string `json:"name"`
}

ExtraDecl is one accepted catalog parameter.

type Link struct {
	Name     string `json:"name"`
	Category string `json:"category"`
	URL      string `json:"url"`
}

Link is one entry of a meta's `links` array — the modern Cinemeta shape that carries cast, directors, writers and genres as categorised references.

type Manifest

type Manifest struct {
	ID          string         `json:"id"`
	Name        string         `json:"name"`
	Version     string         `json:"version"`
	Description string         `json:"description"`
	Resources   []ResourceDecl `json:"resources"`
	Types       []string       `json:"types"`
	Catalogs    []CatalogDecl  `json:"catalogs"`
	// AddonCatalogs are catalogs of *other addons* this addon exposes (the
	// `addon_catalog` resource) — how a user discovers installable addons without
	// a manifest URL (ADR 0038).
	AddonCatalogs []CatalogDecl      `json:"addonCatalogs"`
	BehaviorHints addonBehaviorHints `json:"behaviorHints"`
}

Manifest is the subset of a Stremio addon manifest this client reads.

type Meta

type Meta struct {
	ID          string   `json:"id"`
	Type        string   `json:"type"`
	Name        string   `json:"name"`
	Poster      string   `json:"poster"`
	Background  string   `json:"background"`
	Description string   `json:"description"`
	ReleaseInfo string   `json:"releaseInfo"`
	Genres      []string `json:"genres"`
	// ImdbRating is Cinemeta's rating, a string ("8.0") in its API.
	ImdbRating string `json:"imdbRating"`
	// Runtime is a display string whose format varies ("120 min").
	Runtime string `json:"runtime"`
	// Cast is the legacy top-level cast (names). Modern Cinemeta also puts cast
	// in Links with category "Cast"; both are read (see castNames).
	Cast   []string `json:"cast"`
	Links  []Link   `json:"links"`
	Videos []Video  `json:"videos"`
	// AppExtras is where an addon proxying a real metadata database puts credits
	// that the base Stremio meta shape has no room for. `links` carries cast as
	// a name and a search URL — no character, no photo — so an addon with better
	// data has nowhere to put it and puts it here instead.
	AppExtras AppExtras `json:"app_extras"`
}

Meta is the subset of a meta response this client reads. For a series, Videos lists the episodes, each carrying its season and episode number. Logo/ImdbRating/Runtime/Cast/Links back the rich detail surface (ADR 0034); Cinemeta provides them all — the module simply decoded none of them before.

type MetaPreview

type MetaPreview struct {
	ID          string `json:"id"`
	Type        string `json:"type"`
	Name        string `json:"name"`
	Poster      string `json:"poster"`
	ReleaseInfo string `json:"releaseInfo"`
}

MetaPreview is the subset of a catalog/search meta entry this client reads — the lightweight item shape a catalog returns, distinct from the full Meta a meta lookup returns. ReleaseInfo is a year ("2017") or a range ("2008-2013").

type MetaProvenance added in v0.14.0

type MetaProvenance struct {
	Identity     string
	Artwork      string
	Contributors []string
}

MetaProvenance records which addon supplied each tier of a merged record.

It costs almost nothing and turns "why does this look odd" into something answerable. Metadata assembled from several sources is exactly the kind of thing that is hard to debug after the fact without it.

type ResourceDecl

type ResourceDecl struct {
	Name       string
	Types      []string
	IDPrefixes []string
}

ResourceDecl is one entry of a manifest's resources array. Stremio allows each entry to be either a bare string ("meta") or an object carrying its own types and id prefixes; this unmarshals both shapes.

func (*ResourceDecl) UnmarshalJSON

func (r *ResourceDecl) UnmarshalJSON(b []byte) error

UnmarshalJSON accepts either a bare string or the object form.

type Stream

type Stream struct {
	Name          string        `json:"name"`
	Title         string        `json:"title"`
	Description   string        `json:"description"`
	URL           string        `json:"url"`
	InfoHash      string        `json:"infoHash"`
	FileIdx       int           `json:"fileIdx"`
	BehaviorHints behaviorHints `json:"behaviorHints"`
}

Stream is the subset of a stream object this client reads. A stream is either a direct URL or a torrent identified by InfoHash. Description/ BehaviorHints carry the release detail (quality, size) addons pack into the title, which parseStreamMeta teases back out (ADR 0037).

func (Stream) Ref

func (s Stream) Ref() string

Ref is the location reference to store for this stream: the direct URL when present, otherwise a magnet URI built from the torrent info hash. It is empty when the stream carries neither.

type Subtitle

type Subtitle struct {
	ID   string `json:"id"`
	URL  string `json:"url"`
	Lang string `json:"lang"`
}

Subtitle is the subset of a subtitles response entry this client reads (ADR 0037): a track's language and the file URL.

type Video

type Video struct {
	ID       string `json:"id"`
	Title    string `json:"title"`
	Name     string `json:"name"`
	Season   int    `json:"season"`
	Episode  int    `json:"episode"`
	Overview string `json:"overview"`
	// Thumbnail is a still image URL for the episode.
	Thumbnail string `json:"thumbnail"`
	// Released is the episode's air date (an ISO datetime in Cinemeta).
	Released string `json:"released"`
}

Video is one episode of a series' meta. Overview/Thumbnail/Released back the episode preview (ADR 0034); Cinemeta provides them on each video entry.

func (Video) EpisodeTitle

func (v Video) EpisodeTitle() string

EpisodeTitle is the video's title, falling back to its name and then a generated label, so an item always has something to show.

Jump to

Keyboard shortcuts

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