Stream Metadata
You can attach arbitrary key/value pairs to any stream when it is created. Metadata is preserved and returned in all stream queries, making it easy to identify, organise, and filter streams using your own identifiers.
Use Cases
Channel identification — associate your local channel IDs with proxy streams:
{
"metadata": {
"local_id": "channel_123",
"channel_name": "HBO HD",
"channel_number": "201"
}
}
Content classification — tag streams with categories:
{
"metadata": {
"category": "sports",
"league": "premier_league",
"quality": "1080p",
"language": "en"
}
}
Provider tracking — record which source provided a stream:
{
"metadata": {
"provider": "provider_a",
"provider_stream_id": "ext_12345"
}
}
Creating a Stream with Metadata
curl -X POST "http://localhost:8085/streams" \
-H "Content-Type: application/json" \
-H "X-API-Token: your-token" \
-d '{
"url": "https://example.com/hbo.m3u8",
"metadata": {
"local_id": "hbo_hd",
"channel_name": "HBO HD",
"channel_number": "201",
"category": "movies",
"quality": "1080p"
}
}'
Metadata is returned in the response and in all subsequent stream queries.
Filtering Streams by Metadata
Server-side filtering (recommended)
Use the dedicated endpoint for efficient server-side filtering:
# Find a stream by your local ID
curl "http://localhost:8085/streams/by-metadata?field=local_id&value=hbo_hd" \
-H "X-API-Token: your-token"
# Get all active sports streams
curl "http://localhost:8085/streams/by-metadata?field=category&value=sports&active_only=true" \
-H "X-API-Token: your-token"
# Include inactive streams
curl "http://localhost:8085/streams/by-metadata?field=provider&value=provider_a&active_only=false" \
-H "X-API-Token: your-token"
Query parameters:
field(required) — metadata key to filter onvalue(required) — value to matchactive_only(optional, defaulttrue) — only return streams with active clients
Response:
{
"filter": { "field": "category", "value": "sports" },
"active_only": true,
"matching_streams": [
{
"stream_id": "a1b2c3...",
"client_count": 2,
"metadata": { "local_id": "espn_hd", "category": "sports" },
"last_access": "2025-10-05T14:35:00.000000",
"is_active": true,
"url": "https://example.com/espn.m3u8",
"stream_type": "HLS"
}
],
"total_matching": 1,
"total_clients": 2
}
Client-side filtering with jq
# Find by local_id
curl -s "http://localhost:8085/streams" -H "X-API-Token: your-token" | \
jq '.streams[] | select(.metadata.local_id == "hbo_hd")'
# Count clients on all sports streams
curl -s "http://localhost:8085/streams/by-metadata?field=category&value=sports" \
-H "X-API-Token: your-token" | jq '.total_clients'
Metadata Rules
- Keys: strings only
- Values: strings, integers, floats, or booleans (all stored as strings)
- Nesting: flat key/value pairs only — arrays and nested objects are not supported
- Size: keep under 1 KB per stream
- Persistence: stored in memory; lost on proxy restart (same as all stream data)
// Valid
{ "count": 42, "active": true, "quality": "1080p", "rating": 4.5 }
// Invalid — arrays and nested objects are rejected
{ "tags": ["sports", "hd"], "info": { "nested": "not allowed" } }
Python Example
import requests
class IPTVProxy:
def __init__(self, base_url, token):
self.base = base_url
self.headers = {"X-API-Token": token, "Content-Type": "application/json"}
def add_channel(self, local_id, name, url, number=None):
meta = {"local_id": local_id, "channel_name": name}
if number:
meta["channel_number"] = str(number)
resp = requests.post(f"{self.base}/streams",
headers=self.headers,
json={"url": url, "metadata": meta})
resp.raise_for_status()
return resp.json()["stream_endpoint"]
def get_by_local_id(self, local_id):
resp = requests.get(f"{self.base}/streams/by-metadata",
headers=self.headers,
params={"field": "local_id", "value": local_id,
"active_only": False})
data = resp.json()
streams = data.get("matching_streams", [])
return streams[0] if streams else None
proxy = IPTVProxy("http://localhost:8085", "your-token")
endpoint = proxy.add_channel("ch_hbo", "HBO HD", "https://provider.com/hbo.m3u8", 201)
info = proxy.get_by_local_id("ch_hbo")
print(f"HBO has {info['client_count']} viewers")
Best Practices
- Use server-side filtering — the
/streams/by-metadataendpoint is more efficient than fetching all streams - Define a consistent schema — agree on standard key names across your application (
local_id,category, etc.) - Always include a unique identifier — a
local_idfield lets you look up streams without storing proxy stream IDs - Use
active_only=truewhen you only need streams with connected clients - Keep it flat and small — metadata is not indexed; avoid large blobs