A fully modernized, asynchronous Python framework for building awesome Stremio Addons with ease.
python-stremio drops confusing legacy architectures in favor of a sleek, type-safe, routing-based approach—feeling right at home if you've developed using frameworks like FastAPI or Starlette.
- Modern Routing Architecture: Built with a decorator-based web hook event model (
@app.on_stream()). - Insanely Fast: Powered by
blacksheepunder the hood. High-performance async/await native. - Auto-Optimized JSON: Automatically prefers and leverages high-speed
orjsonorujsonenvironments when available! - Deep Schema Validation: Validates your manifest heavily using standard
ExceptionGroupand Python structural pattern matching to surface all configuration errors simultaneously instead of failing silently or repetitively. - Fail-Safe execution: Wraps plugin executions so unhandled tracebacks map gracefully to HTTP 500 responses without crashing the Addon socket!
- Forward-Compatible Typing: Leverages PEP 695 Type Aliasing to give you brilliant IDE autocomplete on payload types.
Because the framework targets cutting edge functionalities, Python 3.14+ is expected to be utilized alongside uv (or pip).
uv pip install python-stremioAlternatively using standard pip:
pip install python-stremioBuilding an addon requires two main things: defining a manifest, and mapping routes to those resources!
Start by declaring your Stremio manifest dictionary. StremioApplication will aggressively validate this configuration on boot, letting you know instantly if you've violated the Stremio schema requirements!
from python_stremio import StremioApplication
addon_manifest = {
"id": "org.example.hello_world",
"version": "1.0.0",
"name": "Hello World Addon",
"description": "My incredibly fast python-stremio addon!",
"resources": ["catalog", "stream", "meta"],
"types": ["movie", "series"],
"catalogs": [
{"id": "my_top_catalog", "type": "movie"}
]
}
# Creates the internal API and validates the manifest configuration
app = StremioApplication(
app_manifest=addon_manifest,
bind_port=7000, # The port to run the web application on
server_log_level="info" # Logging outputs (info, debug, error etc.)
)You can seamlessly bind handlers for Stremio concepts using routing decorators. Each function receives a context dictionary mapping the request id, type, and parsed extraArgs.
Handling Catalogs:
@app.on_catalog()
async def serve_catalog_content(req: dict):
# Returns the list of content presented when opening the addon!
return {
"metas": [
{
"id": "tt1254207",
"type": "movie",
"name": "Big Buck Bunny",
"poster": "https://upload.wikimedia.org/wikipedia/commons/c/c5/Big_buck_bunny_poster_big.jpg"
}
]
}Handling Video Streams:
@app.on_stream()
async def serve_video_stream(req: dict):
# Check if the requested video matches our catalog
if req["id"] == "tt1254207":
return {
"streams": [
{
"title": "1080p HD Direct",
"url": "http://distribution.bbb3d.renderfarming.net/video/mp4/bbb_sunflower_1080p_30fps_normal.mp4"
}
]
}
# Returning an empty streams array tells Stremio we don't have sources for the title
return {"streams": []}Custom Landing Pages: If a user goes to the Addon url directly, you can serve them custom installation prompts or visual content!
@app.serve_landing_page()
async def show_presentation_page(req):
return """
<html>
<body>
<h1>Welcome to the Hello World Addon!</h1>
<a href="/manifest.json">Click here to install manually in Stremio</a>
</body>
</html>
"""Block and ignite the uvicorn network layer!
if __name__ == "__main__":
app.run()When reading catalog tags (e.g. searching, genre filtering), Stremio sends them in the req["extraArgs"] mapping! python-stremio parses query strings automatically.
@app.on_catalog()
async def filter_catalog(req):
extras = req.get("extraArgs")
if extras and "search" in extras:
return search_database(query=extras["search"])
...You can safely rely on the internal framework exception classes to diagnose complex issues.
from python_stremio import ManifestValidationError, StremioBaseError
try:
StremioApplication(broken_manifest)
except ManifestValidationError as e:
# Use standard Python ExceptionGroup unrolling
for validation_failure in e.exceptions:
print(validation_failure)You can easily register your deployed Stremio webhook remotely to standard Stremio catalog pipelines.
# To be run asynchronously:
await app.publish_to_registry(manifest_remote_url="https://api.mycustomaddon.com/manifest.json")