Repository files navigation

OMSS Framework

NPM VersionLicense: MITTypeScriptOMSS SpecNode.js

social preview

This is an extendable multi site scraping framework, which follows the implementation guidelines of the OMSS (Open Media Streaming Standard). It demonstrates how to build a compliant streaming media aggregation service that scrapes content from multiple providers and returns standardized responses. It handles most of the logic already for you. You just have to add the scraping logic!

Additionally, this is the worlds first AI-Enabled Streaming Framework! With built-in support for the Model Context Protocol (MCP), you can easily integrate LLMs and intelligent agents to find streaming sources using natural language queries, or even automate the management of your streaming backend using AI assistants.



🎯 What is OMSS?

OMSS is an open standard for streaming media aggregation. It provides a unified API for fetching movie and TV show streaming sources from multiple providers, with built-in proxy support, subtitle handling, and quality selection.

πŸ” What is the @omss/framework?

The @omss/framework is the official TypeScript/Node.js implementation framework that makes building OMSS-compliant backends effortless. Instead of manually implementing the standard from scratch, developers can focus solely on writing provider scraping logic while the framework handles all the boilerplate β€” routing, validation, proxy management, caching, error handling, and response formatting.

Key Features

  • βœ… Standardized API: Consistent response format across all providers
  • βœ… MCP Support: Optional Model Context Protocol endpoint for LLM integration
  • βœ… Stremio Compatibility: Designed to work seamlessly with Stremio Addons and also support Stremio Addon SDK
  • βœ… Multi-Provider Support: Aggregate sources from multiple streaming providers
  • βœ… Built-in Proxy: Automatic URL proxying with header forwarding
  • βœ… TMDB Integration: Validation against The Movie Database
  • βœ… Caching Layer: Redis or in-memory caching for performance
  • βœ… Type Safety: Full TypeScript support
  • βœ… Provider Management: Easy enable/disable, automatic discovery
  • βœ… Health Checks: Monitor provider availability
  • βœ… Refresh API: Force cache invalidation when needed

πŸ“‹ Table of Contents

πŸš€ Installation

There is a template which you can use to easily create your own streaming backend. Check it out here!This is the easiest way to create your own OMSS backend.

Prerequisites

  • Node.js 18.x or higher
  • npm or yarn
  • TMDB API Key (Get one here)
  • (Optional) Redis server for caching

Install Dependencies

# npm
npm install @omss/framework
# yarn
yarn add @omss/framework
# pnpm
pnpm add @omss/framework

πŸš€ Quick start

Minimal example using the built‑in provider and in‑memory cache:

// src/server.tsimport{OMSSServer}from'@omss/framework'import{ExampleProvider}from'./src/providers/implementations/example-provider'// Create server instanceconstserver=newOMSSServer({name: 'My OMSS Backend',version: '1.0.0',host: 'localhost',port: 3000,cache: {type: 'memory',ttl: {sources: 7200,subtitles: 7200,},},tmdb: {apiKey: process.env.TMDB_API_KEY,cacheTTL: 86400,},proxyConfig: {knownThirdPartyProxies: {'hls1.vid1.site': [/\/proxy\/(.+)$/],'madplay.site': [/\/api\/[^/]+\/proxy\?url=(.+)$/],'*': [/\/proxy\/(.+)$/,/\/m3u8-proxy\?url=(.+?)(&|$)/],},streamPatterns: [/^https?:\/\/.+\.(mp4)(\?.*)?$/],// treat direct mp4 links as streams that need proxying. You can also add custom domains that should be streamed through the proxy.},// You can override the default cors settings, by passing your own fastify cors options here. By default, it allows all origins./* cors: { origin: '*', methods: ['GET', 'OPTIONS', 'HEAD'], allowedHeaders: ['Content-Type', 'Authorization', 'Range', 'Accept'], exposedHeaders: ['Content-Length', 'Content-Type', 'Content-Range', 'Accept-Ranges'], }, */})// Register providersconstregistry=server.getRegistry()registry.register(newExampleProvider())// or use the very cool auto-discovery feature// registry.discoverProviders('./path/to/providerfolder');// Note: this is relative to *where you start the server*.// before starting the server, you can also modify any fastify instance settings, by getting the instance via server.getFastifyInstance() and calling any of its methods. For example, to add a custom route:// Start serverawaitserver.start()

.env:

# Server ConfigurationPORT=3000# Port number for the serverHOST=0.0.0.0# Use 'localhost' to restrict to local accessNODE_ENV=development# 'development' | 'production'# TMDB ConfigurationTMDB_API_KEY=your_tmdb_api_key_hereTMDB_CACHE_TTL=86400# Cache ConfigurationCACHE_TYPE=memory# 'memory' | 'redis'# Redis Configuration (if using Redis cache)REDIS_HOST=localhost# default Redis hostREDIS_PORT=6379# default Redis portREDIS_PASSWORD=# Redis password if required

Run in dev:

npm run dev

And then it should work!

βš™οΈ Configuration

Server Configuration Options

interfaceOMSSConfig{// Required: Server identificationname: string// Your server nameversion: string// OMSS Spec version// Optional: Network settingshost?: string// Default: 'localhost'port?: number// Default: 3000publicUrl?: string// For reverse proxy setups// Optional: Cache configurationcache?: {type: 'memory'|'redis'ttl: {sources: numbersubtitles: number}redis?: {host: stringport: numberpassword?: string}}// Required: TMDB configurationtmdb?: {apiKey?: string// Can also use TMDB_API_KEY env varcacheTTL?: number// Default: 86400 (24 hours)}// Proxy configurationproxyConfig?: {knownThirdPartyProxies: Record<string,RegExp[]>// for this, see the documentation in docs/third-party-pattern-config.mdstreamPatterns: RegExp[]// Optional: Custom patterns to identify streaming URLs that need proxying}// Optional: CORS configuration (overrides default)cors?: {origin: stringmethods: string[]allowedHeaders: string[]exposedHeaders: string[]}}

Example Configurations

Development

constserver=newOMSSServer({name: 'OMSS Dev Server',version: '1.0.0',host: 'localhost',port: 3000,cache: {type: 'memory',ttl: {sources: 7200,subtitles: 7200,},},tmdb: {apiKey: process.env.TMDB_API_KEY,cacheTTL: 86400,},proxyConfig: {knownThirdPartyProxies: {},// for this, see the documentation in docs/third-party-pattern-config.mdstreamPatterns: [/^https?:\/\/.+\.(mp4)(\?.*)?$/],// treat direct mp4 links as streams that need proxying. You can also add custom domains that should be streamed through the proxy.},})

Production with Redis

constserver=newOMSSServer({name: 'OMSS Production',version: '1.0.0',host: '0.0.0.0',port: 3000,publicUrl: 'https://api.mystream.com',cache: {type: 'redis',ttl: {sources: 7200,subtitles: 7200,},redis: {host: process.env.REDIS_HOST||'localhost',port: parseInt(process.env.REDIS_PORT||'6379'),password: process.env.REDIS_PASSWORD,},},tmdb: {apiKey: process.env.TMDB_API_KEY,cacheTTL: 86400,},proxyConfig: {knownThirdPartyProxies: {},// for this, see the documentation in docs/third-party-pattern-config.mdstreamPatterns: [/^https?:\/\/.+\.(mp4)(\?.*)?$/],// treat direct mp4 links as streams that need proxying. You can also add custom domains that should be streamed through the proxy.},cors: {origin: 'https://myapp.com',methods: ['GET','OPTIONS'],allowedHeaders: ['Content-Type','Authorization'],exposedHeaders: ['Content-Length','Content-Type'],},})

Behind Reverse Proxy

constserver=newOMSSServer({name: 'OMSS API',version: '1.0.0',host: '0.0.0.0',port: 3000,// This is the public URL clients will usepublicUrl: 'https://myapp.com/api',cache: {type: 'redis',redis: {host: 'redis.internal',port: 6379,},},tmdb: {apiKey: process.env.TMDB_API_KEY,cacheTTL: 86400,},proxyConfig: {knownThirdPartyProxies: {},// for this, see the documentation in docs/third-party-pattern-config.mdstreamPatterns: [/^https?:\/\/.+\.(mp4)(\?.*)?$/],// treat direct mp4 links as streams that need proxying. You can also add custom domains that should be streamed through the proxy.},cors: {origin: 'https://myapp.com',methods: ['GET','OPTIONS'],allowedHeaders: ['Content-Type','Authorization'],exposedHeaders: ['Content-Length','Content-Type'],},})

πŸ”Œ Creating Custom Providers

See the detailed Provider Creation Guide for a complete walkthrough.

Quick Start with Auto-Discovery

The easiest way to add a new provider:

  1. Create a directory for all of your provider files

    touch src/providers/implementations/my-provider.ts
  2. Implement the BaseProvider class (see example below) in each file.

  3. In the Setup, use the discoverProviders method of the ProviderRegistry to load all providers from that directory:

    constregistry=server.getRegistry()registry.discoverProviders('./src/providers/implementations')// relative to where you start the server from
  4. That's it! The provider will be automatically discovered and registered when you start the server!

No imports, no manual registration needed!

Minimal Provider Example

import{BaseProvider}from'./src/providers/base-provider'import{ProviderCapabilities,ProviderMediaObject,ProviderResult}from'./src/core/types'exportclassMyProviderextendsBaseProvider{// Required: Provider identificationreadonlyid='my-provider'readonlyname='My Provider'readonlyenabled=true// Required: Base URL and headersreadonlyBASE_URL='https://provider.example.com'readonlyHEADERS={'User-Agent': 'Mozilla/5.0',Referer: 'https://provider.example.com',}// Required: Declare what this provider supportsreadonlycapabilities: ProviderCapabilities={supportedContentTypes: ['movies','tv'],}// Implement movie scrapingasyncgetMovieSources(media: ProviderMediaObject): Promise<ProviderResult>{this.console.log('Fetching movie sources',media)try{// Your scraping logic hereconststreamUrl=awaitthis.scrapeMovieUrl(media.tmdbId)// this is just some example functionreturn{sources: [{url: this.createProxyUrl(streamUrl,this.HEADERS),type: 'hls',quality: '1080p',audioTracks: [{language: 'en',label: 'English',},],provider: {id: this.id,name: this.name,},},],subtitles: [],diagnostics: [],}}catch(error){this.console.error('Failed to fetch sources',error,media)return{sources: [],subtitles: [],diagnostics: [{code: 'PROVIDER_ERROR',message: `${this.name} failed`,field: '',severity: 'error',},],}}}// Implement TV scrapingasyncgetTVSources(media: ProviderMediaObject): Promise<ProviderResult>{// Similar to getMovieSources but for TVreturn{sources: [],subtitles: [],diagnostics: []}}// Optional: Custom health checkasynchealthCheck(): Promise<boolean>{try{constresponse=awaitfetch(this.BASE_URL)returnresponse.ok}catch{returnfalse}}}

Full Provider Example

See the detailed Provider Creation Guide for a complete walkthrough.

To test a singulare Provider without setting up the whole server, you can use the following file, which will run the provider in isolation and allow you to test its functionality, without debugging the whole server.

import{ProviderMediaObject}from"@omss/framework"import{ExampleProvider}from"./example.js"constprov=newExampleProvider()constmediaObj: ProviderMediaObject={title: "The Dark Knight",tmdbId: "155",releaseYear: "2008",type: "movie",imdbId: "tt0468569"}constresp=awaitprov.getMovieSources(mediaObj)console.log(resp)

🧩 MCP Endpoints

The Model Context Protocol (MCP) is an optional JSON-RPC-like API that allows LLMs and other intelligent agents to interact with your OMSS server in a structured way. This can be useful for advanced integrations, such as allowing users to ask an AI assistant to find streaming sources for a movie or TV show.

When enabled, the MCP endpoint is exposed at /mcp (configurable) and accepts POST requests with a JSON body containing the method and parameters. The framework currently supports the following MCP method:

  • omss_get_sources: Fetches streaming sources for a movie or TV episode by TMDB ID. Parameters are the same as the regular API endpoints, but wrapped in an MCP request.

πŸ“‘ API Endpoints

GET /v1/movies/:tmdbId

Fetch streaming sources for a movie.

Parameters:

  • tmdbId (path): TMDB movie ID

Response:

{
"responseId": "uuid-v4",
"expiresAt": "2026-01-18T20:00:00.000Z",
"sources": [
{
"url": "/v1/proxy?data=...",
"type": "hls",
"quality": "1080p",
"audioTracks": [
{
"language": "en",
"label": "English"
}
],
"provider": {
"id": "vixsrc",
"name": "VixSrc"
}
}
],
"subtitles": [],
"diagnostics": []
}

GET /v1/tv/:tmdbId/seasons/:season/episodes/:episode

Fetch streaming sources for a TV episode.

Parameters:

  • tmdbId (path): TMDB series ID
  • season (path): Season number (0-99)
  • episode (path): Episode number (1-9999)

Response: Same structure as movies endpoint

GET /v1/proxy

Proxy streaming URLs with custom headers.

Query Parameters:

  • data (required): URL-encoded JSON containing:
    {
    "url": "https://stream.example.com/video.m3u8",
    "headers": {
    "Referer": "https://provider.example.com"
    }
    }

GET /v1/refresh/:responseId

Force refresh cached sources.

Parameters:

  • responseId (path): Response ID from previous request

GET /v1/health

Health check endpoint.

Response:

{
"status": "healthy",
"version": "1.0.0",
"providers": {
"total": 1,
"enabled": 1
}
}

🌍 Environment Variables

# Server ConfigurationPORT=3000# Port number for the serverHOST=0.0.0.0# Use 'localhost' to restrict to local accessNODE_ENV=development# 'development' | 'production'MCP_ENABLED=false# 'true' | 'false'# TMDB ConfigurationTMDB_API_KEY=your_tmdb_api_key_hereTMDB_CACHE_TTL=86400# Cache ConfigurationCACHE_TYPE=memory# 'memory' | 'redis'# Redis Configuration (if using Redis cache)REDIS_HOST=localhost# default Redis hostREDIS_PORT=6379# default Redis portREDIS_PASSWORD=# Redis password if required

πŸ“Ί Stremio Compatibility

Although the original OMSS standard was not specifically designed for Stremio, this framework is fully compatible with Stremio. In both ways:

  1. You can use this framework to build a Stremio Addon. To enable the Stremio Addon SDK, simply set the stremioAddon option to true in the server configuration. This will automatically add the required endpoints (/stremio/manifest.json) and response formatting to work seamlessly with Stremio.

  2. You can bind other Stremio Addon's directly to this framework. Since all Stremio Addons follow a standardized API, you can just pass the manifest URL of any Stremio Addon to the stremioAddons configuration option, and the framework will automatically fetch the manifest, extract the sources and bind them to your server. This allows you to easily aggregate sources from existing Stremio Addons alongside your custom providers, and expose them all through a single unified API.

πŸ—οΈ Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ OMSS Server β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ Controllers β”‚
β”‚ β”œβ”€β”€ ContentController (Movies/TV endpoints) β”‚
β”‚ β”œβ”€β”€ ProxyController (Streaming proxy) β”‚
β”‚ └── HealthController (Health checks) β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ Services β”‚
β”‚ β”œβ”€β”€ SourceService (Aggregates provider results) β”‚
β”‚ β”œβ”€β”€ TMDBService (Validates against TMDB) β”‚
β”‚ └── ProxyService (Handles URL proxying) β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ Provider Registry β”‚
β”‚ └── Manages all registered providers β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ Providers (Implement BaseProvider) β”‚
β”‚ β”œβ”€β”€ YourCustomProvider β”‚
β”‚ └── ... β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ Cache Layer β”‚
β”‚ β”œβ”€β”€ MemoryCache (Development) β”‚
β”‚ └── RedisCache (Production) β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

βœ… OMSS Compliance

This implementation follows the OMSS Standard:

  • βœ… Standardized Response Format: All responses follow OMSS schema
  • βœ… TMDB Validation: All requests validated against TMDB
  • βœ… Proxy Support: Required for all streaming URLs
  • βœ… Error Handling: OMSS-compliant error responses
  • βœ… Source Identification: Unique IDs for all sources
  • βœ… Audio Track Support: Multiple audio tracks per source
  • βœ… Subtitle Support: VTT/SRT subtitle formats
  • βœ… Quality Indicators: Resolution-based quality tags
  • βœ… Provider Attribution: Source provider identification
  • βœ… Diagnostics: Detailed error/warning information

πŸ“š Additional Resources

🀝 Contributing

Contributions are welcome! Please read our contributing guidelines before submitting PRs.

πŸ“„ License

MIT License - see LICENSE file for details.

πŸ™ Acknowledgments

  • All maintainers
  • OMSS standard contributors

About

πŸ› οΈ Official TypeScript framework for building OMSS-compliant streaming backends

Resources

Code of conduct

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

Repository files navigation

OMSS Framework

NPM VersionLicense: MITTypeScriptOMSS SpecNode.js

social preview

This is an extendable multi site scraping framework, which follows the implementation guidelines of the OMSS (Open Media Streaming Standard). It demonstrates how to build a compliant streaming media aggregation service that scrapes content from multiple providers and returns standardized responses. It handles most of the logic already for you. You just have to add the scraping logic!

Additionally, this is the worlds first AI-Enabled Streaming Framework! With built-in support for the Model Context Protocol (MCP), you can easily integrate LLMs and intelligent agents to find streaming sources using natural language queries, or even automate the management of your streaming backend using AI assistants.



🎯 What is OMSS?

OMSS is an open standard for streaming media aggregation. It provides a unified API for fetching movie and TV show streaming sources from multiple providers, with built-in proxy support, subtitle handling, and quality selection.

πŸ” What is the @omss/framework?

The @omss/framework is the official TypeScript/Node.js implementation framework that makes building OMSS-compliant backends effortless. Instead of manually implementing the standard from scratch, developers can focus solely on writing provider scraping logic while the framework handles all the boilerplate β€” routing, validation, proxy management, caching, error handling, and response formatting.

Key Features

  • βœ… Standardized API: Consistent response format across all providers
  • βœ… MCP Support: Optional Model Context Protocol endpoint for LLM integration
  • βœ… Stremio Compatibility: Designed to work seamlessly with Stremio Addons and also support Stremio Addon SDK
  • βœ… Multi-Provider Support: Aggregate sources from multiple streaming providers
  • βœ… Built-in Proxy: Automatic URL proxying with header forwarding
  • βœ… TMDB Integration: Validation against The Movie Database
  • βœ… Caching Layer: Redis or in-memory caching for performance
  • βœ… Type Safety: Full TypeScript support
  • βœ… Provider Management: Easy enable/disable, automatic discovery
  • βœ… Health Checks: Monitor provider availability
  • βœ… Refresh API: Force cache invalidation when needed

πŸ“‹ Table of Contents

πŸš€ Installation

There is a template which you can use to easily create your own streaming backend. Check it out here!This is the easiest way to create your own OMSS backend.

Prerequisites

  • Node.js 18.x or higher
  • npm or yarn
  • TMDB API Key (Get one here)
  • (Optional) Redis server for caching

Install Dependencies

# npm
npm install @omss/framework
# yarn
yarn add @omss/framework
# pnpm
pnpm add @omss/framework

πŸš€ Quick start

Minimal example using the built‑in provider and in‑memory cache:

// src/server.tsimport{OMSSServer}from'@omss/framework'import{ExampleProvider}from'./src/providers/implementations/example-provider'// Create server instanceconstserver=newOMSSServer({name: 'My OMSS Backend',version: '1.0.0',host: 'localhost',port: 3000,cache: {type: 'memory',ttl: {sources: 7200,subtitles: 7200,},},tmdb: {apiKey: process.env.TMDB_API_KEY,cacheTTL: 86400,},proxyConfig: {knownThirdPartyProxies: {'hls1.vid1.site': [/\/proxy\/(.+)$/],'madplay.site': [/\/api\/[^/]+\/proxy\?url=(.+)$/],'*': [/\/proxy\/(.+)$/,/\/m3u8-proxy\?url=(.+?)(&|$)/],},streamPatterns: [/^https?:\/\/.+\.(mp4)(\?.*)?$/],// treat direct mp4 links as streams that need proxying. You can also add custom domains that should be streamed through the proxy.},// You can override the default cors settings, by passing your own fastify cors options here. By default, it allows all origins./* cors: { origin: '*', methods: ['GET', 'OPTIONS', 'HEAD'], allowedHeaders: ['Content-Type', 'Authorization', 'Range', 'Accept'], exposedHeaders: ['Content-Length', 'Content-Type', 'Content-Range', 'Accept-Ranges'], }, */})// Register providersconstregistry=server.getRegistry()registry.register(newExampleProvider())// or use the very cool auto-discovery feature// registry.discoverProviders('./path/to/providerfolder');// Note: this is relative to *where you start the server*.// before starting the server, you can also modify any fastify instance settings, by getting the instance via server.getFastifyInstance() and calling any of its methods. For example, to add a custom route:// Start serverawaitserver.start()

.env:

# Server ConfigurationPORT=3000# Port number for the serverHOST=0.0.0.0# Use 'localhost' to restrict to local accessNODE_ENV=development# 'development' | 'production'# TMDB ConfigurationTMDB_API_KEY=your_tmdb_api_key_hereTMDB_CACHE_TTL=86400# Cache ConfigurationCACHE_TYPE=memory# 'memory' | 'redis'# Redis Configuration (if using Redis cache)REDIS_HOST=localhost# default Redis hostREDIS_PORT=6379# default Redis portREDIS_PASSWORD=# Redis password if required

Run in dev:

npm run dev

And then it should work!

βš™οΈ Configuration

Server Configuration Options

interfaceOMSSConfig{// Required: Server identificationname: string// Your server nameversion: string// OMSS Spec version// Optional: Network settingshost?: string// Default: 'localhost'port?: number// Default: 3000publicUrl?: string// For reverse proxy setups// Optional: Cache configurationcache?: {type: 'memory'|'redis'ttl: {sources: numbersubtitles: number}redis?: {host: stringport: numberpassword?: string}}// Required: TMDB configurationtmdb?: {apiKey?: string// Can also use TMDB_API_KEY env varcacheTTL?: number// Default: 86400 (24 hours)}// Proxy configurationproxyConfig?: {knownThirdPartyProxies: Record<string,RegExp[]>// for this, see the documentation in docs/third-party-pattern-config.mdstreamPatterns: RegExp[]// Optional: Custom patterns to identify streaming URLs that need proxying}// Optional: CORS configuration (overrides default)cors?: {origin: stringmethods: string[]allowedHeaders: string[]exposedHeaders: string[]}}

Example Configurations

Development

constserver=newOMSSServer({name: 'OMSS Dev Server',version: '1.0.0',host: 'localhost',port: 3000,cache: {type: 'memory',ttl: {sources: 7200,subtitles: 7200,},},tmdb: {apiKey: process.env.TMDB_API_KEY,cacheTTL: 86400,},proxyConfig: {knownThirdPartyProxies: {},// for this, see the documentation in docs/third-party-pattern-config.mdstreamPatterns: [/^https?:\/\/.+\.(mp4)(\?.*)?$/],// treat direct mp4 links as streams that need proxying. You can also add custom domains that should be streamed through the proxy.},})

Production with Redis

constserver=newOMSSServer({name: 'OMSS Production',version: '1.0.0',host: '0.0.0.0',port: 3000,publicUrl: 'https://api.mystream.com',cache: {type: 'redis',ttl: {sources: 7200,subtitles: 7200,},redis: {host: process.env.REDIS_HOST||'localhost',port: parseInt(process.env.REDIS_PORT||'6379'),password: process.env.REDIS_PASSWORD,},},tmdb: {apiKey: process.env.TMDB_API_KEY,cacheTTL: 86400,},proxyConfig: {knownThirdPartyProxies: {},// for this, see the documentation in docs/third-party-pattern-config.mdstreamPatterns: [/^https?:\/\/.+\.(mp4)(\?.*)?$/],// treat direct mp4 links as streams that need proxying. You can also add custom domains that should be streamed through the proxy.},cors: {origin: 'https://myapp.com',methods: ['GET','OPTIONS'],allowedHeaders: ['Content-Type','Authorization'],exposedHeaders: ['Content-Length','Content-Type'],},})

Behind Reverse Proxy

constserver=newOMSSServer({name: 'OMSS API',version: '1.0.0',host: '0.0.0.0',port: 3000,// This is the public URL clients will usepublicUrl: 'https://myapp.com/api',cache: {type: 'redis',redis: {host: 'redis.internal',port: 6379,},},tmdb: {apiKey: process.env.TMDB_API_KEY,cacheTTL: 86400,},proxyConfig: {knownThirdPartyProxies: {},// for this, see the documentation in docs/third-party-pattern-config.mdstreamPatterns: [/^https?:\/\/.+\.(mp4)(\?.*)?$/],// treat direct mp4 links as streams that need proxying. You can also add custom domains that should be streamed through the proxy.},cors: {origin: 'https://myapp.com',methods: ['GET','OPTIONS'],allowedHeaders: ['Content-Type','Authorization'],exposedHeaders: ['Content-Length','Content-Type'],},})

πŸ”Œ Creating Custom Providers

See the detailed Provider Creation Guide for a complete walkthrough.

Quick Start with Auto-Discovery

The easiest way to add a new provider:

  1. Create a directory for all of your provider files

    touch src/providers/implementations/my-provider.ts
  2. Implement the BaseProvider class (see example below) in each file.

  3. In the Setup, use the discoverProviders method of the ProviderRegistry to load all providers from that directory:

    constregistry=server.getRegistry()registry.discoverProviders('./src/providers/implementations')// relative to where you start the server from
  4. That's it! The provider will be automatically discovered and registered when you start the server!

No imports, no manual registration needed!

Minimal Provider Example

import{BaseProvider}from'./src/providers/base-provider'import{ProviderCapabilities,ProviderMediaObject,ProviderResult}from'./src/core/types'exportclassMyProviderextendsBaseProvider{// Required: Provider identificationreadonlyid='my-provider'readonlyname='My Provider'readonlyenabled=true// Required: Base URL and headersreadonlyBASE_URL='https://provider.example.com'readonlyHEADERS={'User-Agent': 'Mozilla/5.0',Referer: 'https://provider.example.com',}// Required: Declare what this provider supportsreadonlycapabilities: ProviderCapabilities={supportedContentTypes: ['movies','tv'],}// Implement movie scrapingasyncgetMovieSources(media: ProviderMediaObject): Promise<ProviderResult>{this.console.log('Fetching movie sources',media)try{// Your scraping logic hereconststreamUrl=awaitthis.scrapeMovieUrl(media.tmdbId)// this is just some example functionreturn{sources: [{url: this.createProxyUrl(streamUrl,this.HEADERS),type: 'hls',quality: '1080p',audioTracks: [{language: 'en',label: 'English',},],provider: {id: this.id,name: this.name,},},],subtitles: [],diagnostics: [],}}catch(error){this.console.error('Failed to fetch sources',error,media)return{sources: [],subtitles: [],diagnostics: [{code: 'PROVIDER_ERROR',message: `${this.name} failed`,field: '',severity: 'error',},],}}}// Implement TV scrapingasyncgetTVSources(media: ProviderMediaObject): Promise<ProviderResult>{// Similar to getMovieSources but for TVreturn{sources: [],subtitles: [],diagnostics: []}}// Optional: Custom health checkasynchealthCheck(): Promise<boolean>{try{constresponse=awaitfetch(this.BASE_URL)returnresponse.ok}catch{returnfalse}}}

Full Provider Example

See the detailed Provider Creation Guide for a complete walkthrough.

To test a singulare Provider without setting up the whole server, you can use the following file, which will run the provider in isolation and allow you to test its functionality, without debugging the whole server.

import{ProviderMediaObject}from"@omss/framework"import{ExampleProvider}from"./example.js"constprov=newExampleProvider()constmediaObj: ProviderMediaObject={title: "The Dark Knight",tmdbId: "155",releaseYear: "2008",type: "movie",imdbId: "tt0468569"}constresp=awaitprov.getMovieSources(mediaObj)console.log(resp)

🧩 MCP Endpoints

The Model Context Protocol (MCP) is an optional JSON-RPC-like API that allows LLMs and other intelligent agents to interact with your OMSS server in a structured way. This can be useful for advanced integrations, such as allowing users to ask an AI assistant to find streaming sources for a movie or TV show.

When enabled, the MCP endpoint is exposed at /mcp (configurable) and accepts POST requests with a JSON body containing the method and parameters. The framework currently supports the following MCP method:

  • omss_get_sources: Fetches streaming sources for a movie or TV episode by TMDB ID. Parameters are the same as the regular API endpoints, but wrapped in an MCP request.

πŸ“‘ API Endpoints

GET /v1/movies/:tmdbId

Fetch streaming sources for a movie.

Parameters:

  • tmdbId (path): TMDB movie ID

Response:

{
"responseId": "uuid-v4",
"expiresAt": "2026-01-18T20:00:00.000Z",
"sources": [
{
"url": "/v1/proxy?data=...",
"type": "hls",
"quality": "1080p",
"audioTracks": [
{
"language": "en",
"label": "English"
}
],
"provider": {
"id": "vixsrc",
"name": "VixSrc"
}
}
],
"subtitles": [],
"diagnostics": []
}

GET /v1/tv/:tmdbId/seasons/:season/episodes/:episode

Fetch streaming sources for a TV episode.

Parameters:

  • tmdbId (path): TMDB series ID
  • season (path): Season number (0-99)
  • episode (path): Episode number (1-9999)

Response: Same structure as movies endpoint

GET /v1/proxy

Proxy streaming URLs with custom headers.

Query Parameters:

  • data (required): URL-encoded JSON containing:
    {
    "url": "https://stream.example.com/video.m3u8",
    "headers": {
    "Referer": "https://provider.example.com"
    }
    }

GET /v1/refresh/:responseId

Force refresh cached sources.

Parameters:

  • responseId (path): Response ID from previous request

GET /v1/health

Health check endpoint.

Response:

{
"status": "healthy",
"version": "1.0.0",
"providers": {
"total": 1,
"enabled": 1
}
}

🌍 Environment Variables

# Server ConfigurationPORT=3000# Port number for the serverHOST=0.0.0.0# Use 'localhost' to restrict to local accessNODE_ENV=development# 'development' | 'production'MCP_ENABLED=false# 'true' | 'false'# TMDB ConfigurationTMDB_API_KEY=your_tmdb_api_key_hereTMDB_CACHE_TTL=86400# Cache ConfigurationCACHE_TYPE=memory# 'memory' | 'redis'# Redis Configuration (if using Redis cache)REDIS_HOST=localhost# default Redis hostREDIS_PORT=6379# default Redis portREDIS_PASSWORD=# Redis password if required

πŸ“Ί Stremio Compatibility

Although the original OMSS standard was not specifically designed for Stremio, this framework is fully compatible with Stremio. In both ways:

  1. You can use this framework to build a Stremio Addon. To enable the Stremio Addon SDK, simply set the stremioAddon option to true in the server configuration. This will automatically add the required endpoints (/stremio/manifest.json) and response formatting to work seamlessly with Stremio.

  2. You can bind other Stremio Addon's directly to this framework. Since all Stremio Addons follow a standardized API, you can just pass the manifest URL of any Stremio Addon to the stremioAddons configuration option, and the framework will automatically fetch the manifest, extract the sources and bind them to your server. This allows you to easily aggregate sources from existing Stremio Addons alongside your custom providers, and expose them all through a single unified API.

πŸ—οΈ Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ OMSS Server β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ Controllers β”‚
β”‚ β”œβ”€β”€ ContentController (Movies/TV endpoints) β”‚
β”‚ β”œβ”€β”€ ProxyController (Streaming proxy) β”‚
β”‚ └── HealthController (Health checks) β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ Services β”‚
β”‚ β”œβ”€β”€ SourceService (Aggregates provider results) β”‚
β”‚ β”œβ”€β”€ TMDBService (Validates against TMDB) β”‚
β”‚ └── ProxyService (Handles URL proxying) β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ Provider Registry β”‚
β”‚ └── Manages all registered providers β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ Providers (Implement BaseProvider) β”‚
β”‚ β”œβ”€β”€ YourCustomProvider β”‚
β”‚ └── ... β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ Cache Layer β”‚
β”‚ β”œβ”€β”€ MemoryCache (Development) β”‚
β”‚ └── RedisCache (Production) β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

βœ… OMSS Compliance

This implementation follows the OMSS Standard:

  • βœ… Standardized Response Format: All responses follow OMSS schema
  • βœ… TMDB Validation: All requests validated against TMDB
  • βœ… Proxy Support: Required for all streaming URLs
  • βœ… Error Handling: OMSS-compliant error responses
  • βœ… Source Identification: Unique IDs for all sources
  • βœ… Audio Track Support: Multiple audio tracks per source
  • βœ… Subtitle Support: VTT/SRT subtitle formats
  • βœ… Quality Indicators: Resolution-based quality tags
  • βœ… Provider Attribution: Source provider identification
  • βœ… Diagnostics: Detailed error/warning information

πŸ“š Additional Resources

🀝 Contributing

Contributions are welcome! Please read our contributing guidelines before submitting PRs.

πŸ“„ License

MIT License - see LICENSE file for details.

πŸ™ Acknowledgments

  • All maintainers
  • OMSS standard contributors

About

πŸ› οΈ Official TypeScript framework for building OMSS-compliant streaming backends

Resources

Code of conduct

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

OMSS Framework

NPM VersionLicense: MITTypeScriptOMSS SpecNode.js

social preview

This is an extendable multi site scraping framework, which follows the implementation guidelines of the OMSS (Open Media Streaming Standard). It demonstrates how to build a compliant streaming media aggregation service that scrapes content from multiple providers and returns standardized responses. It handles most of the logic already for you. You just have to add the scraping logic!

Additionally, this is the worlds first AI-Enabled Streaming Framework! With built-in support for the Model Context Protocol (MCP), you can easily integrate LLMs and intelligent agents to find streaming sources using natural language queries, or even automate the management of your streaming backend using AI assistants.



🎯 What is OMSS?

OMSS is an open standard for streaming media aggregation. It provides a unified API for fetching movie and TV show streaming sources from multiple providers, with built-in proxy support, subtitle handling, and quality selection.

πŸ” What is the @omss/framework?

The @omss/framework is the official TypeScript/Node.js implementation framework that makes building OMSS-compliant backends effortless. Instead of manually implementing the standard from scratch, developers can focus solely on writing provider scraping logic while the framework handles all the boilerplate β€” routing, validation, proxy management, caching, error handling, and response formatting.

Key Features

  • βœ… Standardized API: Consistent response format across all providers
  • βœ… MCP Support: Optional Model Context Protocol endpoint for LLM integration
  • βœ… Stremio Compatibility: Designed to work seamlessly with Stremio Addons and also support Stremio Addon SDK
  • βœ… Multi-Provider Support: Aggregate sources from multiple streaming providers
  • βœ… Built-in Proxy: Automatic URL proxying with header forwarding
  • βœ… TMDB Integration: Validation against The Movie Database
  • βœ… Caching Layer: Redis or in-memory caching for performance
  • βœ… Type Safety: Full TypeScript support
  • βœ… Provider Management: Easy enable/disable, automatic discovery
  • βœ… Health Checks: Monitor provider availability
  • βœ… Refresh API: Force cache invalidation when needed

πŸ“‹ Table of Contents

πŸš€ Installation

There is a template which you can use to easily create your own streaming backend. Check it out here!This is the easiest way to create your own OMSS backend.

Prerequisites

  • Node.js 18.x or higher
  • npm or yarn
  • TMDB API Key (Get one here)
  • (Optional) Redis server for caching

Install Dependencies

# npm
npm install @omss/framework
# yarn
yarn add @omss/framework
# pnpm
pnpm add @omss/framework

πŸš€ Quick start

Minimal example using the built‑in provider and in‑memory cache:

// src/server.tsimport{OMSSServer}from'@omss/framework'import{ExampleProvider}from'./src/providers/implementations/example-provider'// Create server instanceconstserver=newOMSSServer({name: 'My OMSS Backend',version: '1.0.0',host: 'localhost',port: 3000,cache: {type: 'memory',ttl: {sources: 7200,subtitles: 7200,},},tmdb: {apiKey: process.env.TMDB_API_KEY,cacheTTL: 86400,},proxyConfig: {knownThirdPartyProxies: {'hls1.vid1.site': [/\/proxy\/(.+)$/],'madplay.site': [/\/api\/[^/]+\/proxy\?url=(.+)$/],'*': [/\/proxy\/(.+)$/,/\/m3u8-proxy\?url=(.+?)(&|$)/],},streamPatterns: [/^https?:\/\/.+\.(mp4)(\?.*)?$/],// treat direct mp4 links as streams that need proxying. You can also add custom domains that should be streamed through the proxy.},// You can override the default cors settings, by passing your own fastify cors options here. By default, it allows all origins./* cors: { origin: '*', methods: ['GET', 'OPTIONS', 'HEAD'], allowedHeaders: ['Content-Type', 'Authorization', 'Range', 'Accept'], exposedHeaders: ['Content-Length', 'Content-Type', 'Content-Range', 'Accept-Ranges'], }, */})// Register providersconstregistry=server.getRegistry()registry.register(newExampleProvider())// or use the very cool auto-discovery feature// registry.discoverProviders('./path/to/providerfolder');// Note: this is relative to *where you start the server*.// before starting the server, you can also modify any fastify instance settings, by getting the instance via server.getFastifyInstance() and calling any of its methods. For example, to add a custom route:// Start serverawaitserver.start()

.env:

# Server ConfigurationPORT=3000# Port number for the serverHOST=0.0.0.0# Use 'localhost' to restrict to local accessNODE_ENV=development# 'development' | 'production'# TMDB ConfigurationTMDB_API_KEY=your_tmdb_api_key_hereTMDB_CACHE_TTL=86400# Cache ConfigurationCACHE_TYPE=memory# 'memory' | 'redis'# Redis Configuration (if using Redis cache)REDIS_HOST=localhost# default Redis hostREDIS_PORT=6379# default Redis portREDIS_PASSWORD=# Redis password if required

Run in dev:

npm run dev

And then it should work!

βš™οΈ Configuration

Server Configuration Options

interfaceOMSSConfig{// Required: Server identificationname: string// Your server nameversion: string// OMSS Spec version// Optional: Network settingshost?: string// Default: 'localhost'port?: number// Default: 3000publicUrl?: string// For reverse proxy setups// Optional: Cache configurationcache?: {type: 'memory'|'redis'ttl: {sources: numbersubtitles: number}redis?: {host: stringport: numberpassword?: string}}// Required: TMDB configurationtmdb?: {apiKey?: string// Can also use TMDB_API_KEY env varcacheTTL?: number// Default: 86400 (24 hours)}// Proxy configurationproxyConfig?: {knownThirdPartyProxies: Record<string,RegExp[]>// for this, see the documentation in docs/third-party-pattern-config.mdstreamPatterns: RegExp[]// Optional: Custom patterns to identify streaming URLs that need proxying}// Optional: CORS configuration (overrides default)cors?: {origin: stringmethods: string[]allowedHeaders: string[]exposedHeaders: string[]}}

Example Configurations

Development

constserver=newOMSSServer({name: 'OMSS Dev Server',version: '1.0.0',host: 'localhost',port: 3000,cache: {type: 'memory',ttl: {sources: 7200,subtitles: 7200,},},tmdb: {apiKey: process.env.TMDB_API_KEY,cacheTTL: 86400,},proxyConfig: {knownThirdPartyProxies: {},// for this, see the documentation in docs/third-party-pattern-config.mdstreamPatterns: [/^https?:\/\/.+\.(mp4)(\?.*)?$/],// treat direct mp4 links as streams that need proxying. You can also add custom domains that should be streamed through the proxy.},})

Production with Redis

constserver=newOMSSServer({name: 'OMSS Production',version: '1.0.0',host: '0.0.0.0',port: 3000,publicUrl: 'https://api.mystream.com',cache: {type: 'redis',ttl: {sources: 7200,subtitles: 7200,},redis: {host: process.env.REDIS_HOST||'localhost',port: parseInt(process.env.REDIS_PORT||'6379'),password: process.env.REDIS_PASSWORD,},},tmdb: {apiKey: process.env.TMDB_API_KEY,cacheTTL: 86400,},proxyConfig: {knownThirdPartyProxies: {},// for this, see the documentation in docs/third-party-pattern-config.mdstreamPatterns: [/^https?:\/\/.+\.(mp4)(\?.*)?$/],// treat direct mp4 links as streams that need proxying. You can also add custom domains that should be streamed through the proxy.},cors: {origin: 'https://myapp.com',methods: ['GET','OPTIONS'],allowedHeaders: ['Content-Type','Authorization'],exposedHeaders: ['Content-Length','Content-Type'],},})

Behind Reverse Proxy

constserver=newOMSSServer({name: 'OMSS API',version: '1.0.0',host: '0.0.0.0',port: 3000,// This is the public URL clients will usepublicUrl: 'https://myapp.com/api',cache: {type: 'redis',redis: {host: 'redis.internal',port: 6379,},},tmdb: {apiKey: process.env.TMDB_API_KEY,cacheTTL: 86400,},proxyConfig: {knownThirdPartyProxies: {},// for this, see the documentation in docs/third-party-pattern-config.mdstreamPatterns: [/^https?:\/\/.+\.(mp4)(\?.*)?$/],// treat direct mp4 links as streams that need proxying. You can also add custom domains that should be streamed through the proxy.},cors: {origin: 'https://myapp.com',methods: ['GET','OPTIONS'],allowedHeaders: ['Content-Type','Authorization'],exposedHeaders: ['Content-Length','Content-Type'],},})

πŸ”Œ Creating Custom Providers

See the detailed Provider Creation Guide for a complete walkthrough.

Quick Start with Auto-Discovery

The easiest way to add a new provider:

  1. Create a directory for all of your provider files

    touch src/providers/implementations/my-provider.ts
  2. Implement the BaseProvider class (see example below) in each file.

  3. In the Setup, use the discoverProviders method of the ProviderRegistry to load all providers from that directory:

    constregistry=server.getRegistry()registry.discoverProviders('./src/providers/implementations')// relative to where you start the server from
  4. That's it! The provider will be automatically discovered and registered when you start the server!

No imports, no manual registration needed!

Minimal Provider Example

import{BaseProvider}from'./src/providers/base-provider'import{ProviderCapabilities,ProviderMediaObject,ProviderResult}from'./src/core/types'exportclassMyProviderextendsBaseProvider{// Required: Provider identificationreadonlyid='my-provider'readonlyname='My Provider'readonlyenabled=true// Required: Base URL and headersreadonlyBASE_URL='https://provider.example.com'readonlyHEADERS={'User-Agent': 'Mozilla/5.0',Referer: 'https://provider.example.com',}// Required: Declare what this provider supportsreadonlycapabilities: ProviderCapabilities={supportedContentTypes: ['movies','tv'],}// Implement movie scrapingasyncgetMovieSources(media: ProviderMediaObject): Promise<ProviderResult>{this.console.log('Fetching movie sources',media)try{// Your scraping logic hereconststreamUrl=awaitthis.scrapeMovieUrl(media.tmdbId)// this is just some example functionreturn{sources: [{url: this.createProxyUrl(streamUrl,this.HEADERS),type: 'hls',quality: '1080p',audioTracks: [{language: 'en',label: 'English',},],provider: {id: this.id,name: this.name,},},],subtitles: [],diagnostics: [],}}catch(error){this.console.error('Failed to fetch sources',error,media)return{sources: [],subtitles: [],diagnostics: [{code: 'PROVIDER_ERROR',message: `${this.name} failed`,field: '',severity: 'error',},],}}}// Implement TV scrapingasyncgetTVSources(media: ProviderMediaObject): Promise<ProviderResult>{// Similar to getMovieSources but for TVreturn{sources: [],subtitles: [],diagnostics: []}}// Optional: Custom health checkasynchealthCheck(): Promise<boolean>{try{constresponse=awaitfetch(this.BASE_URL)returnresponse.ok}catch{returnfalse}}}

Full Provider Example

See the detailed Provider Creation Guide for a complete walkthrough.

To test a singulare Provider without setting up the whole server, you can use the following file, which will run the provider in isolation and allow you to test its functionality, without debugging the whole server.

import{ProviderMediaObject}from"@omss/framework"import{ExampleProvider}from"./example.js"constprov=newExampleProvider()constmediaObj: ProviderMediaObject={title: "The Dark Knight",tmdbId: "155",releaseYear: "2008",type: "movie",imdbId: "tt0468569"}constresp=awaitprov.getMovieSources(mediaObj)console.log(resp)

🧩 MCP Endpoints

The Model Context Protocol (MCP) is an optional JSON-RPC-like API that allows LLMs and other intelligent agents to interact with your OMSS server in a structured way. This can be useful for advanced integrations, such as allowing users to ask an AI assistant to find streaming sources for a movie or TV show.

When enabled, the MCP endpoint is exposed at /mcp (configurable) and accepts POST requests with a JSON body containing the method and parameters. The framework currently supports the following MCP method:

  • omss_get_sources: Fetches streaming sources for a movie or TV episode by TMDB ID. Parameters are the same as the regular API endpoints, but wrapped in an MCP request.

πŸ“‘ API Endpoints

GET /v1/movies/:tmdbId

Fetch streaming sources for a movie.

Parameters:

  • tmdbId (path): TMDB movie ID

Response:

{
"responseId": "uuid-v4",
"expiresAt": "2026-01-18T20:00:00.000Z",
"sources": [
{
"url": "/v1/proxy?data=...",
"type": "hls",
"quality": "1080p",
"audioTracks": [
{
"language": "en",
"label": "English"
}
],
"provider": {
"id": "vixsrc",
"name": "VixSrc"
}
}
],
"subtitles": [],
"diagnostics": []
}

GET /v1/tv/:tmdbId/seasons/:season/episodes/:episode

Fetch streaming sources for a TV episode.

Parameters:

  • tmdbId (path): TMDB series ID
  • season (path): Season number (0-99)
  • episode (path): Episode number (1-9999)

Response: Same structure as movies endpoint

GET /v1/proxy

Proxy streaming URLs with custom headers.

Query Parameters:

  • data (required): URL-encoded JSON containing:
    {
    "url": "https://stream.example.com/video.m3u8",
    "headers": {
    "Referer": "https://provider.example.com"
    }
    }

GET /v1/refresh/:responseId

Force refresh cached sources.

Parameters:

  • responseId (path): Response ID from previous request

GET /v1/health

Health check endpoint.

Response:

{
"status": "healthy",
"version": "1.0.0",
"providers": {
"total": 1,
"enabled": 1
}
}

🌍 Environment Variables

# Server ConfigurationPORT=3000# Port number for the serverHOST=0.0.0.0# Use 'localhost' to restrict to local accessNODE_ENV=development# 'development' | 'production'MCP_ENABLED=false# 'true' | 'false'# TMDB ConfigurationTMDB_API_KEY=your_tmdb_api_key_hereTMDB_CACHE_TTL=86400# Cache ConfigurationCACHE_TYPE=memory# 'memory' | 'redis'# Redis Configuration (if using Redis cache)REDIS_HOST=localhost# default Redis hostREDIS_PORT=6379# default Redis portREDIS_PASSWORD=# Redis password if required

πŸ“Ί Stremio Compatibility

Although the original OMSS standard was not specifically designed for Stremio, this framework is fully compatible with Stremio. In both ways:

  1. You can use this framework to build a Stremio Addon. To enable the Stremio Addon SDK, simply set the stremioAddon option to true in the server configuration. This will automatically add the required endpoints (/stremio/manifest.json) and response formatting to work seamlessly with Stremio.

  2. You can bind other Stremio Addon's directly to this framework. Since all Stremio Addons follow a standardized API, you can just pass the manifest URL of any Stremio Addon to the stremioAddons configuration option, and the framework will automatically fetch the manifest, extract the sources and bind them to your server. This allows you to easily aggregate sources from existing Stremio Addons alongside your custom providers, and expose them all through a single unified API.

πŸ—οΈ Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ OMSS Server β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ Controllers β”‚
β”‚ β”œβ”€β”€ ContentController (Movies/TV endpoints) β”‚
β”‚ β”œβ”€β”€ ProxyController (Streaming proxy) β”‚
β”‚ └── HealthController (Health checks) β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ Services β”‚
β”‚ β”œβ”€β”€ SourceService (Aggregates provider results) β”‚
β”‚ β”œβ”€β”€ TMDBService (Validates against TMDB) β”‚
β”‚ └── ProxyService (Handles URL proxying) β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ Provider Registry β”‚
β”‚ └── Manages all registered providers β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ Providers (Implement BaseProvider) β”‚
β”‚ β”œβ”€β”€ YourCustomProvider β”‚
β”‚ └── ... β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ Cache Layer β”‚
β”‚ β”œβ”€β”€ MemoryCache (Development) β”‚
β”‚ └── RedisCache (Production) β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

βœ… OMSS Compliance

This implementation follows the OMSS Standard:

  • βœ… Standardized Response Format: All responses follow OMSS schema
  • βœ… TMDB Validation: All requests validated against TMDB
  • βœ… Proxy Support: Required for all streaming URLs
  • βœ… Error Handling: OMSS-compliant error responses
  • βœ… Source Identification: Unique IDs for all sources
  • βœ… Audio Track Support: Multiple audio tracks per source
  • βœ… Subtitle Support: VTT/SRT subtitle formats
  • βœ… Quality Indicators: Resolution-based quality tags
  • βœ… Provider Attribution: Source provider identification
  • βœ… Diagnostics: Detailed error/warning information

πŸ“š Additional Resources

🀝 Contributing

Contributions are welcome! Please read our contributing guidelines before submitting PRs.

πŸ“„ License

MIT License - see LICENSE file for details.

πŸ™ Acknowledgments

  • All maintainers
  • OMSS standard contributors

About

πŸ› οΈ Official TypeScript framework for building OMSS-compliant streaming backends

Resources

Code of conduct

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

OMSS Framework

NPM VersionLicense: MITTypeScriptOMSS SpecNode.js

social preview

This is an extendable multi site scraping framework, which follows the implementation guidelines of the OMSS (Open Media Streaming Standard). It demonstrates how to build a compliant streaming media aggregation service that scrapes content from multiple providers and returns standardized responses. It handles most of the logic already for you. You just have to add the scraping logic!

Additionally, this is the worlds first AI-Enabled Streaming Framework! With built-in support for the Model Context Protocol (MCP), you can easily integrate LLMs and intelligent agents to find streaming sources using natural language queries, or even automate the management of your streaming backend using AI assistants.



🎯 What is OMSS?

OMSS is an open standard for streaming media aggregation. It provides a unified API for fetching movie and TV show streaming sources from multiple providers, with built-in proxy support, subtitle handling, and quality selection.

πŸ” What is the @omss/framework?

The @omss/framework is the official TypeScript/Node.js implementation framework that makes building OMSS-compliant backends effortless. Instead of manually implementing the standard from scratch, developers can focus solely on writing provider scraping logic while the framework handles all the boilerplate β€” routing, validation, proxy management, caching, error handling, and response formatting.

Key Features

  • βœ… Standardized API: Consistent response format across all providers
  • βœ… MCP Support: Optional Model Context Protocol endpoint for LLM integration
  • βœ… Stremio Compatibility: Designed to work seamlessly with Stremio Addons and also support Stremio Addon SDK
  • βœ… Multi-Provider Support: Aggregate sources from multiple streaming providers
  • βœ… Built-in Proxy: Automatic URL proxying with header forwarding
  • βœ… TMDB Integration: Validation against The Movie Database
  • βœ… Caching Layer: Redis or in-memory caching for performance
  • βœ… Type Safety: Full TypeScript support
  • βœ… Provider Management: Easy enable/disable, automatic discovery
  • βœ… Health Checks: Monitor provider availability
  • βœ… Refresh API: Force cache invalidation when needed

πŸ“‹ Table of Contents

πŸš€ Installation

There is a template which you can use to easily create your own streaming backend. Check it out here!This is the easiest way to create your own OMSS backend.

Prerequisites

  • Node.js 18.x or higher
  • npm or yarn
  • TMDB API Key (Get one here)
  • (Optional) Redis server for caching

Install Dependencies

# npm
npm install @omss/framework
# yarn
yarn add @omss/framework
# pnpm
pnpm add @omss/framework

πŸš€ Quick start

Minimal example using the built‑in provider and in‑memory cache:

// src/server.tsimport{OMSSServer}from'@omss/framework'import{ExampleProvider}from'./src/providers/implementations/example-provider'// Create server instanceconstserver=newOMSSServer({name: 'My OMSS Backend',version: '1.0.0',host: 'localhost',port: 3000,cache: {type: 'memory',ttl: {sources: 7200,subtitles: 7200,},},tmdb: {apiKey: process.env.TMDB_API_KEY,cacheTTL: 86400,},proxyConfig: {knownThirdPartyProxies: {'hls1.vid1.site': [/\/proxy\/(.+)$/],'madplay.site': [/\/api\/[^/]+\/proxy\?url=(.+)$/],'*': [/\/proxy\/(.+)$/,/\/m3u8-proxy\?url=(.+?)(&|$)/],},streamPatterns: [/^https?:\/\/.+\.(mp4)(\?.*)?$/],// treat direct mp4 links as streams that need proxying. You can also add custom domains that should be streamed through the proxy.},// You can override the default cors settings, by passing your own fastify cors options here. By default, it allows all origins./* cors: { origin: '*', methods: ['GET', 'OPTIONS', 'HEAD'], allowedHeaders: ['Content-Type', 'Authorization', 'Range', 'Accept'], exposedHeaders: ['Content-Length', 'Content-Type', 'Content-Range', 'Accept-Ranges'], }, */})// Register providersconstregistry=server.getRegistry()registry.register(newExampleProvider())// or use the very cool auto-discovery feature// registry.discoverProviders('./path/to/providerfolder');// Note: this is relative to *where you start the server*.// before starting the server, you can also modify any fastify instance settings, by getting the instance via server.getFastifyInstance() and calling any of its methods. For example, to add a custom route:// Start serverawaitserver.start()

.env:

# Server ConfigurationPORT=3000# Port number for the serverHOST=0.0.0.0# Use 'localhost' to restrict to local accessNODE_ENV=development# 'development' | 'production'# TMDB ConfigurationTMDB_API_KEY=your_tmdb_api_key_hereTMDB_CACHE_TTL=86400# Cache ConfigurationCACHE_TYPE=memory# 'memory' | 'redis'# Redis Configuration (if using Redis cache)REDIS_HOST=localhost# default Redis hostREDIS_PORT=6379# default Redis portREDIS_PASSWORD=# Redis password if required

Run in dev:

npm run dev

And then it should work!

βš™οΈ Configuration

Server Configuration Options

interfaceOMSSConfig{// Required: Server identificationname: string// Your server nameversion: string// OMSS Spec version// Optional: Network settingshost?: string// Default: 'localhost'port?: number// Default: 3000publicUrl?: string// For reverse proxy setups// Optional: Cache configurationcache?: {type: 'memory'|'redis'ttl: {sources: numbersubtitles: number}redis?: {host: stringport: numberpassword?: string}}// Required: TMDB configurationtmdb?: {apiKey?: string// Can also use TMDB_API_KEY env varcacheTTL?: number// Default: 86400 (24 hours)}// Proxy configurationproxyConfig?: {knownThirdPartyProxies: Record<string,RegExp[]>// for this, see the documentation in docs/third-party-pattern-config.mdstreamPatterns: RegExp[]// Optional: Custom patterns to identify streaming URLs that need proxying}// Optional: CORS configuration (overrides default)cors?: {origin: stringmethods: string[]allowedHeaders: string[]exposedHeaders: string[]}}

Example Configurations

Development

constserver=newOMSSServer({name: 'OMSS Dev Server',version: '1.0.0',host: 'localhost',port: 3000,cache: {type: 'memory',ttl: {sources: 7200,subtitles: 7200,},},tmdb: {apiKey: process.env.TMDB_API_KEY,cacheTTL: 86400,},proxyConfig: {knownThirdPartyProxies: {},// for this, see the documentation in docs/third-party-pattern-config.mdstreamPatterns: [/^https?:\/\/.+\.(mp4)(\?.*)?$/],// treat direct mp4 links as streams that need proxying. You can also add custom domains that should be streamed through the proxy.},})

Production with Redis

constserver=newOMSSServer({name: 'OMSS Production',version: '1.0.0',host: '0.0.0.0',port: 3000,publicUrl: 'https://api.mystream.com',cache: {type: 'redis',ttl: {sources: 7200,subtitles: 7200,},redis: {host: process.env.REDIS_HOST||'localhost',port: parseInt(process.env.REDIS_PORT||'6379'),password: process.env.REDIS_PASSWORD,},},tmdb: {apiKey: process.env.TMDB_API_KEY,cacheTTL: 86400,},proxyConfig: {knownThirdPartyProxies: {},// for this, see the documentation in docs/third-party-pattern-config.mdstreamPatterns: [/^https?:\/\/.+\.(mp4)(\?.*)?$/],// treat direct mp4 links as streams that need proxying. You can also add custom domains that should be streamed through the proxy.},cors: {origin: 'https://myapp.com',methods: ['GET','OPTIONS'],allowedHeaders: ['Content-Type','Authorization'],exposedHeaders: ['Content-Length','Content-Type'],},})

Behind Reverse Proxy

constserver=newOMSSServer({name: 'OMSS API',version: '1.0.0',host: '0.0.0.0',port: 3000,// This is the public URL clients will usepublicUrl: 'https://myapp.com/api',cache: {type: 'redis',redis: {host: 'redis.internal',port: 6379,},},tmdb: {apiKey: process.env.TMDB_API_KEY,cacheTTL: 86400,},proxyConfig: {knownThirdPartyProxies: {},// for this, see the documentation in docs/third-party-pattern-config.mdstreamPatterns: [/^https?:\/\/.+\.(mp4)(\?.*)?$/],// treat direct mp4 links as streams that need proxying. You can also add custom domains that should be streamed through the proxy.},cors: {origin: 'https://myapp.com',methods: ['GET','OPTIONS'],allowedHeaders: ['Content-Type','Authorization'],exposedHeaders: ['Content-Length','Content-Type'],},})

πŸ”Œ Creating Custom Providers

See the detailed Provider Creation Guide for a complete walkthrough.

Quick Start with Auto-Discovery

The easiest way to add a new provider:

  1. Create a directory for all of your provider files

    touch src/providers/implementations/my-provider.ts
  2. Implement the BaseProvider class (see example below) in each file.

  3. In the Setup, use the discoverProviders method of the ProviderRegistry to load all providers from that directory:

    constregistry=server.getRegistry()registry.discoverProviders('./src/providers/implementations')// relative to where you start the server from
  4. That's it! The provider will be automatically discovered and registered when you start the server!

No imports, no manual registration needed!

Minimal Provider Example

import{BaseProvider}from'./src/providers/base-provider'import{ProviderCapabilities,ProviderMediaObject,ProviderResult}from'./src/core/types'exportclassMyProviderextendsBaseProvider{// Required: Provider identificationreadonlyid='my-provider'readonlyname='My Provider'readonlyenabled=true// Required: Base URL and headersreadonlyBASE_URL='https://provider.example.com'readonlyHEADERS={'User-Agent': 'Mozilla/5.0',Referer: 'https://provider.example.com',}// Required: Declare what this provider supportsreadonlycapabilities: ProviderCapabilities={supportedContentTypes: ['movies','tv'],}// Implement movie scrapingasyncgetMovieSources(media: ProviderMediaObject): Promise<ProviderResult>{this.console.log('Fetching movie sources',media)try{// Your scraping logic hereconststreamUrl=awaitthis.scrapeMovieUrl(media.tmdbId)// this is just some example functionreturn{sources: [{url: this.createProxyUrl(streamUrl,this.HEADERS),type: 'hls',quality: '1080p',audioTracks: [{language: 'en',label: 'English',},],provider: {id: this.id,name: this.name,},},],subtitles: [],diagnostics: [],}}catch(error){this.console.error('Failed to fetch sources',error,media)return{sources: [],subtitles: [],diagnostics: [{code: 'PROVIDER_ERROR',message: `${this.name} failed`,field: '',severity: 'error',},],}}}// Implement TV scrapingasyncgetTVSources(media: ProviderMediaObject): Promise<ProviderResult>{// Similar to getMovieSources but for TVreturn{sources: [],subtitles: [],diagnostics: []}}// Optional: Custom health checkasynchealthCheck(): Promise<boolean>{try{constresponse=awaitfetch(this.BASE_URL)returnresponse.ok}catch{returnfalse}}}

Full Provider Example

See the detailed Provider Creation Guide for a complete walkthrough.

To test a singulare Provider without setting up the whole server, you can use the following file, which will run the provider in isolation and allow you to test its functionality, without debugging the whole server.

import{ProviderMediaObject}from"@omss/framework"import{ExampleProvider}from"./example.js"constprov=newExampleProvider()constmediaObj: ProviderMediaObject={title: "The Dark Knight",tmdbId: "155",releaseYear: "2008",type: "movie",imdbId: "tt0468569"}constresp=awaitprov.getMovieSources(mediaObj)console.log(resp)

🧩 MCP Endpoints

The Model Context Protocol (MCP) is an optional JSON-RPC-like API that allows LLMs and other intelligent agents to interact with your OMSS server in a structured way. This can be useful for advanced integrations, such as allowing users to ask an AI assistant to find streaming sources for a movie or TV show.

When enabled, the MCP endpoint is exposed at /mcp (configurable) and accepts POST requests with a JSON body containing the method and parameters. The framework currently supports the following MCP method:

  • omss_get_sources: Fetches streaming sources for a movie or TV episode by TMDB ID. Parameters are the same as the regular API endpoints, but wrapped in an MCP request.

πŸ“‘ API Endpoints

GET /v1/movies/:tmdbId

Fetch streaming sources for a movie.

Parameters:

  • tmdbId (path): TMDB movie ID

Response:

{
"responseId": "uuid-v4",
"expiresAt": "2026-01-18T20:00:00.000Z",
"sources": [
{
"url": "/v1/proxy?data=...",
"type": "hls",
"quality": "1080p",
"audioTracks": [
{
"language": "en",
"label": "English"
}
],
"provider": {
"id": "vixsrc",
"name": "VixSrc"
}
}
],
"subtitles": [],
"diagnostics": []
}

GET /v1/tv/:tmdbId/seasons/:season/episodes/:episode

Fetch streaming sources for a TV episode.

Parameters:

  • tmdbId (path): TMDB series ID
  • season (path): Season number (0-99)
  • episode (path): Episode number (1-9999)

Response: Same structure as movies endpoint

GET /v1/proxy

Proxy streaming URLs with custom headers.

Query Parameters:

  • data (required): URL-encoded JSON containing:
    {
    "url": "https://stream.example.com/video.m3u8",
    "headers": {
    "Referer": "https://provider.example.com"
    }
    }

GET /v1/refresh/:responseId

Force refresh cached sources.

Parameters:

  • responseId (path): Response ID from previous request

GET /v1/health

Health check endpoint.

Response:

{
"status": "healthy",
"version": "1.0.0",
"providers": {
"total": 1,
"enabled": 1
}
}

🌍 Environment Variables

# Server ConfigurationPORT=3000# Port number for the serverHOST=0.0.0.0# Use 'localhost' to restrict to local accessNODE_ENV=development# 'development' | 'production'MCP_ENABLED=false# 'true' | 'false'# TMDB ConfigurationTMDB_API_KEY=your_tmdb_api_key_hereTMDB_CACHE_TTL=86400# Cache ConfigurationCACHE_TYPE=memory# 'memory' | 'redis'# Redis Configuration (if using Redis cache)REDIS_HOST=localhost# default Redis hostREDIS_PORT=6379# default Redis portREDIS_PASSWORD=# Redis password if required

πŸ“Ί Stremio Compatibility

Although the original OMSS standard was not specifically designed for Stremio, this framework is fully compatible with Stremio. In both ways:

  1. You can use this framework to build a Stremio Addon. To enable the Stremio Addon SDK, simply set the stremioAddon option to true in the server configuration. This will automatically add the required endpoints (/stremio/manifest.json) and response formatting to work seamlessly with Stremio.

  2. You can bind other Stremio Addon's directly to this framework. Since all Stremio Addons follow a standardized API, you can just pass the manifest URL of any Stremio Addon to the stremioAddons configuration option, and the framework will automatically fetch the manifest, extract the sources and bind them to your server. This allows you to easily aggregate sources from existing Stremio Addons alongside your custom providers, and expose them all through a single unified API.

πŸ—οΈ Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ OMSS Server β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ Controllers β”‚
β”‚ β”œβ”€β”€ ContentController (Movies/TV endpoints) β”‚
β”‚ β”œβ”€β”€ ProxyController (Streaming proxy) β”‚
β”‚ └── HealthController (Health checks) β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ Services β”‚
β”‚ β”œβ”€β”€ SourceService (Aggregates provider results) β”‚
β”‚ β”œβ”€β”€ TMDBService (Validates against TMDB) β”‚
β”‚ └── ProxyService (Handles URL proxying) β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ Provider Registry β”‚
β”‚ └── Manages all registered providers β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ Providers (Implement BaseProvider) β”‚
β”‚ β”œβ”€β”€ YourCustomProvider β”‚
β”‚ └── ... β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ Cache Layer β”‚
β”‚ β”œβ”€β”€ MemoryCache (Development) β”‚
β”‚ └── RedisCache (Production) β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

βœ… OMSS Compliance

This implementation follows the OMSS Standard:

  • βœ… Standardized Response Format: All responses follow OMSS schema
  • βœ… TMDB Validation: All requests validated against TMDB
  • βœ… Proxy Support: Required for all streaming URLs
  • βœ… Error Handling: OMSS-compliant error responses
  • βœ… Source Identification: Unique IDs for all sources
  • βœ… Audio Track Support: Multiple audio tracks per source
  • βœ… Subtitle Support: VTT/SRT subtitle formats
  • βœ… Quality Indicators: Resolution-based quality tags
  • βœ… Provider Attribution: Source provider identification
  • βœ… Diagnostics: Detailed error/warning information

πŸ“š Additional Resources

🀝 Contributing

Contributions are welcome! Please read our contributing guidelines before submitting PRs.

πŸ“„ License

MIT License - see LICENSE file for details.

πŸ™ Acknowledgments

  • All maintainers
  • OMSS standard contributors

About

πŸ› οΈ Official TypeScript framework for building OMSS-compliant streaming backends

Resources

Code of conduct

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

Repository files navigation

OMSS Framework

NPM VersionLicense: MITTypeScriptOMSS SpecNode.js

social preview

This is an extendable multi site scraping framework, which follows the implementation guidelines of the OMSS (Open Media Streaming Standard). It demonstrates how to build a compliant streaming media aggregation service that scrapes content from multiple providers and returns standardized responses. It handles most of the logic already for you. You just have to add the scraping logic!

Additionally, this is the worlds first AI-Enabled Streaming Framework! With built-in support for the Model Context Protocol (MCP), you can easily integrate LLMs and intelligent agents to find streaming sources using natural language queries, or even automate the management of your streaming backend using AI assistants.



🎯 What is OMSS?

OMSS is an open standard for streaming media aggregation. It provides a unified API for fetching movie and TV show streaming sources from multiple providers, with built-in proxy support, subtitle handling, and quality selection.

πŸ” What is the @omss/framework?

The @omss/framework is the official TypeScript/Node.js implementation framework that makes building OMSS-compliant backends effortless. Instead of manually implementing the standard from scratch, developers can focus solely on writing provider scraping logic while the framework handles all the boilerplate β€” routing, validation, proxy management, caching, error handling, and response formatting.

Key Features

  • βœ… Standardized API: Consistent response format across all providers
  • βœ… MCP Support: Optional Model Context Protocol endpoint for LLM integration
  • βœ… Stremio Compatibility: Designed to work seamlessly with Stremio Addons and also support Stremio Addon SDK
  • βœ… Multi-Provider Support: Aggregate sources from multiple streaming providers
  • βœ… Built-in Proxy: Automatic URL proxying with header forwarding
  • βœ… TMDB Integration: Validation against The Movie Database
  • βœ… Caching Layer: Redis or in-memory caching for performance
  • βœ… Type Safety: Full TypeScript support
  • βœ… Provider Management: Easy enable/disable, automatic discovery
  • βœ… Health Checks: Monitor provider availability
  • βœ… Refresh API: Force cache invalidation when needed

πŸ“‹ Table of Contents

πŸš€ Installation

There is a template which you can use to easily create your own streaming backend. Check it out here!This is the easiest way to create your own OMSS backend.

Prerequisites

  • Node.js 18.x or higher
  • npm or yarn
  • TMDB API Key (Get one here)
  • (Optional) Redis server for caching

Install Dependencies

# npm
npm install @omss/framework
# yarn
yarn add @omss/framework
# pnpm
pnpm add @omss/framework

πŸš€ Quick start

Minimal example using the built‑in provider and in‑memory cache:

// src/server.tsimport{OMSSServer}from'@omss/framework'import{ExampleProvider}from'./src/providers/implementations/example-provider'// Create server instanceconstserver=newOMSSServer({name: 'My OMSS Backend',version: '1.0.0',host: 'localhost',port: 3000,cache: {type: 'memory',ttl: {sources: 7200,subtitles: 7200,},},tmdb: {apiKey: process.env.TMDB_API_KEY,cacheTTL: 86400,},proxyConfig: {knownThirdPartyProxies: {'hls1.vid1.site': [/\/proxy\/(.+)$/],'madplay.site': [/\/api\/[^/]+\/proxy\?url=(.+)$/],'*': [/\/proxy\/(.+)$/,/\/m3u8-proxy\?url=(.+?)(&|$)/],},streamPatterns: [/^https?:\/\/.+\.(mp4)(\?.*)?$/],// treat direct mp4 links as streams that need proxying. You can also add custom domains that should be streamed through the proxy.},// You can override the default cors settings, by passing your own fastify cors options here. By default, it allows all origins./* cors: { origin: '*', methods: ['GET', 'OPTIONS', 'HEAD'], allowedHeaders: ['Content-Type', 'Authorization', 'Range', 'Accept'], exposedHeaders: ['Content-Length', 'Content-Type', 'Content-Range', 'Accept-Ranges'], }, */})// Register providersconstregistry=server.getRegistry()registry.register(newExampleProvider())// or use the very cool auto-discovery feature// registry.discoverProviders('./path/to/providerfolder');// Note: this is relative to *where you start the server*.// before starting the server, you can also modify any fastify instance settings, by getting the instance via server.getFastifyInstance() and calling any of its methods. For example, to add a custom route:// Start serverawaitserver.start()

.env:

# Server ConfigurationPORT=3000# Port number for the serverHOST=0.0.0.0# Use 'localhost' to restrict to local accessNODE_ENV=development# 'development' | 'production'# TMDB ConfigurationTMDB_API_KEY=your_tmdb_api_key_hereTMDB_CACHE_TTL=86400# Cache ConfigurationCACHE_TYPE=memory# 'memory' | 'redis'# Redis Configuration (if using Redis cache)REDIS_HOST=localhost# default Redis hostREDIS_PORT=6379# default Redis portREDIS_PASSWORD=# Redis password if required

Run in dev:

npm run dev

And then it should work!

βš™οΈ Configuration

Server Configuration Options

interfaceOMSSConfig{// Required: Server identificationname: string// Your server nameversion: string// OMSS Spec version// Optional: Network settingshost?: string// Default: 'localhost'port?: number// Default: 3000publicUrl?: string// For reverse proxy setups// Optional: Cache configurationcache?: {type: 'memory'|'redis'ttl: {sources: numbersubtitles: number}redis?: {host: stringport: numberpassword?: string}}// Required: TMDB configurationtmdb?: {apiKey?: string// Can also use TMDB_API_KEY env varcacheTTL?: number// Default: 86400 (24 hours)}// Proxy configurationproxyConfig?: {knownThirdPartyProxies: Record<string,RegExp[]>// for this, see the documentation in docs/third-party-pattern-config.mdstreamPatterns: RegExp[]// Optional: Custom patterns to identify streaming URLs that need proxying}// Optional: CORS configuration (overrides default)cors?: {origin: stringmethods: string[]allowedHeaders: string[]exposedHeaders: string[]}}

Example Configurations

Development

constserver=newOMSSServer({name: 'OMSS Dev Server',version: '1.0.0',host: 'localhost',port: 3000,cache: {type: 'memory',ttl: {sources: 7200,subtitles: 7200,},},tmdb: {apiKey: process.env.TMDB_API_KEY,cacheTTL: 86400,},proxyConfig: {knownThirdPartyProxies: {},// for this, see the documentation in docs/third-party-pattern-config.mdstreamPatterns: [/^https?:\/\/.+\.(mp4)(\?.*)?$/],// treat direct mp4 links as streams that need proxying. You can also add custom domains that should be streamed through the proxy.},})

Production with Redis

constserver=newOMSSServer({name: 'OMSS Production',version: '1.0.0',host: '0.0.0.0',port: 3000,publicUrl: 'https://api.mystream.com',cache: {type: 'redis',ttl: {sources: 7200,subtitles: 7200,},redis: {host: process.env.REDIS_HOST||'localhost',port: parseInt(process.env.REDIS_PORT||'6379'),password: process.env.REDIS_PASSWORD,},},tmdb: {apiKey: process.env.TMDB_API_KEY,cacheTTL: 86400,},proxyConfig: {knownThirdPartyProxies: {},// for this, see the documentation in docs/third-party-pattern-config.mdstreamPatterns: [/^https?:\/\/.+\.(mp4)(\?.*)?$/],// treat direct mp4 links as streams that need proxying. You can also add custom domains that should be streamed through the proxy.},cors: {origin: 'https://myapp.com',methods: ['GET','OPTIONS'],allowedHeaders: ['Content-Type','Authorization'],exposedHeaders: ['Content-Length','Content-Type'],},})

Behind Reverse Proxy

constserver=newOMSSServer({name: 'OMSS API',version: '1.0.0',host: '0.0.0.0',port: 3000,// This is the public URL clients will usepublicUrl: 'https://myapp.com/api',cache: {type: 'redis',redis: {host: 'redis.internal',port: 6379,},},tmdb: {apiKey: process.env.TMDB_API_KEY,cacheTTL: 86400,},proxyConfig: {knownThirdPartyProxies: {},// for this, see the documentation in docs/third-party-pattern-config.mdstreamPatterns: [/^https?:\/\/.+\.(mp4)(\?.*)?$/],// treat direct mp4 links as streams that need proxying. You can also add custom domains that should be streamed through the proxy.},cors: {origin: 'https://myapp.com',methods: ['GET','OPTIONS'],allowedHeaders: ['Content-Type','Authorization'],exposedHeaders: ['Content-Length','Content-Type'],},})

πŸ”Œ Creating Custom Providers

See the detailed Provider Creation Guide for a complete walkthrough.

Quick Start with Auto-Discovery

The easiest way to add a new provider:

  1. Create a directory for all of your provider files

    touch src/providers/implementations/my-provider.ts
  2. Implement the BaseProvider class (see example below) in each file.

  3. In the Setup, use the discoverProviders method of the ProviderRegistry to load all providers from that directory:

    constregistry=server.getRegistry()registry.discoverProviders('./src/providers/implementations')// relative to where you start the server from
  4. That's it! The provider will be automatically discovered and registered when you start the server!

No imports, no manual registration needed!

Minimal Provider Example

import{BaseProvider}from'./src/providers/base-provider'import{ProviderCapabilities,ProviderMediaObject,ProviderResult}from'./src/core/types'exportclassMyProviderextendsBaseProvider{// Required: Provider identificationreadonlyid='my-provider'readonlyname='My Provider'readonlyenabled=true// Required: Base URL and headersreadonlyBASE_URL='https://provider.example.com'readonlyHEADERS={'User-Agent': 'Mozilla/5.0',Referer: 'https://provider.example.com',}// Required: Declare what this provider supportsreadonlycapabilities: ProviderCapabilities={supportedContentTypes: ['movies','tv'],}// Implement movie scrapingasyncgetMovieSources(media: ProviderMediaObject): Promise<ProviderResult>{this.console.log('Fetching movie sources',media)try{// Your scraping logic hereconststreamUrl=awaitthis.scrapeMovieUrl(media.tmdbId)// this is just some example functionreturn{sources: [{url: this.createProxyUrl(streamUrl,this.HEADERS),type: 'hls',quality: '1080p',audioTracks: [{language: 'en',label: 'English',},],provider: {id: this.id,name: this.name,},},],subtitles: [],diagnostics: [],}}catch(error){this.console.error('Failed to fetch sources',error,media)return{sources: [],subtitles: [],diagnostics: [{code: 'PROVIDER_ERROR',message: `${this.name} failed`,field: '',severity: 'error',},],}}}// Implement TV scrapingasyncgetTVSources(media: ProviderMediaObject): Promise<ProviderResult>{// Similar to getMovieSources but for TVreturn{sources: [],subtitles: [],diagnostics: []}}// Optional: Custom health checkasynchealthCheck(): Promise<boolean>{try{constresponse=awaitfetch(this.BASE_URL)returnresponse.ok}catch{returnfalse}}}

Full Provider Example

See the detailed Provider Creation Guide for a complete walkthrough.

To test a singulare Provider without setting up the whole server, you can use the following file, which will run the provider in isolation and allow you to test its functionality, without debugging the whole server.

import{ProviderMediaObject}from"@omss/framework"import{ExampleProvider}from"./example.js"constprov=newExampleProvider()constmediaObj: ProviderMediaObject={title: "The Dark Knight",tmdbId: "155",releaseYear: "2008",type: "movie",imdbId: "tt0468569"}constresp=awaitprov.getMovieSources(mediaObj)console.log(resp)

🧩 MCP Endpoints

The Model Context Protocol (MCP) is an optional JSON-RPC-like API that allows LLMs and other intelligent agents to interact with your OMSS server in a structured way. This can be useful for advanced integrations, such as allowing users to ask an AI assistant to find streaming sources for a movie or TV show.

When enabled, the MCP endpoint is exposed at /mcp (configurable) and accepts POST requests with a JSON body containing the method and parameters. The framework currently supports the following MCP method:

  • omss_get_sources: Fetches streaming sources for a movie or TV episode by TMDB ID. Parameters are the same as the regular API endpoints, but wrapped in an MCP request.

πŸ“‘ API Endpoints

GET /v1/movies/:tmdbId

Fetch streaming sources for a movie.

Parameters:

  • tmdbId (path): TMDB movie ID

Response:

{
"responseId": "uuid-v4",
"expiresAt": "2026-01-18T20:00:00.000Z",
"sources": [
{
"url": "/v1/proxy?data=...",
"type": "hls",
"quality": "1080p",
"audioTracks": [
{
"language": "en",
"label": "English"
}
],
"provider": {
"id": "vixsrc",
"name": "VixSrc"
}
}
],
"subtitles": [],
"diagnostics": []
}

GET /v1/tv/:tmdbId/seasons/:season/episodes/:episode

Fetch streaming sources for a TV episode.

Parameters:

  • tmdbId (path): TMDB series ID
  • season (path): Season number (0-99)
  • episode (path): Episode number (1-9999)

Response: Same structure as movies endpoint

GET /v1/proxy

Proxy streaming URLs with custom headers.

Query Parameters:

  • data (required): URL-encoded JSON containing:
    {
    "url": "https://stream.example.com/video.m3u8",
    "headers": {
    "Referer": "https://provider.example.com"
    }
    }

GET /v1/refresh/:responseId

Force refresh cached sources.

Parameters:

  • responseId (path): Response ID from previous request

GET /v1/health

Health check endpoint.

Response:

{
"status": "healthy",
"version": "1.0.0",
"providers": {
"total": 1,
"enabled": 1
}
}

🌍 Environment Variables

# Server ConfigurationPORT=3000# Port number for the serverHOST=0.0.0.0# Use 'localhost' to restrict to local accessNODE_ENV=development# 'development' | 'production'MCP_ENABLED=false# 'true' | 'false'# TMDB ConfigurationTMDB_API_KEY=your_tmdb_api_key_hereTMDB_CACHE_TTL=86400# Cache ConfigurationCACHE_TYPE=memory# 'memory' | 'redis'# Redis Configuration (if using Redis cache)REDIS_HOST=localhost# default Redis hostREDIS_PORT=6379# default Redis portREDIS_PASSWORD=# Redis password if required

πŸ“Ί Stremio Compatibility

Although the original OMSS standard was not specifically designed for Stremio, this framework is fully compatible with Stremio. In both ways:

  1. You can use this framework to build a Stremio Addon. To enable the Stremio Addon SDK, simply set the stremioAddon option to true in the server configuration. This will automatically add the required endpoints (/stremio/manifest.json) and response formatting to work seamlessly with Stremio.

  2. You can bind other Stremio Addon's directly to this framework. Since all Stremio Addons follow a standardized API, you can just pass the manifest URL of any Stremio Addon to the stremioAddons configuration option, and the framework will automatically fetch the manifest, extract the sources and bind them to your server. This allows you to easily aggregate sources from existing Stremio Addons alongside your custom providers, and expose them all through a single unified API.

πŸ—οΈ Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ OMSS Server β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ Controllers β”‚
β”‚ β”œβ”€β”€ ContentController (Movies/TV endpoints) β”‚
β”‚ β”œβ”€β”€ ProxyController (Streaming proxy) β”‚
β”‚ └── HealthController (Health checks) β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ Services β”‚
β”‚ β”œβ”€β”€ SourceService (Aggregates provider results) β”‚
β”‚ β”œβ”€β”€ TMDBService (Validates against TMDB) β”‚
β”‚ └── ProxyService (Handles URL proxying) β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ Provider Registry β”‚
β”‚ └── Manages all registered providers β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ Providers (Implement BaseProvider) β”‚
β”‚ β”œβ”€β”€ YourCustomProvider β”‚
β”‚ └── ... β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ Cache Layer β”‚
β”‚ β”œβ”€β”€ MemoryCache (Development) β”‚
β”‚ └── RedisCache (Production) β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

βœ… OMSS Compliance

This implementation follows the OMSS Standard:

  • βœ… Standardized Response Format: All responses follow OMSS schema
  • βœ… TMDB Validation: All requests validated against TMDB
  • βœ… Proxy Support: Required for all streaming URLs
  • βœ… Error Handling: OMSS-compliant error responses
  • βœ… Source Identification: Unique IDs for all sources
  • βœ… Audio Track Support: Multiple audio tracks per source
  • βœ… Subtitle Support: VTT/SRT subtitle formats
  • βœ… Quality Indicators: Resolution-based quality tags
  • βœ… Provider Attribution: Source provider identification
  • βœ… Diagnostics: Detailed error/warning information

πŸ“š Additional Resources

🀝 Contributing

Contributions are welcome! Please read our contributing guidelines before submitting PRs.

πŸ“„ License

MIT License - see LICENSE file for details.

πŸ™ Acknowledgments

  • All maintainers
  • OMSS standard contributors

About

πŸ› οΈ Official TypeScript framework for building OMSS-compliant streaming backends

Resources

Code of conduct

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

OMSS Framework

NPM VersionLicense: MITTypeScriptOMSS SpecNode.js

social preview

This is an extendable multi site scraping framework, which follows the implementation guidelines of the OMSS (Open Media Streaming Standard). It demonstrates how to build a compliant streaming media aggregation service that scrapes content from multiple providers and returns standardized responses. It handles most of the logic already for you. You just have to add the scraping logic!

Additionally, this is the worlds first AI-Enabled Streaming Framework! With built-in support for the Model Context Protocol (MCP), you can easily integrate LLMs and intelligent agents to find streaming sources using natural language queries, or even automate the management of your streaming backend using AI assistants.



🎯 What is OMSS?

OMSS is an open standard for streaming media aggregation. It provides a unified API for fetching movie and TV show streaming sources from multiple providers, with built-in proxy support, subtitle handling, and quality selection.

πŸ” What is the @omss/framework?

The @omss/framework is the official TypeScript/Node.js implementation framework that makes building OMSS-compliant backends effortless. Instead of manually implementing the standard from scratch, developers can focus solely on writing provider scraping logic while the framework handles all the boilerplate β€” routing, validation, proxy management, caching, error handling, and response formatting.

Key Features

  • βœ… Standardized API: Consistent response format across all providers
  • βœ… MCP Support: Optional Model Context Protocol endpoint for LLM integration
  • βœ… Stremio Compatibility: Designed to work seamlessly with Stremio Addons and also support Stremio Addon SDK
  • βœ… Multi-Provider Support: Aggregate sources from multiple streaming providers
  • βœ… Built-in Proxy: Automatic URL proxying with header forwarding
  • βœ… TMDB Integration: Validation against The Movie Database
  • βœ… Caching Layer: Redis or in-memory caching for performance
  • βœ… Type Safety: Full TypeScript support
  • βœ… Provider Management: Easy enable/disable, automatic discovery
  • βœ… Health Checks: Monitor provider availability
  • βœ… Refresh API: Force cache invalidation when needed

πŸ“‹ Table of Contents

πŸš€ Installation

There is a template which you can use to easily create your own streaming backend. Check it out here!This is the easiest way to create your own OMSS backend.

Prerequisites

  • Node.js 18.x or higher
  • npm or yarn
  • TMDB API Key (Get one here)
  • (Optional) Redis server for caching

Install Dependencies

# npm
npm install @omss/framework
# yarn
yarn add @omss/framework
# pnpm
pnpm add @omss/framework

πŸš€ Quick start

Minimal example using the built‑in provider and in‑memory cache:

// src/server.tsimport{OMSSServer}from'@omss/framework'import{ExampleProvider}from'./src/providers/implementations/example-provider'// Create server instanceconstserver=newOMSSServer({name: 'My OMSS Backend',version: '1.0.0',host: 'localhost',port: 3000,cache: {type: 'memory',ttl: {sources: 7200,subtitles: 7200,},},tmdb: {apiKey: process.env.TMDB_API_KEY,cacheTTL: 86400,},proxyConfig: {knownThirdPartyProxies: {'hls1.vid1.site': [/\/proxy\/(.+)$/],'madplay.site': [/\/api\/[^/]+\/proxy\?url=(.+)$/],'*': [/\/proxy\/(.+)$/,/\/m3u8-proxy\?url=(.+?)(&|$)/],},streamPatterns: [/^https?:\/\/.+\.(mp4)(\?.*)?$/],// treat direct mp4 links as streams that need proxying. You can also add custom domains that should be streamed through the proxy.},// You can override the default cors settings, by passing your own fastify cors options here. By default, it allows all origins./* cors: { origin: '*', methods: ['GET', 'OPTIONS', 'HEAD'], allowedHeaders: ['Content-Type', 'Authorization', 'Range', 'Accept'], exposedHeaders: ['Content-Length', 'Content-Type', 'Content-Range', 'Accept-Ranges'], }, */})// Register providersconstregistry=server.getRegistry()registry.register(newExampleProvider())// or use the very cool auto-discovery feature// registry.discoverProviders('./path/to/providerfolder');// Note: this is relative to *where you start the server*.// before starting the server, you can also modify any fastify instance settings, by getting the instance via server.getFastifyInstance() and calling any of its methods. For example, to add a custom route:// Start serverawaitserver.start()

.env:

# Server ConfigurationPORT=3000# Port number for the serverHOST=0.0.0.0# Use 'localhost' to restrict to local accessNODE_ENV=development# 'development' | 'production'# TMDB ConfigurationTMDB_API_KEY=your_tmdb_api_key_hereTMDB_CACHE_TTL=86400# Cache ConfigurationCACHE_TYPE=memory# 'memory' | 'redis'# Redis Configuration (if using Redis cache)REDIS_HOST=localhost# default Redis hostREDIS_PORT=6379# default Redis portREDIS_PASSWORD=# Redis password if required

Run in dev:

npm run dev

And then it should work!

βš™οΈ Configuration

Server Configuration Options

interfaceOMSSConfig{// Required: Server identificationname: string// Your server nameversion: string// OMSS Spec version// Optional: Network settingshost?: string// Default: 'localhost'port?: number// Default: 3000publicUrl?: string// For reverse proxy setups// Optional: Cache configurationcache?: {type: 'memory'|'redis'ttl: {sources: numbersubtitles: number}redis?: {host: stringport: numberpassword?: string}}// Required: TMDB configurationtmdb?: {apiKey?: string// Can also use TMDB_API_KEY env varcacheTTL?: number// Default: 86400 (24 hours)}// Proxy configurationproxyConfig?: {knownThirdPartyProxies: Record<string,RegExp[]>// for this, see the documentation in docs/third-party-pattern-config.mdstreamPatterns: RegExp[]// Optional: Custom patterns to identify streaming URLs that need proxying}// Optional: CORS configuration (overrides default)cors?: {origin: stringmethods: string[]allowedHeaders: string[]exposedHeaders: string[]}}

Example Configurations

Development

constserver=newOMSSServer({name: 'OMSS Dev Server',version: '1.0.0',host: 'localhost',port: 3000,cache: {type: 'memory',ttl: {sources: 7200,subtitles: 7200,},},tmdb: {apiKey: process.env.TMDB_API_KEY,cacheTTL: 86400,},proxyConfig: {knownThirdPartyProxies: {},// for this, see the documentation in docs/third-party-pattern-config.mdstreamPatterns: [/^https?:\/\/.+\.(mp4)(\?.*)?$/],// treat direct mp4 links as streams that need proxying. You can also add custom domains that should be streamed through the proxy.},})

Production with Redis

constserver=newOMSSServer({name: 'OMSS Production',version: '1.0.0',host: '0.0.0.0',port: 3000,publicUrl: 'https://api.mystream.com',cache: {type: 'redis',ttl: {sources: 7200,subtitles: 7200,},redis: {host: process.env.REDIS_HOST||'localhost',port: parseInt(process.env.REDIS_PORT||'6379'),password: process.env.REDIS_PASSWORD,},},tmdb: {apiKey: process.env.TMDB_API_KEY,cacheTTL: 86400,},proxyConfig: {knownThirdPartyProxies: {},// for this, see the documentation in docs/third-party-pattern-config.mdstreamPatterns: [/^https?:\/\/.+\.(mp4)(\?.*)?$/],// treat direct mp4 links as streams that need proxying. You can also add custom domains that should be streamed through the proxy.},cors: {origin: 'https://myapp.com',methods: ['GET','OPTIONS'],allowedHeaders: ['Content-Type','Authorization'],exposedHeaders: ['Content-Length','Content-Type'],},})

Behind Reverse Proxy

constserver=newOMSSServer({name: 'OMSS API',version: '1.0.0',host: '0.0.0.0',port: 3000,// This is the public URL clients will usepublicUrl: 'https://myapp.com/api',cache: {type: 'redis',redis: {host: 'redis.internal',port: 6379,},},tmdb: {apiKey: process.env.TMDB_API_KEY,cacheTTL: 86400,},proxyConfig: {knownThirdPartyProxies: {},// for this, see the documentation in docs/third-party-pattern-config.mdstreamPatterns: [/^https?:\/\/.+\.(mp4)(\?.*)?$/],// treat direct mp4 links as streams that need proxying. You can also add custom domains that should be streamed through the proxy.},cors: {origin: 'https://myapp.com',methods: ['GET','OPTIONS'],allowedHeaders: ['Content-Type','Authorization'],exposedHeaders: ['Content-Length','Content-Type'],},})

πŸ”Œ Creating Custom Providers

See the detailed Provider Creation Guide for a complete walkthrough.

Quick Start with Auto-Discovery

The easiest way to add a new provider:

  1. Create a directory for all of your provider files

    touch src/providers/implementations/my-provider.ts
  2. Implement the BaseProvider class (see example below) in each file.

  3. In the Setup, use the discoverProviders method of the ProviderRegistry to load all providers from that directory:

    constregistry=server.getRegistry()registry.discoverProviders('./src/providers/implementations')// relative to where you start the server from
  4. That's it! The provider will be automatically discovered and registered when you start the server!

No imports, no manual registration needed!

Minimal Provider Example

import{BaseProvider}from'./src/providers/base-provider'import{ProviderCapabilities,ProviderMediaObject,ProviderResult}from'./src/core/types'exportclassMyProviderextendsBaseProvider{// Required: Provider identificationreadonlyid='my-provider'readonlyname='My Provider'readonlyenabled=true// Required: Base URL and headersreadonlyBASE_URL='https://provider.example.com'readonlyHEADERS={'User-Agent': 'Mozilla/5.0',Referer: 'https://provider.example.com',}// Required: Declare what this provider supportsreadonlycapabilities: ProviderCapabilities={supportedContentTypes: ['movies','tv'],}// Implement movie scrapingasyncgetMovieSources(media: ProviderMediaObject): Promise<ProviderResult>{this.console.log('Fetching movie sources',media)try{// Your scraping logic hereconststreamUrl=awaitthis.scrapeMovieUrl(media.tmdbId)// this is just some example functionreturn{sources: [{url: this.createProxyUrl(streamUrl,this.HEADERS),type: 'hls',quality: '1080p',audioTracks: [{language: 'en',label: 'English',},],provider: {id: this.id,name: this.name,},},],subtitles: [],diagnostics: [],}}catch(error){this.console.error('Failed to fetch sources',error,media)return{sources: [],subtitles: [],diagnostics: [{code: 'PROVIDER_ERROR',message: `${this.name} failed`,field: '',severity: 'error',},],}}}// Implement TV scrapingasyncgetTVSources(media: ProviderMediaObject): Promise<ProviderResult>{// Similar to getMovieSources but for TVreturn{sources: [],subtitles: [],diagnostics: []}}// Optional: Custom health checkasynchealthCheck(): Promise<boolean>{try{constresponse=awaitfetch(this.BASE_URL)returnresponse.ok}catch{returnfalse}}}

Full Provider Example

See the detailed Provider Creation Guide for a complete walkthrough.

To test a singulare Provider without setting up the whole server, you can use the following file, which will run the provider in isolation and allow you to test its functionality, without debugging the whole server.

import{ProviderMediaObject}from"@omss/framework"import{ExampleProvider}from"./example.js"constprov=newExampleProvider()constmediaObj: ProviderMediaObject={title: "The Dark Knight",tmdbId: "155",releaseYear: "2008",type: "movie",imdbId: "tt0468569"}constresp=awaitprov.getMovieSources(mediaObj)console.log(resp)

🧩 MCP Endpoints

The Model Context Protocol (MCP) is an optional JSON-RPC-like API that allows LLMs and other intelligent agents to interact with your OMSS server in a structured way. This can be useful for advanced integrations, such as allowing users to ask an AI assistant to find streaming sources for a movie or TV show.

When enabled, the MCP endpoint is exposed at /mcp (configurable) and accepts POST requests with a JSON body containing the method and parameters. The framework currently supports the following MCP method:

  • omss_get_sources: Fetches streaming sources for a movie or TV episode by TMDB ID. Parameters are the same as the regular API endpoints, but wrapped in an MCP request.

πŸ“‘ API Endpoints

GET /v1/movies/:tmdbId

Fetch streaming sources for a movie.

Parameters:

  • tmdbId (path): TMDB movie ID

Response:

{
"responseId": "uuid-v4",
"expiresAt": "2026-01-18T20:00:00.000Z",
"sources": [
{
"url": "/v1/proxy?data=...",
"type": "hls",
"quality": "1080p",
"audioTracks": [
{
"language": "en",
"label": "English"
}
],
"provider": {
"id": "vixsrc",
"name": "VixSrc"
}
}
],
"subtitles": [],
"diagnostics": []
}

GET /v1/tv/:tmdbId/seasons/:season/episodes/:episode

Fetch streaming sources for a TV episode.

Parameters:

  • tmdbId (path): TMDB series ID
  • season (path): Season number (0-99)
  • episode (path): Episode number (1-9999)

Response: Same structure as movies endpoint

GET /v1/proxy

Proxy streaming URLs with custom headers.

Query Parameters:

  • data (required): URL-encoded JSON containing:
    {
    "url": "https://stream.example.com/video.m3u8",
    "headers": {
    "Referer": "https://provider.example.com"
    }
    }

GET /v1/refresh/:responseId

Force refresh cached sources.

Parameters:

  • responseId (path): Response ID from previous request

GET /v1/health

Health check endpoint.

Response:

{
"status": "healthy",
"version": "1.0.0",
"providers": {
"total": 1,
"enabled": 1
}
}

🌍 Environment Variables

# Server ConfigurationPORT=3000# Port number for the serverHOST=0.0.0.0# Use 'localhost' to restrict to local accessNODE_ENV=development# 'development' | 'production'MCP_ENABLED=false# 'true' | 'false'# TMDB ConfigurationTMDB_API_KEY=your_tmdb_api_key_hereTMDB_CACHE_TTL=86400# Cache ConfigurationCACHE_TYPE=memory# 'memory' | 'redis'# Redis Configuration (if using Redis cache)REDIS_HOST=localhost# default Redis hostREDIS_PORT=6379# default Redis portREDIS_PASSWORD=# Redis password if required

πŸ“Ί Stremio Compatibility

Although the original OMSS standard was not specifically designed for Stremio, this framework is fully compatible with Stremio. In both ways:

  1. You can use this framework to build a Stremio Addon. To enable the Stremio Addon SDK, simply set the stremioAddon option to true in the server configuration. This will automatically add the required endpoints (/stremio/manifest.json) and response formatting to work seamlessly with Stremio.

  2. You can bind other Stremio Addon's directly to this framework. Since all Stremio Addons follow a standardized API, you can just pass the manifest URL of any Stremio Addon to the stremioAddons configuration option, and the framework will automatically fetch the manifest, extract the sources and bind them to your server. This allows you to easily aggregate sources from existing Stremio Addons alongside your custom providers, and expose them all through a single unified API.

πŸ—οΈ Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ OMSS Server β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ Controllers β”‚
β”‚ β”œβ”€β”€ ContentController (Movies/TV endpoints) β”‚
β”‚ β”œβ”€β”€ ProxyController (Streaming proxy) β”‚
β”‚ └── HealthController (Health checks) β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ Services β”‚
β”‚ β”œβ”€β”€ SourceService (Aggregates provider results) β”‚
β”‚ β”œβ”€β”€ TMDBService (Validates against TMDB) β”‚
β”‚ └── ProxyService (Handles URL proxying) β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ Provider Registry β”‚
β”‚ └── Manages all registered providers β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ Providers (Implement BaseProvider) β”‚
β”‚ β”œβ”€β”€ YourCustomProvider β”‚
β”‚ └── ... β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ Cache Layer β”‚
β”‚ β”œβ”€β”€ MemoryCache (Development) β”‚
β”‚ └── RedisCache (Production) β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

βœ… OMSS Compliance

This implementation follows the OMSS Standard:

  • βœ… Standardized Response Format: All responses follow OMSS schema
  • βœ… TMDB Validation: All requests validated against TMDB
  • βœ… Proxy Support: Required for all streaming URLs
  • βœ… Error Handling: OMSS-compliant error responses
  • βœ… Source Identification: Unique IDs for all sources
  • βœ… Audio Track Support: Multiple audio tracks per source
  • βœ… Subtitle Support: VTT/SRT subtitle formats
  • βœ… Quality Indicators: Resolution-based quality tags
  • βœ… Provider Attribution: Source provider identification
  • βœ… Diagnostics: Detailed error/warning information

πŸ“š Additional Resources

🀝 Contributing

Contributions are welcome! Please read our contributing guidelines before submitting PRs.

πŸ“„ License

MIT License - see LICENSE file for details.

πŸ™ Acknowledgments

  • All maintainers
  • OMSS standard contributors

About

πŸ› οΈ Official TypeScript framework for building OMSS-compliant streaming backends

Resources

Code of conduct

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

Repository files navigation

OMSS Framework

NPM VersionLicense: MITTypeScriptOMSS SpecNode.js

social preview

This is an extendable multi site scraping framework, which follows the implementation guidelines of the OMSS (Open Media Streaming Standard). It demonstrates how to build a compliant streaming media aggregation service that scrapes content from multiple providers and returns standardized responses. It handles most of the logic already for you. You just have to add the scraping logic!

Additionally, this is the worlds first AI-Enabled Streaming Framework! With built-in support for the Model Context Protocol (MCP), you can easily integrate LLMs and intelligent agents to find streaming sources using natural language queries, or even automate the management of your streaming backend using AI assistants.



🎯 What is OMSS?

OMSS is an open standard for streaming media aggregation. It provides a unified API for fetching movie and TV show streaming sources from multiple providers, with built-in proxy support, subtitle handling, and quality selection.

πŸ” What is the @omss/framework?

The @omss/framework is the official TypeScript/Node.js implementation framework that makes building OMSS-compliant backends effortless. Instead of manually implementing the standard from scratch, developers can focus solely on writing provider scraping logic while the framework handles all the boilerplate β€” routing, validation, proxy management, caching, error handling, and response formatting.

Key Features

  • βœ… Standardized API: Consistent response format across all providers
  • βœ… MCP Support: Optional Model Context Protocol endpoint for LLM integration
  • βœ… Stremio Compatibility: Designed to work seamlessly with Stremio Addons and also support Stremio Addon SDK
  • βœ… Multi-Provider Support: Aggregate sources from multiple streaming providers
  • βœ… Built-in Proxy: Automatic URL proxying with header forwarding
  • βœ… TMDB Integration: Validation against The Movie Database
  • βœ… Caching Layer: Redis or in-memory caching for performance
  • βœ… Type Safety: Full TypeScript support
  • βœ… Provider Management: Easy enable/disable, automatic discovery
  • βœ… Health Checks: Monitor provider availability
  • βœ… Refresh API: Force cache invalidation when needed

πŸ“‹ Table of Contents

πŸš€ Installation

There is a template which you can use to easily create your own streaming backend. Check it out here!This is the easiest way to create your own OMSS backend.

Prerequisites

  • Node.js 18.x or higher
  • npm or yarn
  • TMDB API Key (Get one here)
  • (Optional) Redis server for caching

Install Dependencies

# npm
npm install @omss/framework
# yarn
yarn add @omss/framework
# pnpm
pnpm add @omss/framework

πŸš€ Quick start

Minimal example using the built‑in provider and in‑memory cache:

// src/server.tsimport{OMSSServer}from'@omss/framework'import{ExampleProvider}from'./src/providers/implementations/example-provider'// Create server instanceconstserver=newOMSSServer({name: 'My OMSS Backend',version: '1.0.0',host: 'localhost',port: 3000,cache: {type: 'memory',ttl: {sources: 7200,subtitles: 7200,},},tmdb: {apiKey: process.env.TMDB_API_KEY,cacheTTL: 86400,},proxyConfig: {knownThirdPartyProxies: {'hls1.vid1.site': [/\/proxy\/(.+)$/],'madplay.site': [/\/api\/[^/]+\/proxy\?url=(.+)$/],'*': [/\/proxy\/(.+)$/,/\/m3u8-proxy\?url=(.+?)(&|$)/],},streamPatterns: [/^https?:\/\/.+\.(mp4)(\?.*)?$/],// treat direct mp4 links as streams that need proxying. You can also add custom domains that should be streamed through the proxy.},// You can override the default cors settings, by passing your own fastify cors options here. By default, it allows all origins./* cors: { origin: '*', methods: ['GET', 'OPTIONS', 'HEAD'], allowedHeaders: ['Content-Type', 'Authorization', 'Range', 'Accept'], exposedHeaders: ['Content-Length', 'Content-Type', 'Content-Range', 'Accept-Ranges'], }, */})// Register providersconstregistry=server.getRegistry()registry.register(newExampleProvider())// or use the very cool auto-discovery feature// registry.discoverProviders('./path/to/providerfolder');// Note: this is relative to *where you start the server*.// before starting the server, you can also modify any fastify instance settings, by getting the instance via server.getFastifyInstance() and calling any of its methods. For example, to add a custom route:// Start serverawaitserver.start()

.env:

# Server ConfigurationPORT=3000# Port number for the serverHOST=0.0.0.0# Use 'localhost' to restrict to local accessNODE_ENV=development# 'development' | 'production'# TMDB ConfigurationTMDB_API_KEY=your_tmdb_api_key_hereTMDB_CACHE_TTL=86400# Cache ConfigurationCACHE_TYPE=memory# 'memory' | 'redis'# Redis Configuration (if using Redis cache)REDIS_HOST=localhost# default Redis hostREDIS_PORT=6379# default Redis portREDIS_PASSWORD=# Redis password if required

Run in dev:

npm run dev

And then it should work!

βš™οΈ Configuration

Server Configuration Options

interfaceOMSSConfig{// Required: Server identificationname: string// Your server nameversion: string// OMSS Spec version// Optional: Network settingshost?: string// Default: 'localhost'port?: number// Default: 3000publicUrl?: string// For reverse proxy setups// Optional: Cache configurationcache?: {type: 'memory'|'redis'ttl: {sources: numbersubtitles: number}redis?: {host: stringport: numberpassword?: string}}// Required: TMDB configurationtmdb?: {apiKey?: string// Can also use TMDB_API_KEY env varcacheTTL?: number// Default: 86400 (24 hours)}// Proxy configurationproxyConfig?: {knownThirdPartyProxies: Record<string,RegExp[]>// for this, see the documentation in docs/third-party-pattern-config.mdstreamPatterns: RegExp[]// Optional: Custom patterns to identify streaming URLs that need proxying}// Optional: CORS configuration (overrides default)cors?: {origin: stringmethods: string[]allowedHeaders: string[]exposedHeaders: string[]}}

Example Configurations

Development

constserver=newOMSSServer({name: 'OMSS Dev Server',version: '1.0.0',host: 'localhost',port: 3000,cache: {type: 'memory',ttl: {sources: 7200,subtitles: 7200,},},tmdb: {apiKey: process.env.TMDB_API_KEY,cacheTTL: 86400,},proxyConfig: {knownThirdPartyProxies: {},// for this, see the documentation in docs/third-party-pattern-config.mdstreamPatterns: [/^https?:\/\/.+\.(mp4)(\?.*)?$/],// treat direct mp4 links as streams that need proxying. You can also add custom domains that should be streamed through the proxy.},})

Production with Redis

constserver=newOMSSServer({name: 'OMSS Production',version: '1.0.0',host: '0.0.0.0',port: 3000,publicUrl: 'https://api.mystream.com',cache: {type: 'redis',ttl: {sources: 7200,subtitles: 7200,},redis: {host: process.env.REDIS_HOST||'localhost',port: parseInt(process.env.REDIS_PORT||'6379'),password: process.env.REDIS_PASSWORD,},},tmdb: {apiKey: process.env.TMDB_API_KEY,cacheTTL: 86400,},proxyConfig: {knownThirdPartyProxies: {},// for this, see the documentation in docs/third-party-pattern-config.mdstreamPatterns: [/^https?:\/\/.+\.(mp4)(\?.*)?$/],// treat direct mp4 links as streams that need proxying. You can also add custom domains that should be streamed through the proxy.},cors: {origin: 'https://myapp.com',methods: ['GET','OPTIONS'],allowedHeaders: ['Content-Type','Authorization'],exposedHeaders: ['Content-Length','Content-Type'],},})

Behind Reverse Proxy

constserver=newOMSSServer({name: 'OMSS API',version: '1.0.0',host: '0.0.0.0',port: 3000,// This is the public URL clients will usepublicUrl: 'https://myapp.com/api',cache: {type: 'redis',redis: {host: 'redis.internal',port: 6379,},},tmdb: {apiKey: process.env.TMDB_API_KEY,cacheTTL: 86400,},proxyConfig: {knownThirdPartyProxies: {},// for this, see the documentation in docs/third-party-pattern-config.mdstreamPatterns: [/^https?:\/\/.+\.(mp4)(\?.*)?$/],// treat direct mp4 links as streams that need proxying. You can also add custom domains that should be streamed through the proxy.},cors: {origin: 'https://myapp.com',methods: ['GET','OPTIONS'],allowedHeaders: ['Content-Type','Authorization'],exposedHeaders: ['Content-Length','Content-Type'],},})

πŸ”Œ Creating Custom Providers

See the detailed Provider Creation Guide for a complete walkthrough.

Quick Start with Auto-Discovery

The easiest way to add a new provider:

  1. Create a directory for all of your provider files

    touch src/providers/implementations/my-provider.ts
  2. Implement the BaseProvider class (see example below) in each file.

  3. In the Setup, use the discoverProviders method of the ProviderRegistry to load all providers from that directory:

    constregistry=server.getRegistry()registry.discoverProviders('./src/providers/implementations')// relative to where you start the server from
  4. That's it! The provider will be automatically discovered and registered when you start the server!

No imports, no manual registration needed!

Minimal Provider Example

import{BaseProvider}from'./src/providers/base-provider'import{ProviderCapabilities,ProviderMediaObject,ProviderResult}from'./src/core/types'exportclassMyProviderextendsBaseProvider{// Required: Provider identificationreadonlyid='my-provider'readonlyname='My Provider'readonlyenabled=true// Required: Base URL and headersreadonlyBASE_URL='https://provider.example.com'readonlyHEADERS={'User-Agent': 'Mozilla/5.0',Referer: 'https://provider.example.com',}// Required: Declare what this provider supportsreadonlycapabilities: ProviderCapabilities={supportedContentTypes: ['movies','tv'],}// Implement movie scrapingasyncgetMovieSources(media: ProviderMediaObject): Promise<ProviderResult>{this.console.log('Fetching movie sources',media)try{// Your scraping logic hereconststreamUrl=awaitthis.scrapeMovieUrl(media.tmdbId)// this is just some example functionreturn{sources: [{url: this.createProxyUrl(streamUrl,this.HEADERS),type: 'hls',quality: '1080p',audioTracks: [{language: 'en',label: 'English',},],provider: {id: this.id,name: this.name,},},],subtitles: [],diagnostics: [],}}catch(error){this.console.error('Failed to fetch sources',error,media)return{sources: [],subtitles: [],diagnostics: [{code: 'PROVIDER_ERROR',message: `${this.name} failed`,field: '',severity: 'error',},],}}}// Implement TV scrapingasyncgetTVSources(media: ProviderMediaObject): Promise<ProviderResult>{// Similar to getMovieSources but for TVreturn{sources: [],subtitles: [],diagnostics: []}}// Optional: Custom health checkasynchealthCheck(): Promise<boolean>{try{constresponse=awaitfetch(this.BASE_URL)returnresponse.ok}catch{returnfalse}}}

Full Provider Example

See the detailed Provider Creation Guide for a complete walkthrough.

To test a singulare Provider without setting up the whole server, you can use the following file, which will run the provider in isolation and allow you to test its functionality, without debugging the whole server.

import{ProviderMediaObject}from"@omss/framework"import{ExampleProvider}from"./example.js"constprov=newExampleProvider()constmediaObj: ProviderMediaObject={title: "The Dark Knight",tmdbId: "155",releaseYear: "2008",type: "movie",imdbId: "tt0468569"}constresp=awaitprov.getMovieSources(mediaObj)console.log(resp)

🧩 MCP Endpoints

The Model Context Protocol (MCP) is an optional JSON-RPC-like API that allows LLMs and other intelligent agents to interact with your OMSS server in a structured way. This can be useful for advanced integrations, such as allowing users to ask an AI assistant to find streaming sources for a movie or TV show.

When enabled, the MCP endpoint is exposed at /mcp (configurable) and accepts POST requests with a JSON body containing the method and parameters. The framework currently supports the following MCP method:

  • omss_get_sources: Fetches streaming sources for a movie or TV episode by TMDB ID. Parameters are the same as the regular API endpoints, but wrapped in an MCP request.

πŸ“‘ API Endpoints

GET /v1/movies/:tmdbId

Fetch streaming sources for a movie.

Parameters:

  • tmdbId (path): TMDB movie ID

Response:

{
"responseId": "uuid-v4",
"expiresAt": "2026-01-18T20:00:00.000Z",
"sources": [
{
"url": "/v1/proxy?data=...",
"type": "hls",
"quality": "1080p",
"audioTracks": [
{
"language": "en",
"label": "English"
}
],
"provider": {
"id": "vixsrc",
"name": "VixSrc"
}
}
],
"subtitles": [],
"diagnostics": []
}

GET /v1/tv/:tmdbId/seasons/:season/episodes/:episode

Fetch streaming sources for a TV episode.

Parameters:

  • tmdbId (path): TMDB series ID
  • season (path): Season number (0-99)
  • episode (path): Episode number (1-9999)

Response: Same structure as movies endpoint

GET /v1/proxy

Proxy streaming URLs with custom headers.

Query Parameters:

  • data (required): URL-encoded JSON containing:
    {
    "url": "https://stream.example.com/video.m3u8",
    "headers": {
    "Referer": "https://provider.example.com"
    }
    }

GET /v1/refresh/:responseId

Force refresh cached sources.

Parameters:

  • responseId (path): Response ID from previous request

GET /v1/health

Health check endpoint.

Response:

{
"status": "healthy",
"version": "1.0.0",
"providers": {
"total": 1,
"enabled": 1
}
}

🌍 Environment Variables

# Server ConfigurationPORT=3000# Port number for the serverHOST=0.0.0.0# Use 'localhost' to restrict to local accessNODE_ENV=development# 'development' | 'production'MCP_ENABLED=false# 'true' | 'false'# TMDB ConfigurationTMDB_API_KEY=your_tmdb_api_key_hereTMDB_CACHE_TTL=86400# Cache ConfigurationCACHE_TYPE=memory# 'memory' | 'redis'# Redis Configuration (if using Redis cache)REDIS_HOST=localhost# default Redis hostREDIS_PORT=6379# default Redis portREDIS_PASSWORD=# Redis password if required

πŸ“Ί Stremio Compatibility

Although the original OMSS standard was not specifically designed for Stremio, this framework is fully compatible with Stremio. In both ways:

  1. You can use this framework to build a Stremio Addon. To enable the Stremio Addon SDK, simply set the stremioAddon option to true in the server configuration. This will automatically add the required endpoints (/stremio/manifest.json) and response formatting to work seamlessly with Stremio.

  2. You can bind other Stremio Addon's directly to this framework. Since all Stremio Addons follow a standardized API, you can just pass the manifest URL of any Stremio Addon to the stremioAddons configuration option, and the framework will automatically fetch the manifest, extract the sources and bind them to your server. This allows you to easily aggregate sources from existing Stremio Addons alongside your custom providers, and expose them all through a single unified API.

πŸ—οΈ Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ OMSS Server β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ Controllers β”‚
β”‚ β”œβ”€β”€ ContentController (Movies/TV endpoints) β”‚
β”‚ β”œβ”€β”€ ProxyController (Streaming proxy) β”‚
β”‚ └── HealthController (Health checks) β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ Services β”‚
β”‚ β”œβ”€β”€ SourceService (Aggregates provider results) β”‚
β”‚ β”œβ”€β”€ TMDBService (Validates against TMDB) β”‚
β”‚ └── ProxyService (Handles URL proxying) β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ Provider Registry β”‚
β”‚ └── Manages all registered providers β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ Providers (Implement BaseProvider) β”‚
β”‚ β”œβ”€β”€ YourCustomProvider β”‚
β”‚ └── ... β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ Cache Layer β”‚
β”‚ β”œβ”€β”€ MemoryCache (Development) β”‚
β”‚ └── RedisCache (Production) β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

βœ… OMSS Compliance

This implementation follows the OMSS Standard:

  • βœ… Standardized Response Format: All responses follow OMSS schema
  • βœ… TMDB Validation: All requests validated against TMDB
  • βœ… Proxy Support: Required for all streaming URLs
  • βœ… Error Handling: OMSS-compliant error responses
  • βœ… Source Identification: Unique IDs for all sources
  • βœ… Audio Track Support: Multiple audio tracks per source
  • βœ… Subtitle Support: VTT/SRT subtitle formats
  • βœ… Quality Indicators: Resolution-based quality tags
  • βœ… Provider Attribution: Source provider identification
  • βœ… Diagnostics: Detailed error/warning information

πŸ“š Additional Resources

🀝 Contributing

Contributions are welcome! Please read our contributing guidelines before submitting PRs.

πŸ“„ License

MIT License - see LICENSE file for details.

πŸ™ Acknowledgments

  • All maintainers
  • OMSS standard contributors

About

πŸ› οΈ Official TypeScript framework for building OMSS-compliant streaming backends

Resources

Code of conduct

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages

, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

Repository files navigation

OMSS Framework

NPM VersionLicense: MITTypeScriptOMSS SpecNode.js

social preview

This is an extendable multi site scraping framework, which follows the implementation guidelines of the OMSS (Open Media Streaming Standard). It demonstrates how to build a compliant streaming media aggregation service that scrapes content from multiple providers and returns standardized responses. It handles most of the logic already for you. You just have to add the scraping logic!

Additionally, this is the worlds first AI-Enabled Streaming Framework! With built-in support for the Model Context Protocol (MCP), you can easily integrate LLMs and intelligent agents to find streaming sources using natural language queries, or even automate the management of your streaming backend using AI assistants.



🎯 What is OMSS?

OMSS is an open standard for streaming media aggregation. It provides a unified API for fetching movie and TV show streaming sources from multiple providers, with built-in proxy support, subtitle handling, and quality selection.

πŸ” What is the @omss/framework?

The @omss/framework is the official TypeScript/Node.js implementation framework that makes building OMSS-compliant backends effortless. Instead of manually implementing the standard from scratch, developers can focus solely on writing provider scraping logic while the framework handles all the boilerplate β€” routing, validation, proxy management, caching, error handling, and response formatting.

Key Features

  • βœ… Standardized API: Consistent response format across all providers
  • βœ… MCP Support: Optional Model Context Protocol endpoint for LLM integration
  • βœ… Stremio Compatibility: Designed to work seamlessly with Stremio Addons and also support Stremio Addon SDK
  • βœ… Multi-Provider Support: Aggregate sources from multiple streaming providers
  • βœ… Built-in Proxy: Automatic URL proxying with header forwarding
  • βœ… TMDB Integration: Validation against The Movie Database
  • βœ… Caching Layer: Redis or in-memory caching for performance
  • βœ… Type Safety: Full TypeScript support
  • βœ… Provider Management: Easy enable/disable, automatic discovery
  • βœ… Health Checks: Monitor provider availability
  • βœ… Refresh API: Force cache invalidation when needed

πŸ“‹ Table of Contents

πŸš€ Installation

There is a template which you can use to easily create your own streaming backend. Check it out here!This is the easiest way to create your own OMSS backend.

Prerequisites

  • Node.js 18.x or higher
  • npm or yarn
  • TMDB API Key (Get one here)
  • (Optional) Redis server for caching

Install Dependencies

# npm
npm install @omss/framework
# yarn
yarn add @omss/framework
# pnpm
pnpm add @omss/framework

πŸš€ Quick start

Minimal example using the built‑in provider and in‑memory cache:

// src/server.tsimport{OMSSServer}from'@omss/framework'import{ExampleProvider}from'./src/providers/implementations/example-provider'// Create server instanceconstserver=newOMSSServer({name: 'My OMSS Backend',version: '1.0.0',host: 'localhost',port: 3000,cache: {type: 'memory',ttl: {sources: 7200,subtitles: 7200,},},tmdb: {apiKey: process.env.TMDB_API_KEY,cacheTTL: 86400,},proxyConfig: {knownThirdPartyProxies: {'hls1.vid1.site': [/\/proxy\/(.+)$/],'madplay.site': [/\/api\/[^/]+\/proxy\?url=(.+)$/],'*': [/\/proxy\/(.+)$/,/\/m3u8-proxy\?url=(.+?)(&|$)/],},streamPatterns: [/^https?:\/\/.+\.(mp4)(\?.*)?$/],// treat direct mp4 links as streams that need proxying. You can also add custom domains that should be streamed through the proxy.},// You can override the default cors settings, by passing your own fastify cors options here. By default, it allows all origins./* cors: { origin: '*', methods: ['GET', 'OPTIONS', 'HEAD'], allowedHeaders: ['Content-Type', 'Authorization', 'Range', 'Accept'], exposedHeaders: ['Content-Length', 'Content-Type', 'Content-Range', 'Accept-Ranges'], }, */})// Register providersconstregistry=server.getRegistry()registry.register(newExampleProvider())// or use the very cool auto-discovery feature// registry.discoverProviders('./path/to/providerfolder');// Note: this is relative to *where you start the server*.// before starting the server, you can also modify any fastify instance settings, by getting the instance via server.getFastifyInstance() and calling any of its methods. For example, to add a custom route:// Start serverawaitserver.start()

.env:

# Server ConfigurationPORT=3000# Port number for the serverHOST=0.0.0.0# Use 'localhost' to restrict to local accessNODE_ENV=development# 'development' | 'production'# TMDB ConfigurationTMDB_API_KEY=your_tmdb_api_key_hereTMDB_CACHE_TTL=86400# Cache ConfigurationCACHE_TYPE=memory# 'memory' | 'redis'# Redis Configuration (if using Redis cache)REDIS_HOST=localhost# default Redis hostREDIS_PORT=6379# default Redis portREDIS_PASSWORD=# Redis password if required

Run in dev:

npm run dev

And then it should work!

βš™οΈ Configuration

Server Configuration Options

interfaceOMSSConfig{// Required: Server identificationname: string// Your server nameversion: string// OMSS Spec version// Optional: Network settingshost?: string// Default: 'localhost'port?: number// Default: 3000publicUrl?: string// For reverse proxy setups// Optional: Cache configurationcache?: {type: 'memory'|'redis'ttl: {sources: numbersubtitles: number}redis?: {host: stringport: numberpassword?: string}}// Required: TMDB configurationtmdb?: {apiKey?: string// Can also use TMDB_API_KEY env varcacheTTL?: number// Default: 86400 (24 hours)}// Proxy configurationproxyConfig?: {knownThirdPartyProxies: Record<string,RegExp[]>// for this, see the documentation in docs/third-party-pattern-config.mdstreamPatterns: RegExp[]// Optional: Custom patterns to identify streaming URLs that need proxying}// Optional: CORS configuration (overrides default)cors?: {origin: stringmethods: string[]allowedHeaders: string[]exposedHeaders: string[]}}

Example Configurations

Development

constserver=newOMSSServer({name: 'OMSS Dev Server',version: '1.0.0',host: 'localhost',port: 3000,cache: {type: 'memory',ttl: {sources: 7200,subtitles: 7200,},},tmdb: {apiKey: process.env.TMDB_API_KEY,cacheTTL: 86400,},proxyConfig: {knownThirdPartyProxies: {},// for this, see the documentation in docs/third-party-pattern-config.mdstreamPatterns: [/^https?:\/\/.+\.(mp4)(\?.*)?$/],// treat direct mp4 links as streams that need proxying. You can also add custom domains that should be streamed through the proxy.},})

Production with Redis

constserver=newOMSSServer({name: 'OMSS Production',version: '1.0.0',host: '0.0.0.0',port: 3000,publicUrl: 'https://api.mystream.com',cache: {type: 'redis',ttl: {sources: 7200,subtitles: 7200,},redis: {host: process.env.REDIS_HOST||'localhost',port: parseInt(process.env.REDIS_PORT||'6379'),password: process.env.REDIS_PASSWORD,},},tmdb: {apiKey: process.env.TMDB_API_KEY,cacheTTL: 86400,},proxyConfig: {knownThirdPartyProxies: {},// for this, see the documentation in docs/third-party-pattern-config.mdstreamPatterns: [/^https?:\/\/.+\.(mp4)(\?.*)?$/],// treat direct mp4 links as streams that need proxying. You can also add custom domains that should be streamed through the proxy.},cors: {origin: 'https://myapp.com',methods: ['GET','OPTIONS'],allowedHeaders: ['Content-Type','Authorization'],exposedHeaders: ['Content-Length','Content-Type'],},})

Behind Reverse Proxy

constserver=newOMSSServer({name: 'OMSS API',version: '1.0.0',host: '0.0.0.0',port: 3000,// This is the public URL clients will usepublicUrl: 'https://myapp.com/api',cache: {type: 'redis',redis: {host: 'redis.internal',port: 6379,},},tmdb: {apiKey: process.env.TMDB_API_KEY,cacheTTL: 86400,},proxyConfig: {knownThirdPartyProxies: {},// for this, see the documentation in docs/third-party-pattern-config.mdstreamPatterns: [/^https?:\/\/.+\.(mp4)(\?.*)?$/],// treat direct mp4 links as streams that need proxying. You can also add custom domains that should be streamed through the proxy.},cors: {origin: 'https://myapp.com',methods: ['GET','OPTIONS'],allowedHeaders: ['Content-Type','Authorization'],exposedHeaders: ['Content-Length','Content-Type'],},})

πŸ”Œ Creating Custom Providers

See the detailed Provider Creation Guide for a complete walkthrough.

Quick Start with Auto-Discovery

The easiest way to add a new provider:

  1. Create a directory for all of your provider files

    touch src/providers/implementations/my-provider.ts
  2. Implement the BaseProvider class (see example below) in each file.

  3. In the Setup, use the discoverProviders method of the ProviderRegistry to load all providers from that directory:

    constregistry=server.getRegistry()registry.discoverProviders('./src/providers/implementations')// relative to where you start the server from
  4. That's it! The provider will be automatically discovered and registered when you start the server!

No imports, no manual registration needed!

Minimal Provider Example

import{BaseProvider}from'./src/providers/base-provider'import{ProviderCapabilities,ProviderMediaObject,ProviderResult}from'./src/core/types'exportclassMyProviderextendsBaseProvider{// Required: Provider identificationreadonlyid='my-provider'readonlyname='My Provider'readonlyenabled=true// Required: Base URL and headersreadonlyBASE_URL='https://provider.example.com'readonlyHEADERS={'User-Agent': 'Mozilla/5.0',Referer: 'https://provider.example.com',}// Required: Declare what this provider supportsreadonlycapabilities: ProviderCapabilities={supportedContentTypes: ['movies','tv'],}// Implement movie scrapingasyncgetMovieSources(media: ProviderMediaObject): Promise<ProviderResult>{this.console.log('Fetching movie sources',media)try{// Your scraping logic hereconststreamUrl=awaitthis.scrapeMovieUrl(media.tmdbId)// this is just some example functionreturn{sources: [{url: this.createProxyUrl(streamUrl,this.HEADERS),type: 'hls',quality: '1080p',audioTracks: [{language: 'en',label: 'English',},],provider: {id: this.id,name: this.name,},},],subtitles: [],diagnostics: [],}}catch(error){this.console.error('Failed to fetch sources',error,media)return{sources: [],subtitles: [],diagnostics: [{code: 'PROVIDER_ERROR',message: `${this.name} failed`,field: '',severity: 'error',},],}}}// Implement TV scrapingasyncgetTVSources(media: ProviderMediaObject): Promise<ProviderResult>{// Similar to getMovieSources but for TVreturn{sources: [],subtitles: [],diagnostics: []}}// Optional: Custom health checkasynchealthCheck(): Promise<boolean>{try{constresponse=awaitfetch(this.BASE_URL)returnresponse.ok}catch{returnfalse}}}

Full Provider Example

See the detailed Provider Creation Guide for a complete walkthrough.

To test a singulare Provider without setting up the whole server, you can use the following file, which will run the provider in isolation and allow you to test its functionality, without debugging the whole server.

import{ProviderMediaObject}from"@omss/framework"import{ExampleProvider}from"./example.js"constprov=newExampleProvider()constmediaObj: ProviderMediaObject={title: "The Dark Knight",tmdbId: "155",releaseYear: "2008",type: "movie",imdbId: "tt0468569"}constresp=awaitprov.getMovieSources(mediaObj)console.log(resp)

🧩 MCP Endpoints

The Model Context Protocol (MCP) is an optional JSON-RPC-like API that allows LLMs and other intelligent agents to interact with your OMSS server in a structured way. This can be useful for advanced integrations, such as allowing users to ask an AI assistant to find streaming sources for a movie or TV show.

When enabled, the MCP endpoint is exposed at /mcp (configurable) and accepts POST requests with a JSON body containing the method and parameters. The framework currently supports the following MCP method:

  • omss_get_sources: Fetches streaming sources for a movie or TV episode by TMDB ID. Parameters are the same as the regular API endpoints, but wrapped in an MCP request.

πŸ“‘ API Endpoints

GET /v1/movies/:tmdbId

Fetch streaming sources for a movie.

Parameters:

  • tmdbId (path): TMDB movie ID

Response:

{
"responseId": "uuid-v4",
"expiresAt": "2026-01-18T20:00:00.000Z",
"sources": [
{
"url": "/v1/proxy?data=...",
"type": "hls",
"quality": "1080p",
"audioTracks": [
{
"language": "en",
"label": "English"
}
],
"provider": {
"id": "vixsrc",
"name": "VixSrc"
}
}
],
"subtitles": [],
"diagnostics": []
}

GET /v1/tv/:tmdbId/seasons/:season/episodes/:episode

Fetch streaming sources for a TV episode.

Parameters:

  • tmdbId (path): TMDB series ID
  • season (path): Season number (0-99)
  • episode (path): Episode number (1-9999)

Response: Same structure as movies endpoint

GET /v1/proxy

Proxy streaming URLs with custom headers.

Query Parameters:

  • data (required): URL-encoded JSON containing:
    {
    "url": "https://stream.example.com/video.m3u8",
    "headers": {
    "Referer": "https://provider.example.com"
    }
    }

GET /v1/refresh/:responseId

Force refresh cached sources.

Parameters:

  • responseId (path): Response ID from previous request

GET /v1/health

Health check endpoint.

Response:

{
"status": "healthy",
"version": "1.0.0",
"providers": {
"total": 1,
"enabled": 1
}
}

🌍 Environment Variables

# Server ConfigurationPORT=3000# Port number for the serverHOST=0.0.0.0# Use 'localhost' to restrict to local accessNODE_ENV=development# 'development' | 'production'MCP_ENABLED=false# 'true' | 'false'# TMDB ConfigurationTMDB_API_KEY=your_tmdb_api_key_hereTMDB_CACHE_TTL=86400# Cache ConfigurationCACHE_TYPE=memory# 'memory' | 'redis'# Redis Configuration (if using Redis cache)REDIS_HOST=localhost# default Redis hostREDIS_PORT=6379# default Redis portREDIS_PASSWORD=# Redis password if required

πŸ“Ί Stremio Compatibility

Although the original OMSS standard was not specifically designed for Stremio, this framework is fully compatible with Stremio. In both ways:

  1. You can use this framework to build a Stremio Addon. To enable the Stremio Addon SDK, simply set the stremioAddon option to true in the server configuration. This will automatically add the required endpoints (/stremio/manifest.json) and response formatting to work seamlessly with Stremio.

  2. You can bind other Stremio Addon's directly to this framework. Since all Stremio Addons follow a standardized API, you can just pass the manifest URL of any Stremio Addon to the stremioAddons configuration option, and the framework will automatically fetch the manifest, extract the sources and bind them to your server. This allows you to easily aggregate sources from existing Stremio Addons alongside your custom providers, and expose them all through a single unified API.

πŸ—οΈ Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ OMSS Server β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ Controllers β”‚
β”‚ β”œβ”€β”€ ContentController (Movies/TV endpoints) β”‚
β”‚ β”œβ”€β”€ ProxyController (Streaming proxy) β”‚
β”‚ └── HealthController (Health checks) β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ Services β”‚
β”‚ β”œβ”€β”€ SourceService (Aggregates provider results) β”‚
β”‚ β”œβ”€β”€ TMDBService (Validates against TMDB) β”‚
β”‚ └── ProxyService (Handles URL proxying) β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ Provider Registry β”‚
β”‚ └── Manages all registered providers β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ Providers (Implement BaseProvider) β”‚
β”‚ β”œβ”€β”€ YourCustomProvider β”‚
β”‚ └── ... β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ Cache Layer β”‚
β”‚ β”œβ”€β”€ MemoryCache (Development) β”‚
β”‚ └── RedisCache (Production) β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

βœ… OMSS Compliance

This implementation follows the OMSS Standard:

  • βœ… Standardized Response Format: All responses follow OMSS schema
  • βœ… TMDB Validation: All requests validated against TMDB
  • βœ… Proxy Support: Required for all streaming URLs
  • βœ… Error Handling: OMSS-compliant error responses
  • βœ… Source Identification: Unique IDs for all sources
  • βœ… Audio Track Support: Multiple audio tracks per source
  • βœ… Subtitle Support: VTT/SRT subtitle formats
  • βœ… Quality Indicators: Resolution-based quality tags
  • βœ… Provider Attribution: Source provider identification
  • βœ… Diagnostics: Detailed error/warning information

πŸ“š Additional Resources

🀝 Contributing

Contributions are welcome! Please read our contributing guidelines before submitting PRs.

πŸ“„ License

MIT License - see LICENSE file for details.

πŸ™ Acknowledgments

  • All maintainers
  • OMSS standard contributors

About

πŸ› οΈ Official TypeScript framework for building OMSS-compliant streaming backends

Resources

Code of conduct

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages