-
Notifications
You must be signed in to change notification settings - Fork 1
/
addon.py
187 lines (155 loc) · 6.4 KB
/
addon.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
"""
AIS playbox TV addon for kodi.
This Kodi addon allows you to play the free TV channels provided by the AIS
playbox device.
"""
import json
import random
import re
import requests
import sys
import xbmcaddon
import xbmcgui
import xbmcplugin
import zlib
from base64 import b64encode
from time import strftime
from urlparse import parse_qsl
AISWEB = "https://playbox.ais.co.th/AISWeb/"
# Without SSL GET_DEVICE_OWNER = "http://stbbe.ais.co.th:8080/getDeviceOwner"
GET_DEVICE_OWNER = "https://stbbe.ais.co.th:8443/getDeviceOwner"
TV_CHANNELS = "https://sifsecretstore.s3.amazonaws.com/AIS/json/Page/NewTV.json.gz"
GET_USER_ID = AISWEB + "ServiceGetUserIdFromPrivateId.aspx"
GET_PACKAGES = AISWEB + "PageGetPackagesByUserID.aspx"
CHECK_ENTITLEMENT = AISWEB + "ServiceCheckAssetEntitlementByUserId.aspx"
PLAYBOX_APP_KEY = "UHgZAVpacCXP/spFoX+S7Pwt/sM="
HEADERS = {
'User-Agent': 'Dalvik/1.6.0 (Linux; U; Android 4.4.2; n200 Build/KOT49H)'}
plugin_url = sys.argv[0]
plugin_handle = int(sys.argv[1])
def get_tv_channels():
"""Retrieve the current list of TV Channels"""
response = requests.get(TV_CHANNELS, headers=HEADERS)
data = json.loads(zlib.decompress(response.content, 16+zlib.MAX_WBITS))
flatten = [item for x in data['SubPage'] for item in x['Items']]
unique = dict((i['ItemID'], i) for i in flatten).values()
return sorted(unique, key=lambda item: item['ItemName'])
def get_subscriber_packages(user_id):
"""Asks for the packages the current subscriber has"""
parameters = {
'appId': 'AND',
'userId': user_id,
# Not needed but just in case
'appKey': PLAYBOX_APP_KEY}
data = {'JSONtext': json.dumps(parameters)}
res = requests.post(GET_PACKAGES, headers=HEADERS, data=data,
verify=False)
return [p["ServiceID"] for p in res.json()["PackageInfo"]]
def filter_channels(channels):
user_id = xbmcplugin.getSetting(plugin_handle, 'userId')
packages = set(get_subscriber_packages(user_id))
included = lambda cp: not packages.isdisjoint(cp.split('|'))
return [c for c in channels if included(c['Packages'])]
def map_channels(channels):
"""Creates a xbmc list of playable TV channels"""
final_list = []
for channel in channels:
list_item = xbmcgui.ListItem(label=channel['ItemName'])
list_item.setArt({'thumb': channel['ItemIcon'],
'icon': channel['ItemIcon']})
list_item.setInfo('video', {'title': channel['ItemName']})
list_item.setProperty('IsPlayable', 'true')
url = '{0}?action=play&channel={1}'.format(
plugin_url, channel['ItemID'])
final_list.append((url, list_item, False))
return final_list
def get_channel_url(assetId):
"""Request the final playable URL
This url contains a playlist with SQ and HQ streams.
"""
parameters = {
'appId': 'AND',
'assetId': assetId,
'assetType': 'CHANNEL',
'deviceType': 'STB',
'userId': xbmcplugin.getSetting(plugin_handle, 'userId'),
'lang': 'en',
'appKey': PLAYBOX_APP_KEY}
data = {'JSONtext': json.dumps(parameters)}
# Verify false due to problems in kodi v16 in macos with old python
res = requests.post(CHECK_ENTITLEMENT, headers=HEADERS, data=data,
verify=False)
return res.json()["StreamingInfo"][0]["URLInfo"]
def play_channel(channel):
"""Make kodi play a TV channel"""
url = get_channel_url(channel)
play_item = xbmcgui.ListItem("Channel")
play_item.setPath(url)
play_item.setInfo(type='Video', infoLabels={'Title': 'Channel'})
play_item.setProperty("IsPlayable", "true")
xbmcplugin.setResolvedUrl(plugin_handle, True, listitem=play_item)
def generate_command_id(serial):
"""AIS command ids"""
timestamp = strftime('%m%d%Y%H%M%S')
options = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'
rand_ending = "".join([random.choice(options) for _ in range(4)])
return "{0}-{1}{2}".format(serial, timestamp, rand_ending)
def get_device_owner(mac, serial):
"""Gets the internal/private/email id of the device owner"""
device_id = b64encode('n200|null|{0}|{1}'.format(mac, serial))
command_id = generate_command_id(serial)
parameters = {
'commandId': command_id,
'deviceId': device_id}
res = requests.get(GET_DEVICE_OWNER, params=parameters, headers=HEADERS,
verify=False)
return res.json()["ownerId"]
def get_user_id_from_email(email):
"""Converts the email/private id to the user id used in channels"""
parameters = {
'PrivateId': email,
# Not needed but just in case
'appKey': PLAYBOX_APP_KEY}
data = {'JSONtext': json.dumps(parameters)}
res = requests.post(GET_USER_ID, headers=HEADERS, data=data,
verify=False)
return res.json()["UserId"]
def get_user_id():
"""Get and save AIS user id and email/private id."""
mac = xbmcplugin.getSetting(plugin_handle, 'playboxMAC').strip().upper()
if re.match('^([0-9A-F]{2}[:]){5}([0-9A-F]{2})$', mac) is None:
xbmcgui.Dialog().ok('AIS', 'Wrong MAC address')
return
serial = xbmcplugin.getSetting(plugin_handle, 'playboxSerial').strip()
email = get_device_owner(mac, serial)
user_id = get_user_id_from_email(email)
myself = xbmcaddon.Addon()
myself.setSetting('privateId', email)
myself.setSetting('userId', user_id)
def check_settings():
"""Checks if there is a user id needed to play TV"""
user_id = xbmcplugin.getSetting(plugin_handle, 'userId')
if user_id:
return
get_user_id()
def refresh_packages():
user_id = xbmcplugin.getSetting(plugin_handle, 'userId')
packages = cache.cacheFunction(get_subscriber_packages, user_id)
def router(paramstring):
"""Decides what to do based on script parameters"""
check_settings()
params = dict(parse_qsl(paramstring))
# Nothing to do yet with those
if not params:
# Demo channel list
channels = map_channels(filter_channels(get_tv_channels()))
xbmcplugin.addDirectoryItems(plugin_handle, channels, len(channels))
xbmcplugin.addSortMethod(
plugin_handle, xbmcplugin.SORT_METHOD_LABEL_IGNORE_THE)
xbmcplugin.endOfDirectory(plugin_handle)
elif params['action'] == 'play':
play_channel(params['channel'])
elif params['action'] == 'get_user_id':
get_user_id()
if __name__ == '__main__':
router(sys.argv[2][1:])