Creating Compatible Service Scripts
xOTT Panel uses universal service scripts that can support any streaming platform. This guide shows you how to create compatible service scripts for new platforms.
Script Structure
All service scripts must follow this standardized format:
#!/usr/bin/env python3
"""
Service Script Template - Standardized Format
=============================================
This script provides a standardized interface for service integration.
It follows the platform's service script conventions for seamless integration.
Required Actions:
- login: Authenticate user and store tokens
- refresh: Refresh authentication tokens
- channels: Get available channels list
- manifest: Get stream manifest URL
- cdm: Get DRM decryption keys
- vod_categories: Get VOD content categories
- vod_content: Get VOD content for a category
- vod_seasons: Get seasons for a series
- vod_episodes: Get episodes for a season
- vod_manifest: Get VOD manifest URL
- vod_cdm: Get DRM decryption keys for VOD
Standard Parameters:
- user: Username for authentication
- password: Password for authentication
- action: Action to perform
- id: Channel/Video ID for manifest/cdm actions
- category: VOD category
- page: Page number for pagination (default: 1)
- limit: Items per page (default: 20)
- proxy: Optional proxy URL
"""
import sys
import os
import json
import base64
import time
import uuid
import requests
import secrets
import string
from bs4 import BeautifulSoup
from pywidevine.cdm import Cdm
from pywidevine.device import Device
from pywidevine.pssh import PSSH
# ============================================================================
# CONFIGURATION
# ============================================================================
# Service Configuration
SERVICE_NAME = "YourService"
SCRIPT_DIR = os.path.abspath(os.path.dirname(__file__))
# Global variables (will be set during execution)
user = None
password = None
action = None
id = None
proxy = None
req = None
# ============================================================================
# LOGGING
# ============================================================================
def log_info(message):
"""Log info message to stderr."""
print(message, file=sys.stderr)
def log_error(message):
"""Log error message to stderr."""
print(f"ERROR: {message}", file=sys.stderr)
# ============================================================================
# DRM/CDM FUNCTIONS
# ============================================================================
def do_cdm(pssh_data, license_url, token=None):
"""Get DRM decryption keys using Widevine CDM."""
try:
if not license_url:
log_error("No license URL provided (DRM not enabled for this stream)")
return None
pssh_obj = PSSH(pssh_data)
device = Device.load(os.path.join(os.path.dirname(__file__), 'WVD.wvd'))
cdm = Cdm.from_device(device)
session_id = cdm.open()
challenge = cdm.get_license_challenge(session_id, pssh_obj)
headers = {
'content-type': 'application/octet-stream',
'origin': 'https://your-service.com',
'referer': 'https://your-service.com/',
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36',
}
if token:
headers['authorization'] = f'Bearer {token}'
license_response = req.post(license_url, headers=headers, data=challenge)
if license_response.ok:
cdm.parse_license(session_id, license_response.content)
keys = []
for key in cdm.get_keys(session_id):
if key.type != 'SIGNING':
keys.append(f"{key.kid.hex}:{key.key.hex()}")
cdm.close(session_id)
return keys
else:
log_error("License request failed")
return None
except Exception as e:
log_error(f"CDM processing failed: {str(e)}")
return None
# ============================================================================
# AUTHENTICATION
# ============================================================================
def do_login(username, password):
"""Handle login action."""
try:
# Your authentication logic here
# Return authentication tokens or session data
pass
except Exception as e:
log_error(f"Login failed: {str(e)}")
return None
def do_refresh(token):
"""Handle token refresh action."""
try:
# Your token refresh logic here
pass
except Exception as e:
log_error(f"Token refresh failed: {str(e)}")
return None
# ============================================================================
# CONTENT RETRIEVAL
# ============================================================================
def get_channels(token):
"""Get available channels list."""
try:
# Your channels retrieval logic here
# Return formatted channels data
pass
except Exception as e:
log_error(f"Failed to get channels: {str(e)}")
return None
def get_events(token):
"""Get available events list."""
try:
# Your events retrieval logic here
# Return formatted events data
pass
except Exception as e:
log_error(f"Failed to get events: {str(e)}")
return None
def get_vod_categories(token):
"""Get VOD content categories."""
try:
# Your VOD categories logic here
pass
except Exception as e:
log_error(f"Failed to get VOD categories: {str(e)}")
return None
def get_vod_content(token, category, page=1, limit=20):
"""Get VOD content for a category."""
try:
# Your VOD content logic here
pass
except Exception as e:
log_error(f"Failed to get VOD content: {str(e)}")
return None
# ============================================================================
# STREAMING
# ============================================================================
def get_manifest(token, channel_id):
"""Get stream manifest URL."""
try:
# Your manifest retrieval logic here
# Return manifest URL and DRM info if applicable
pass
except Exception as e:
log_error(f"Failed to get manifest: {str(e)}")
return None
def get_vod_manifest(token, content_id):
"""Get VOD manifest URL."""
try:
# Your VOD manifest logic here
pass
except Exception as e:
log_error(f"Failed to get VOD manifest: {str(e)}")
return None
# ============================================================================
# MAIN EXECUTION
# ============================================================================
def main():
global user, password, action, id, proxy, req
# Parse command line arguments
args = sys.argv[1:]
for i in range(0, len(args), 2):
if i + 1 < len(args):
key = args[i].replace('--', '')
value = args[i + 1]
if key == 'user':
user = value
elif key == 'password':
password = value
elif key == 'action':
action = value
elif key == 'id':
id = value
elif key == 'proxy':
proxy = value
# Create requests session with proxy if provided
req = requests.Session()
if proxy:
req.proxies = {'http': proxy, 'https': proxy}
# Execute action based on input
try:
if action == 'login':
result = do_login(user, password)
elif action == 'refresh':
result = do_refresh(user) # user contains token in refresh action
elif action == 'channels':
result = get_channels(user) # user contains token in channels action
elif action == 'events':
result = get_events(user) # user contains token in events action
elif action == 'manifest':
result = get_manifest(user, id) # user contains token, id contains channel_id
elif action == 'cdm':
result = do_cdm(user, password, id) # user contains pssh, password contains license_url, id contains token
elif action == 'vod_categories':
result = get_vod_categories(user) # user contains token
elif action == 'vod_content':
result = get_vod_content(user, password, id) # user contains token, password contains category, id contains page
elif action == 'vod_manifest':
result = get_vod_manifest(user, id) # user contains token, id contains content_id
elif action == 'vod_cdm':
result = do_cdm(user, password, id) # user contains pssh, password contains license_url, id contains token
else:
log_error(f"Unknown action: {action}")
sys.exit(1)
if result:
print(json.dumps(result, indent=2))
else:
log_error("Action failed")
sys.exit(1)
except Exception as e:
log_error(f"Execution failed: {str(e)}")
sys.exit(1)
if __name__ == "__main__":
main()
Required Actions
Your service script must implement these actions:
login
Authenticate user and return authentication tokens
refresh
Refresh authentication tokens when they expire
channels
Return list of available live channels
events
Return list of available events
manifest
Get stream manifest URL for a channel
cdm
Get DRM decryption keys for protected content
vod_categories
Get VOD content categories
vod_content
Get VOD content for a category
vod_manifest
Get VOD manifest URL
vod_cdm
Get DRM decryption keys for VOD content
DRM Support
For DRM-protected content, include Widevine device files (.wvd) in your script directory. The script should extract PSSH data from manifests and request decryption keys from license servers.
Testing Your Script
Test your script using the command line:
python3 YourService.py --action login --user "username" --password "password"
python3 YourService.py --action channels --user "token"
python3 YourService.py --action manifest --user "token" --id "channel_id"
Setting Up Telegram Notifications
xOTT Panel includes a comprehensive Telegram notification system for real-time alerts about events, service status updates, proxy assignments, and system monitoring.
Step 1: Create a Telegram Bot
- Open Telegram and search for
@BotFather - Send
/newbotcommand - Follow the instructions to create your bot
- Save the bot token provided by BotFather
Step 2: Get Your Chat ID
- Send a message to your bot
- Visit:
https://api.telegram.org/bot{YOUR_BOT_TOKEN}/getUpdates - Find your chat ID in the response
Step 3: Configure in xOTT Panel
- Log in to your xOTT Panel dashboard
- Navigate to Settings → Notifications
- Enable Telegram Notifications
- Enter your Bot Token
- Enter your Chat ID
- Configure notification types:
- Stream Alerts
- Event Notifications
- Service Status Updates
- Proxy Assignment Updates
- System Monitoring Alerts
- Click Save Settings
Notification Types
Event Notifications
Real-time alerts when events start, stop, or restart
Service Notifications
Updates about service status changes and proxy assignments
Stream Alerts
Notifications about stream status and performance
System Monitoring
Alerts about system health and resource usage
Testing Notifications
After configuration, test your notifications by:
- Starting a test stream
- Scheduling a test event
- Changing service proxy assignments
XUI Panel Integration Setup
xOTT Panel includes full XUI Panel integration with automatic stream export, event scheduling, real-time synchronization, and centralized management.
Step 1: Prepare XUI Panel
- Ensure your XUI Panel is running and accessible
- Note your XUI Panel URL (e.g.,
https://your-xui-panel.com) - Generate an access code from the Access Codes page in XUI Panel (Admin API access code)
- Generate an API key from the Profile Settings page in XUI Panel
Step 2: Configure XUI Connection
- Log in to your xOTT Panel dashboard
- Navigate to XUI Integration in the sidebar
- Click Add Connection
- Fill in the connection details:
- Connection Name: Descriptive name for this connection
- XUI Panel URL: Your XUI Panel base URL
- Access Code: Access code generated from XUI Access Codes page (Admin API access code)
- API Key: API key generated from XUI Profile Settings page
- Auto-Sync: Enable automatic synchronization
- Click Test Connection to verify
- Click Save Connection
Step 3: Export Streams
- Navigate to Streams in xOTT Panel
- Select the streams you want to export
- Click Export to XUI
- Choose your XUI connection
- Configure export settings:
- Stream name and description
- Category assignment
- Quality settings
- Auto-activation
- Click Export
Step 4: Schedule Events
- Navigate to Events in xOTT Panel
- Create or select an event
- Click Export to XUI
- Configure event settings:
- Event name and description
- Start and end times
- Stream assignment
- Auto-activation schedule
- Click Schedule Export
Sync Status Monitoring
Monitor your XUI integration status through:
- Sync Logs: View detailed sync operation logs
- Status Dashboard: Real-time sync status overview
- Error Handling: Automatic retry and error reporting
- Notifications: Telegram alerts for sync events