-
Notifications
You must be signed in to change notification settings - Fork 242
How to provide custom manifest and license
This can be useful when you need to manipulate manifests and/or licenses, or when it is not possible to get the manifests or licenses from a direct web url and you need to make them yourself. In this case, a proxy can be implemented as an intermediary between ISAdaptive and your video service server.
All this is possible by implementing a proxy service in your python add-on (ofc you can also use other ways), then you need:
- Implement a service add-on instance (Kodi service add-ons Wiki)
- Implement an HTTP server (running on localhost inside the add-on service instance)
- User play a video, Kodi starts ISAdaptive
- ISA ask the manifest to your proxy endpoint
- Your proxy does the magic to provide the manifest content (e.g. DASH) and return it to the ISA as HTTP response
- (If set) The ISA now ask for a license to your proxy endpoint
- Your HTTP server does the magic to create the license content and return it to the ISA as HTTP response
- Now Kodi will play the video by using ISA demuxer
This is explained in Integration page.
The part so far relevant here, are two properties:
listitem = xbmcgui.ListItem(path=mpd_url)
This set the address where to get the manifest, the http requests are always of type GET.
So the mpd_url
must contains the address of your http proxy server and eventually other arguments required for your purposes.
Important: It is strongly recommended, to add to the address as the first directory a folder that uses the name of your add-on (see add-on_name
in the example). This allows ISAdaptive to distinguish the add-on that hosts the proxy, because multiple add-ons can use the same address and port.
Example:
http://127.0.0.1:{port}/addon_name/manifest?id=234324
listitem.setProperty('inputstream.adaptive.license_key', lic_url)
This set the address where to get the license, the http requests are always of type POST.
So the lic_url
must contains the address of your http proxy server and eventually other arguments required for your purposes.
Important: It is strongly recommended, to add to the address as the first directory a folder that uses the name of your add-on (see add-on_name
in the example). This allows ISAdaptive to distinguish the add-on that hosts the proxy, because multiple add-ons can use the same address and port.
Example:
http://127.0.0.1:{port}/addon_name/license?id=234324
From this example you can understand how to interact with ISA. There are many examples on the net to make a http server, perhaps the best way is implement a custom http server.
The server must be started within the add-on service instance.
If your add-on service runs multiple features you need to enclose the http server within a separate thread.
To allow ISA detect the manifest type correctly and faster way, you need to add the content-type
header in the proxy manifest response.
The accepted values to be used are standard, choose the appropriate one for your use case:
- MPEG DASH manifest:
application/dash+xml
- HLS manifest:
application/vnd.apple.mpegurl
- Smooth Streaming manifest:
application/vnd.ms-sstr+xml
try: # Python 3
from http.server import BaseHTTPRequestHandler
except ImportError: # Python 2
from BaseHTTPServer import BaseHTTPRequestHandler
try: # Python 3
from socketserver import TCPServer
except ImportError: # Python 2
from SocketServer import TCPServer
try: # Python 3
from urllib.parse import unquote
except ImportError: # Python 2
from urllib import unquote
class SimpleHTTPRequestHandler(BaseHTTPRequestHandler):
def do_GET(self):
"""Handle http get requests, used for manifest"""
path = self.path # Path with parameters received from request e.g. "/manifest?id=234324"
print('HTTP GET Request received to {}'.format(path))
if '/manifest' not in path:
self.send_response(404)
self.end_headers()
return
try:
# To obtain the DRM Challenge and the DRM Session ID data to make a licensed manifest request,
# you must set the ISA property: inputstream.adaptive.pre_init_data, see Integration Wiki page
# challenge_base64 = unquote(self.headers['challengeB64'])
# sid = self.headers['sessionId']
# Call your method to do the magic to generate DASH manifest data
manifest_data = b'my manifest data'
self.send_response(200)
self.send_header('content-type', 'application/dash+xml')
self.end_headers()
self.wfile.write(manifest_data)
except Exception:
self.send_response(500)
self.end_headers()
def do_POST(self):
"""Handle http post requests, used for license"""
path = self.path # Path with parameters received from request e.g. "/license?id=234324"
print('HTTP POST Request received to {}'.format(path))
if '/license' not in path:
self.send_response(404)
self.end_headers()
return
try:
# InputStream Adaptive can send some data depending by license_key settings
# The data is splitted by "!" char
# This example split 'challenge' and 'session id' data
length = int(self.headers.get('content-length', 0))
isa_data = self.rfile.read(length).decode('utf-8').split('!')
challenge = isa_data[0]
session_id = isa_data[1]
# Call your method to do the magic to generate license data
# The format type of data must be correct in according to your VOD service
license_data = b'my license data'
self.send_response(200)
self.end_headers()
self.wfile.write(license_data)
except Exception:
self.send_response(500)
self.end_headers()
address = '127.0.0.1' # Localhost
# The port in this example is fixed, DO NOT USE A FIXED PORT!
# Other add-ons, or operating system functionality, or other software may use the same port!
# You have to implement a way to get a random free port
port = 6969
server_inst = TCPServer((address, port), SimpleHTTPRequestHandler)
# The follow line is only for test purpose, you have to implement a way to stop the http service!
server_inst.serve_forever()
User Documentation
Developer Documentation
- Integration
- Integration DRM
- Integration DRM (old)
- Stream selection types properties
- How to test a stream
- Test samples python addon
- How to provide custom manifest and license
- Supported containers and codecs
- Verified Media Path (VMP)
- Set resolution limits for DRM streams
- Custom DASH manifest tags
- Audio Subtitles track properties
- Dev. FAQ
- Widevine ARM64 support
- Add‐on WIP status
Development