Self-hosted sports calendar and stream orchestrator for Nuvio and Stremio, with per-user TorBox, Usenet Ultimate, and Easynews playback.
JavaScript
20
261 commits
updated Sep 24, 2026
A self-hosted sports calendar and stream orchestrator for Nuvio, Stremio, and other Stremio-compatible clients.
SeriousSportSync turns sports events into proper catalog items with dates, artwork, metadata, and optional playback results. It is primarily designed for Nuvio, and also works with Stremio and compatible clients.
It hosts no media. Every playback connector is optional, self-hosted or user-supplied, and remains under the operator's control.
For a fresh server, follow the installation and recovery guide. It covers Docker installation files, secret generation, LAN access, first login, verification, updates, backups, rebuilding, and common failures.
The shortest path is:
docker-compose.yml and .env.example into a new directory..env.example to .env and set one value: SESSION_SECRET.SSS_BIND_ADDRESS only if another device must reach the server directly.docker compose up -d, create the admin account, then work through
Configure, which ends with the manifest URL to paste into your client.The minimal environment example contains only first-install choices. Advanced overrides are kept in the configuration reference.
Twenty-five promotions ship built in. Most need no API key; the exceptions are noted below. Each account can also add team catalogs from Your teams without exposing every available club as a normal catalog.
Combat sports and entertainment
| Promotion | Coverage |
|---|---|
| UFC | PPVs, Fight Nights, UFC on ABC/ESPN, DWCS |
| ONE Championship | Numbered events, Fight Night, Friday Fights |
| WWE | PLEs, named NXT events, Saturday Night's Main Event |
| WWE Raw, SmackDown and NXT | Weekly television episodes with exact local air dates |
| AEW | PPVs and special events from the official AEW schedule |
| AEW Dynamite and Collision | Weekly television episodes, including targeted recovery for gaps in TheSportsDB's free feeds |
| Boxing | Cards from major promoters |
Motorsport
| Promotion | Coverage |
|---|---|
| Formula 1 | Race, qualifying, sprint, sprint qualifying, and practice sessions; Formula 2 and Formula 3 are excluded |
| MotoGP | Race, qualifying, sprint, and per-round sessions, including combined full-weekend releases |
Football
| Promotion | Source | Coverage |
|---|---|---|
| UEFA Champions League | Official UEFA feed | Fixtures with full club identities and release-aware searches |
| Premier League | football-data.org | Fixtures, club alias table, three-letter code matching |
| Match of the Day | TMDB | Episodes; needs a free TMDB key |
Premier League needs a free football-data.org key and Match of the Day needs a TMDB key. Both are set on Metadata, where a saved key overrides the matching environment variable. A provider failure affects only assigned promotions and leaves the rest working.
North American sport
| Promotion | Source | Coverage |
|---|---|---|
| NFL | ESPN | Fixtures, Away at Home naming |
| NBA | ESPN | Fixtures |
| MLB | Official MLB schedule | Regular-season date and Away @ Home searches |
Discovered sports
Seven further promotions β Rugby, Football, Basketball, Baseball, American Football, Hockey and Other Sport β are built the other way round. A Sport-Video release that matches no fixture from any feed becomes an event of its own, so content that would otherwise be found and discarded still reaches a catalog. Metadata is weak by construction: the name is parsed from the release title and the date is when the site published it. Where a real feed claims the fixture, the feed always wins and the release never reaches ingestion.
Custom promotions
Anything else can be created from the admin UI on top of official UEFA, API-Football, the official MLB schedule, TheSportsDB, football-data.org, TMDB, ONE, or a custom JSON/API catalog.
Playback is optional. SeriousSportSync can combine multiple pipelines and returns only the rows that finish within the configured request budget.
Discovery and playback are separate jobs. A discovery source answers "what releases exist for this event"; a playback service answers "can this account actually play it". Sources are deliberately allowed to over-fetch, because the promotion matcher is far better at rejecting a wrong release than any query string is.
| Source | How it works |
|---|---|
| Direct Bitmagnet | Queries a self-hosted Bitmagnet index over GraphQL. One local database rather than a fan-out to remote trackers, so a query costs tens of milliseconds; results are ordered by seeders server-side, and info hashes arrive directly with no hydration pass |
| Direct Prowlarr | A measured background queue searches selected promotions slowly, saves seeded matches locally, tracks per-indexer budgets and cooldowns, and serves the saved database during playback. Live playback search has a separate switch; Improve Matching can still search Prowlarr when that switch is off |
| Companion scraper | Combines Prowlarr, Zilean, Torznab, and other sources configured in the separate companion service |
| Sport-Video | Reads the public RSS and bounded sport category catalogues, matches releases against existing events before downloading any torrent metadata, then validates same-origin detail pages and bounded bencoded torrent files |
The four source connections sit under Server β Discovery pipelines and keep their settings when disabled. Their automatic work is controlled from the source tabs in Discovery: Prowlarr, Sport-Video and Bitmagnet each have their own promotion selection. Sport-Video is off on a fresh install because it polls a third-party site on a schedule.
Torrent results are checked against each user's TorBox account and resolved on play. Discovery never adds content to TorBox automatically; an uncached release is submitted only when a user selects Warm to TorBox.
| Source | Playback | How it works |
|---|---|---|
| Native Newznab, NZBHydra, or Prowlarr | Built-in Usenet (native NNTP) | SSS searches the indexer directly, filters candidates once, and streams the matched release straight from your NNTP provider β no helper container |
| Easynews | Easynews | Searches and plays with credentials stored on the user's account |
Built-in Usenet is one pipeline: a native indexer connection for discovery and a direct NNTP provider connection for playback. The admin Usenet page presents this as two stages β search and candidate discovery, then native NNTP playback. It owns the indexer and NNTP credentials, native performance profiles, connection state, first-byte timing, throughput, retries and recent playback results; Configure keeps the master pipeline switch. A usable pipeline requires a ready indexer and a ready NNTP provider. New NNTP configurations default to 20 connections, pre-authenticate their pool after resolution, fetch one segment for startup and then pipeline a bounded read-ahead window. The page offers Balanced, Low latency and Resilient profiles plus bounded advanced controls. Native NNTP serves direct videos and stored, unencrypted RAR4/RAR5 videos with HTTP byte ranges.
The local Smart Availability Index stores encrypted, normalized discoveries in SQLite. Fresh torrent, native indexer, and Easynews searches are reused; TorBox cache observations stay isolated by account credentials. The bounded general preparation job is Bitmagnet-only. Prowlarr has its measured queue and Sport-Video has its own sequential preparation worker. Built-in Usenet and Easynews remain fast live responders and create no background indexer traffic.
Provider credentials, admin source keys, and private install tokens are encrypted at rest and are never included in the stream list returned to the client; existing plaintext settings are migrated automatically. TorBox, Easynews, and Built-in Usenet use signed, short-lived resolve URLs. A private manifest URL grants use, not editing access, and can be rotated.
docker compose pull
docker compose up -d --remove-orphans
The default Compose port is bound to 127.0.0.1. Set
SSS_BIND_ADDRESS to the server's LAN IP for trusted LAN access, or
put a tunnel or authenticated reverse proxy in front. Do not expose port 7000
directly to the Internet. Preserve SESSION_SECRET across updates.
The named volume preserves accounts, event data, settings, custom promotions, Nuvio collection layouts, and matching overrides across container replacements.
Metadata sources -> event catalog -> promotion-aware matching -> stream rows
| |
| +-> per-user playback service
+-> noise, year, date, round, and session filters
Bitmagnet answers live requests from its local index and is also prepared in bounded background batches. Direct Prowlarr normally serves the matches its measured queue saved; the operator can separately enable live playback search. The companion remains request-driven and is useful when several private discovery sources need to be combined behind one endpoint.
Configure is the signed-in user's own page, and it is five steps over a single form β nothing is saved until the whole form is saved, and a returning user can jump straight to any step.
The web interface is designed so routine operation does not require editing JSON or application code. Changes take effect without rebuilding the image.
.log or structured .ndjson output.Source refreshes can replace their event cache without overwriting saved promotions, aliases, exclusions, disabled-event decisions, or matching rules.
Start with the short .env.example. The annotated configuration reference contains advanced variables.
| Variable | Default | Purpose |
|---|---|---|
SESSION_SECRET | required | Signs login cookies; use at least 32 random characters |
ADMIN_USER | none | Username promoted to administrator during initial signup |
PUBLIC_URL | auto-detected | Public origin used for private install and resolve URLs |
TRUST_PROXY | false | Set to 1 only when SSS is exclusively behind your trusted reverse proxy/tunnel; enables forwarded client IP, host, protocol, and secure-cookie handling |
REFRESH_INTERVAL_HOURS | 6 | Metadata refresh interval |
AVAILABILITY_DB_FILE | ./data/availability.sqlite | Encrypted reusable provider searches, event/release matches, card-part classification, and scoped availability observations |
AVAILABILITY_WARM_ENABLED | true | Proactively populate selected recent events from Bitmagnet in the background |
AVAILABILITY_SERVE_CONFIRMED | true | Reuse fresh, account-scoped confirmed results before repeating provider discovery |
BITMAGNET_URL | none | Optional direct Bitmagnet discovery; /graphql is appended automatically |
BITMAGNET_LIMIT | 300 | Results per Bitmagnet query |
COMPANION_URL | none | Optional SeriousSportSync-Scraper companion endpoint |
PROWLARR_URL / PROWLARR_API_KEY | none | Optional direct Prowlarr discovery |
Server-wide discovery credentials belong in Server or the root environment; companion-managed sources belong in the companion's own settings. Each playback pipeline has an independent enable switch, so it can be excluded without deleting credentials. Disabling UU stream rows does not disable the optional UU text search used by the DIY pipeline.
Running from source requires Node.js 22 or newer. The supplied container builds and runs on Node.js 24.
Build the local checkout with the development override:
docker compose -f docker-compose.yml -f docker-compose.dev.yml up -d --build
Run the unit suite with npm run test:unit. It uses the Node test runner and
needs no services; the suite is expected to pass on Windows as well as Linux.
For a bespoke built-in promotion, add a self-contained definition to
lib/promotions.js. Simple metadata-backed sports should normally be
added from the Promotions creator instead.
Pull requests run JavaScript/module-load validation and a Docker Compose smoke
deployment. Merges to main publish the public container image to
GHCR and test that image through Compose.
The deployment threat model, trusted-proxy guidance, encrypted data inventory, and reporting process are documented in Security. Planned work is listed in the roadmap, and the changelog records why each release changed what it did.
SeriousSportSync is a metadata catalog and stream orchestrator published for educational and personal self-hosting use. It hosts no content, includes no third-party credentials, and is not affiliated with any sport, league, broadcaster, indexer, debrid provider, or media service. Operators are responsible for complying with applicable laws and service terms.
255 commits
6 commits
JavaScript
98.9%
Self-hosted sports calendar and stream orchestrator for Nuvio and Stremio, with per-user TorBox, Usenet Ultimate, and Easynews playback.
JavaScript
20
261 commits
updated Sep 24, 2026
A self-hosted sports calendar and stream orchestrator for Nuvio, Stremio, and other Stremio-compatible clients.
SeriousSportSync turns sports events into proper catalog items with dates, artwork, metadata, and optional playback results. It is primarily designed for Nuvio, and also works with Stremio and compatible clients.
It hosts no media. Every playback connector is optional, self-hosted or user-supplied, and remains under the operator's control.
For a fresh server, follow the installation and recovery guide. It covers Docker installation files, secret generation, LAN access, first login, verification, updates, backups, rebuilding, and common failures.
The shortest path is:
docker-compose.yml and .env.example into a new directory..env.example to .env and set one value: SESSION_SECRET.SSS_BIND_ADDRESS only if another device must reach the server directly.docker compose up -d, create the admin account, then work through
Configure, which ends with the manifest URL to paste into your client.The minimal environment example contains only first-install choices. Advanced overrides are kept in the configuration reference.
Twenty-five promotions ship built in. Most need no API key; the exceptions are noted below. Each account can also add team catalogs from Your teams without exposing every available club as a normal catalog.
Combat sports and entertainment
| Promotion | Coverage |
|---|---|
| UFC | PPVs, Fight Nights, UFC on ABC/ESPN, DWCS |
| ONE Championship | Numbered events, Fight Night, Friday Fights |
| WWE | PLEs, named NXT events, Saturday Night's Main Event |
| WWE Raw, SmackDown and NXT | Weekly television episodes with exact local air dates |
| AEW | PPVs and special events from the official AEW schedule |
| AEW Dynamite and Collision | Weekly television episodes, including targeted recovery for gaps in TheSportsDB's free feeds |
| Boxing | Cards from major promoters |
Motorsport
| Promotion | Coverage |
|---|---|
| Formula 1 | Race, qualifying, sprint, sprint qualifying, and practice sessions; Formula 2 and Formula 3 are excluded |
| MotoGP | Race, qualifying, sprint, and per-round sessions, including combined full-weekend releases |
Football
| Promotion | Source | Coverage |
|---|---|---|
| UEFA Champions League | Official UEFA feed | Fixtures with full club identities and release-aware searches |
| Premier League | football-data.org | Fixtures, club alias table, three-letter code matching |
| Match of the Day | TMDB | Episodes; needs a free TMDB key |
Premier League needs a free football-data.org key and Match of the Day needs a TMDB key. Both are set on Metadata, where a saved key overrides the matching environment variable. A provider failure affects only assigned promotions and leaves the rest working.
North American sport
| Promotion | Source | Coverage |
|---|---|---|
| NFL | ESPN | Fixtures, Away at Home naming |
| NBA | ESPN | Fixtures |
| MLB | Official MLB schedule | Regular-season date and Away @ Home searches |
Discovered sports
Seven further promotions β Rugby, Football, Basketball, Baseball, American Football, Hockey and Other Sport β are built the other way round. A Sport-Video release that matches no fixture from any feed becomes an event of its own, so content that would otherwise be found and discarded still reaches a catalog. Metadata is weak by construction: the name is parsed from the release title and the date is when the site published it. Where a real feed claims the fixture, the feed always wins and the release never reaches ingestion.
Custom promotions
Anything else can be created from the admin UI on top of official UEFA, API-Football, the official MLB schedule, TheSportsDB, football-data.org, TMDB, ONE, or a custom JSON/API catalog.
Playback is optional. SeriousSportSync can combine multiple pipelines and returns only the rows that finish within the configured request budget.
Discovery and playback are separate jobs. A discovery source answers "what releases exist for this event"; a playback service answers "can this account actually play it". Sources are deliberately allowed to over-fetch, because the promotion matcher is far better at rejecting a wrong release than any query string is.
| Source | How it works |
|---|---|
| Direct Bitmagnet | Queries a self-hosted Bitmagnet index over GraphQL. One local database rather than a fan-out to remote trackers, so a query costs tens of milliseconds; results are ordered by seeders server-side, and info hashes arrive directly with no hydration pass |
| Direct Prowlarr | A measured background queue searches selected promotions slowly, saves seeded matches locally, tracks per-indexer budgets and cooldowns, and serves the saved database during playback. Live playback search has a separate switch; Improve Matching can still search Prowlarr when that switch is off |
| Companion scraper | Combines Prowlarr, Zilean, Torznab, and other sources configured in the separate companion service |
| Sport-Video | Reads the public RSS and bounded sport category catalogues, matches releases against existing events before downloading any torrent metadata, then validates same-origin detail pages and bounded bencoded torrent files |
The four source connections sit under Server β Discovery pipelines and keep their settings when disabled. Their automatic work is controlled from the source tabs in Discovery: Prowlarr, Sport-Video and Bitmagnet each have their own promotion selection. Sport-Video is off on a fresh install because it polls a third-party site on a schedule.
Torrent results are checked against each user's TorBox account and resolved on play. Discovery never adds content to TorBox automatically; an uncached release is submitted only when a user selects Warm to TorBox.
| Source | Playback | How it works |
|---|---|---|
| Native Newznab, NZBHydra, or Prowlarr | Built-in Usenet (native NNTP) | SSS searches the indexer directly, filters candidates once, and streams the matched release straight from your NNTP provider β no helper container |
| Easynews | Easynews | Searches and plays with credentials stored on the user's account |
Built-in Usenet is one pipeline: a native indexer connection for discovery and a direct NNTP provider connection for playback. The admin Usenet page presents this as two stages β search and candidate discovery, then native NNTP playback. It owns the indexer and NNTP credentials, native performance profiles, connection state, first-byte timing, throughput, retries and recent playback results; Configure keeps the master pipeline switch. A usable pipeline requires a ready indexer and a ready NNTP provider. New NNTP configurations default to 20 connections, pre-authenticate their pool after resolution, fetch one segment for startup and then pipeline a bounded read-ahead window. The page offers Balanced, Low latency and Resilient profiles plus bounded advanced controls. Native NNTP serves direct videos and stored, unencrypted RAR4/RAR5 videos with HTTP byte ranges.
The local Smart Availability Index stores encrypted, normalized discoveries in SQLite. Fresh torrent, native indexer, and Easynews searches are reused; TorBox cache observations stay isolated by account credentials. The bounded general preparation job is Bitmagnet-only. Prowlarr has its measured queue and Sport-Video has its own sequential preparation worker. Built-in Usenet and Easynews remain fast live responders and create no background indexer traffic.
Provider credentials, admin source keys, and private install tokens are encrypted at rest and are never included in the stream list returned to the client; existing plaintext settings are migrated automatically. TorBox, Easynews, and Built-in Usenet use signed, short-lived resolve URLs. A private manifest URL grants use, not editing access, and can be rotated.
docker compose pull
docker compose up -d --remove-orphans
The default Compose port is bound to 127.0.0.1. Set
SSS_BIND_ADDRESS to the server's LAN IP for trusted LAN access, or
put a tunnel or authenticated reverse proxy in front. Do not expose port 7000
directly to the Internet. Preserve SESSION_SECRET across updates.
The named volume preserves accounts, event data, settings, custom promotions, Nuvio collection layouts, and matching overrides across container replacements.
Metadata sources -> event catalog -> promotion-aware matching -> stream rows
| |
| +-> per-user playback service
+-> noise, year, date, round, and session filters
Bitmagnet answers live requests from its local index and is also prepared in bounded background batches. Direct Prowlarr normally serves the matches its measured queue saved; the operator can separately enable live playback search. The companion remains request-driven and is useful when several private discovery sources need to be combined behind one endpoint.
Configure is the signed-in user's own page, and it is five steps over a single form β nothing is saved until the whole form is saved, and a returning user can jump straight to any step.
The web interface is designed so routine operation does not require editing JSON or application code. Changes take effect without rebuilding the image.
.log or structured .ndjson output.Source refreshes can replace their event cache without overwriting saved promotions, aliases, exclusions, disabled-event decisions, or matching rules.
Start with the short .env.example. The annotated configuration reference contains advanced variables.
| Variable | Default | Purpose |
|---|---|---|
SESSION_SECRET | required | Signs login cookies; use at least 32 random characters |
ADMIN_USER | none | Username promoted to administrator during initial signup |
PUBLIC_URL | auto-detected | Public origin used for private install and resolve URLs |
TRUST_PROXY | false | Set to 1 only when SSS is exclusively behind your trusted reverse proxy/tunnel; enables forwarded client IP, host, protocol, and secure-cookie handling |
REFRESH_INTERVAL_HOURS | 6 | Metadata refresh interval |
AVAILABILITY_DB_FILE | ./data/availability.sqlite | Encrypted reusable provider searches, event/release matches, card-part classification, and scoped availability observations |
AVAILABILITY_WARM_ENABLED | true | Proactively populate selected recent events from Bitmagnet in the background |
AVAILABILITY_SERVE_CONFIRMED | true | Reuse fresh, account-scoped confirmed results before repeating provider discovery |
BITMAGNET_URL | none | Optional direct Bitmagnet discovery; /graphql is appended automatically |
BITMAGNET_LIMIT | 300 | Results per Bitmagnet query |
COMPANION_URL | none | Optional SeriousSportSync-Scraper companion endpoint |
PROWLARR_URL / PROWLARR_API_KEY | none | Optional direct Prowlarr discovery |
Server-wide discovery credentials belong in Server or the root environment; companion-managed sources belong in the companion's own settings. Each playback pipeline has an independent enable switch, so it can be excluded without deleting credentials. Disabling UU stream rows does not disable the optional UU text search used by the DIY pipeline.
Running from source requires Node.js 22 or newer. The supplied container builds and runs on Node.js 24.
Build the local checkout with the development override:
docker compose -f docker-compose.yml -f docker-compose.dev.yml up -d --build
Run the unit suite with npm run test:unit. It uses the Node test runner and
needs no services; the suite is expected to pass on Windows as well as Linux.
For a bespoke built-in promotion, add a self-contained definition to
lib/promotions.js. Simple metadata-backed sports should normally be
added from the Promotions creator instead.
Pull requests run JavaScript/module-load validation and a Docker Compose smoke
deployment. Merges to main publish the public container image to
GHCR and test that image through Compose.
The deployment threat model, trusted-proxy guidance, encrypted data inventory, and reporting process are documented in Security. Planned work is listed in the roadmap, and the changelog records why each release changed what it did.
SeriousSportSync is a metadata catalog and stream orchestrator published for educational and personal self-hosting use. It hosts no content, includes no third-party credentials, and is not affiliated with any sport, league, broadcaster, indexer, debrid provider, or media service. Operators are responsible for complying with applicable laws and service terms.
255 commits
6 commits
JavaScript
98.9%