Documentation
¶
Overview ¶
Package aiostreams is the AIOStreams module: a **dedicated stream provider** for one named upstream, as distinct from `module-stremio-addons`, which is a host for whatever addons a user pastes in.
The distinction is the reason this module exists. The addon module can source from any Stremio addon, and that is its value and its problem: the addon ecosystem is community-made, unreviewed, and unbounded, so nothing about a configured addon can be guaranteed — not its behaviour, not its reachability, not what it does with the request. An install that wants streams should not have to adopt that whole surface to get them. This module talks to exactly one upstream, AIOStreams, which is itself an aggregator: the breadth stays, and the trust decision collapses from "every addon a user might add" to "one instance, named in settings".
It fills the stream and subtitle roles and nothing else (ADR 0027, ADR 0037). It sources no metadata, contributes no search results and declares no catalogs, so it never puts a title into the library — it fills in what plays for titles some other module described (ADR 0073). An install with only this module and a metadata module is exactly the intended shape.
Its own Go module (github.com/mosaic-media/module-aiostreams) importing only the published SDK, the published SDUI contract and the standard library, and an anti-corruption layer for AIOStreams' dialect of the Stremio addon protocol (ADR 0051): the addressing, the release-text conventions and the instance URL shape stop here, and the Platform learns none of them.
Index ¶
- Constants
- type Capability
- func (c *Capability) Import(_ context.Context, _ v1.ContentService, _ v1.ImportRequest) (v1.ImportResult, error)
- func (c *Capability) Manifest() v1.Manifest
- func (c *Capability) SettingsUI(ctx context.Context, req v1.SettingsUIRequest) (v1.SettingsUIResponse, error)
- func (c *Capability) Streams(ctx context.Context, req v1.StreamRequest) (v1.StreamResponse, error)
- func (c *Capability) Subtitles(ctx context.Context, req v1.SubtitlesRequest) (v1.SubtitlesResponse, error)
- type Client
- type InstanceInfo
- type Manifest
- type ResourceDecl
- type Stream
- type Subtitle
Constants ¶
const ( // CapabilityID is the id the Platform registers this module under and a // caller names to reach its settings screen. // // It sorts before "stremio", and that has a consequence worth stating rather // than discovering: the Platform resolves stream providers in module-id order // and stops at the first that answers (ADR 0073), so on an install running // both, AIOStreams is asked first and its releases are the ones attached. That // is the intended precedence — a single curated aggregator ahead of an // open-ended addon list — but it is alphabetical accident rather than a policy // the Platform holds, exactly like the cinemeta/tmdb ordering beside it. CapabilityID = "aiostreams" )
const DefaultInstance = "https://aiostreams.elfhosted.com/stremio"
DefaultInstance is the public AIOStreams instance run by ElfHosted, and the module's default.
**It is a default host, not a working configuration**, and that distinction is the single most important fact about this module. AIOStreams resolves nothing until a profile exists: the manifest at this base declares `configurationRequired`, an empty `resources` array and no types, so a stream request against it correctly yields nothing. A user creates a profile on the instance and pastes the resulting manifest URL — which carries their profile id — into this module's settings.
Defaulting to it anyway is deliberate. It means the settings screen can offer a working "Configure" link on a fresh install rather than an empty box and a URL to go and find, and it names the instance the module is pointed at instead of leaving that implicit.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Capability ¶
type Capability struct {
// contains filtered or unexported fields
}
Capability is the AIOStreams module: a dedicated stream provider for one named upstream.
**What it deliberately does not fill is the point.** It declares no metadata, search or catalog role, so it can never put a title into the library or offer one in a search — an install adds titles through a metadata module and this fills in what plays (ADR 0073). That is a narrower surface than `module-stremio-addons`, which hosts whatever a user pastes in and therefore inherits whatever those addons do; here the trust decision is a single instance URL a user can read.
It holds an HTTP client and a manifest cache. The instance it points at is a user-managed setting handed in per invocation (ADR 0021), so one registered module serves whatever each install configured.
func New ¶
func New(httpClient *http.Client) *Capability
New builds the capability over an HTTP client (nil for a default). The instance URL is not supplied here — it arrives as settings on each invocation.
The Platform passes its own client, which routes through the dial guard that stops a user-supplied URL reaching the deployment's private network. A module that built its own would bypass it, which is precisely the seam this module sits on: the instance URL is text a user typed.
func (*Capability) Import ¶
func (c *Capability) Import(_ context.Context, _ v1.ContentService, _ v1.ImportRequest) (v1.ImportResult, error)
Import is refused, and that refusal is the module's shape rather than an unimplemented corner.
Import materialises a ref a *read* role produced (ADR 0028). This module fills no read role that produces one: it has no search, no catalogs and no metadata, so nothing can hand it a ref it made, and materialising from a stream listing would mean inventing a title out of release names. Titles come from a metadata module; this fills in what plays.
func (*Capability) Manifest ¶
func (c *Capability) Manifest() v1.Manifest
Manifest is the module's self-declaration (ADR 0027): the two source roles it fills, and the settings screen that configures them.
func (*Capability) SettingsUI ¶
func (c *Capability) SettingsUI(ctx context.Context, req v1.SettingsUIRequest) (v1.SettingsUIResponse, error)
SettingsUI renders the module's own settings screen as SDUI (RoleSettingsUI, ADR 0038): which instance is in use and whether it is actually serving, a way to open that instance's configuration page, a field to point the module at a different instance, and a way back to the default.
This role is not decoration for this module. The public default is a *host*, not a working configuration — AIOStreams serves nothing until a profile exists — so this screen is the whole path from "installed" to "resolving streams". A capability with no client path is not done, it is owed.
Every mutating control is an Invoke of the Platform's configureModule command carrying the complete new settings document, so the Platform stays the one that persists it and the module holds no state between invocations. The screen is returned as serialised UINode JSON, which is what keeps the SDK 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 (RoleStream).
It is called by the Platform's enrichment pass for content some *other* module sourced (ADR 0073), which is the only way it is ever called: a ref this module produced does not exist. So the ref carries a shared external identity, and addressOf decides whether it is one AIOStreams can speak.
Returning an empty response with no error is a normal answer here, not a degraded one. Three ordinary situations produce it — an identity that is not an IMDB id, an instance with no profile configured yet, and a title the instance's sources simply do not have — and erroring on any of them would fail a user's import over a title that was never this module's to know.
func (*Capability) Subtitles ¶
func (c *Capability) Subtitles(ctx context.Context, req v1.SubtitlesRequest) (v1.SubtitlesResponse, error)
Subtitles resolves subtitle tracks for an item (RoleSubtitles, ADR 0037). Like Streams it is a source role and the consumer is a player; it returns an empty response, no error, when the instance serves none.
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client talks to one AIOStreams instance. One instance, not a list: this module is a provider for a named upstream, and "which of several sources answered" is the question `module-stremio-addons` exists to ask.
func (*Client) Instance ¶
func (c *Client) Instance(ctx context.Context) InstanceInfo
Instance reports what the configured instance says about itself, for the settings screen. It never returns an error: every failure is a state the screen has to render, so it is carried in the value.
func (*Client) Streams ¶
Streams fetches every stream the instance offers for a content id.
All of them rather than the best one (ADR 0049): AIOStreams' whole purpose is to return a filtered, sorted *set*, and which member of it a particular client can play is not knowable here. The order is the instance's own, which is the user's configured sort — so it is carried through rather than re-ranked.
It returns nothing, and no error, when the instance declares no stream resource for the type. That is the unconfigured-instance case and it is normal, not a failure.
type InstanceInfo ¶
type InstanceInfo struct {
// Base is the normalised instance URL requests are built from.
Base string
// Reachable is false when the manifest could not be fetched — a wrong URL, an
// instance that is down, a profile that has been deleted.
Reachable bool
// Err is why it was not reachable, for a screen that has to say something
// more useful than "no".
Err error
// Configured is true when the instance serves a stream resource. An
// AIOStreams base with no profile is reachable and *not* configured, which is
// the state a fresh install is in.
Configured bool
Name string
Version string
Logo string
Description string
}
InstanceInfo is the display detail for the configured instance, for the settings screen: what the manifest says about itself, and whether it is reachable and configured at all.
type Manifest ¶
type Manifest struct {
ID string `json:"id"`
Name string `json:"name"`
Version string `json:"version"`
Description string `json:"description"`
Logo string `json:"logo"`
Resources []ResourceDecl `json:"resources"`
Types []string `json:"types"`
BehaviorHints addonBehaviorHints `json:"behaviorHints"`
}
Manifest is the subset of an addon manifest this module reads. AIOStreams is a Stremio addon by protocol, so this is the Stremio manifest shape — narrowed to what a stream and subtitle provider needs, which is why there are no catalog fields here.
type ResourceDecl ¶
ResourceDecl is one entry of a manifest's resources array. The protocol allows each entry to be either a bare string ("stream") or an object carrying its own types and id prefixes; both shapes are unmarshalled.
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 module reads. A stream is either a direct URL — which is what AIOStreams returns for a debrid or proxied result, and the common case — or a torrent identified by InfoHash.
Directories
¶
| Path | Synopsis |
|---|---|
|
cmd
|
|
|
module-aiostreams
command
Command module-aiostreams runs this module as its own process, for a Platform that hosts it out of process (ADR 0064, ADR 0077).
|
Command module-aiostreams runs this module as its own process, for a Platform that hosts it out of process (ADR 0064, ADR 0077). |