def check_data(self, resp, json=True): if self._debug_mode: log.debug('Executing: api.check_data') log.debug('Vars: resp={resp}, json={json}'.format( resp='Unaltered response, see above', json=json)) if json: data = resp.json() if data and check_key(data, 'resultCode') and data['resultCode'] == 'KO': if self._debug_mode: log.debug('Execution Done: api.check_data') return False if not data or not check_key(data, 'resultCode') or not data[ 'resultCode'] == 'OK' or not check_key(data, 'resultObj'): if self._debug_mode: log.debug('Execution Done: api.check_data') return False if self._debug_mode: log.debug('Execution Done: api.check_data') return True
def request(self, method, url, timeout=None, attempts=None, **kwargs): if not url.startswith('http'): url = self._base_url.format(url) kwargs['timeout'] = timeout or self._timeout attempts = attempts or self._attempts if sys.version_info < (3, 0): rngattempts = range(1, attempts+1) else: rngattempts = list(range(1, attempts+1)) for i in rngattempts: log.debug('Attempt {}/{}: {} {} {}'.format(i, attempts, method, url, kwargs if method.lower() != 'post' else "")) try: data = super(Session, self).request(method, url, **kwargs) if self._cookies_key: self.save_cookies() return data except: if i == attempts: raise
def vod_seasons(self, id): if self._debug_mode: log.debug('Executing: api.vod_seasons') log.debug('Vars: id={id}'.format(id=id)) seasons = [] program_url = '{api_url}/CONTENT/DETAIL/GROUP_OF_BUNDLES/{id}'.format( api_url=self._api_url, id=id) file = "cache" + os.sep + "vod_seasons_" + unicode(id) + ".json" if self._enable_cache and not is_file_older_than_x_minutes( file=ADDON_PROFILE + file, minutes=10): data = load_file(file=file, isJSON=True) else: data = self.download(url=program_url, type='get', code=[200], data=None, json_data=False, data_return=True, return_json=True, retry=True, check_data=True) if data and check_key(data['resultObj'], 'containers') and self._enable_cache: write_file(file=file, data=data, isJSON=True) if not data or not check_key(data['resultObj'], 'containers'): if self._debug_mode: log.debug('Failure to retrieve expected data') log.debug('Execution Done: api.vod_seasons') return None for row in data['resultObj']['containers']: for currow in row['containers']: if check_key(currow, 'metadata') and check_key( currow['metadata'], 'season' ) and currow['metadata']['contentSubtype'] == 'SEASON': seasons.append({ 'id': currow['metadata']['contentId'], 'seriesNumber': currow['metadata']['season'], 'desc': currow['metadata']['shortDescription'], 'image': currow['metadata']['pictureUrl'] }) if self._debug_mode: log.debug('Execution Done: api.vod_seasons') return seasons
def set_settings(settings): addon = get_ia_addon(install=False) if not addon: return log.debug('IA Set Settings: {}'.format(settings)) for key in settings: addon.setSetting(key, str(settings[key]))
def update_prefs(self): if self._debug_mode: log.debug('Executing: api.update_prefs') prefs = load_file(file="channel_prefs.json", isJSON=True) results = load_file(file="channel_test.json", isJSON=True) channels = load_file(file="channels.json", isJSON=True) if not results: results = {} if not prefs: prefs = {} if not channels: channels = {} for row in channels: channeldata = self.get_channel_data(row=row, channelno=1) id = unicode(channeldata['channel_id']) if len(unicode(id)) == 0: continue keys = ['live', 'replay', 'epg'] for key in keys: if not check_key(prefs, id) or not check_key(prefs[id], key): if not check_key(results, id): if not check_key(prefs, id): prefs[id] = { key: 'true', key + '_choice': 'auto' } else: prefs[id][key] = 'true' prefs[id][key + '_choice'] = 'auto' else: result_value = results[id][key] if not check_key(prefs, id): prefs[id] = { key: result_value, key + '_choice': 'auto' } else: prefs[id][key] = result_value prefs[id][key + '_choice'] = 'auto' elif prefs[id][key + '_choice'] == 'auto' and check_key(results, id): prefs[id][key] = results[id][key] write_file(file="channel_prefs.json", data=prefs, isJSON=True) if self._debug_mode: log.debug('Execution Done: api.update_prefs')
def change_icon(): try: settingsJSON = load_file(file='settings.json', isJSON=True) if check_key(settingsJSON, 'icon') and check_key(settingsJSON['icon'], 'md5'): addon_icon = ADDON_PATH + os.sep + "icon.png" if not md5sum(addon_icon) or settingsJSON['icon']['md5'] != md5sum(addon_icon): r = requests.get(settingsJSON['icon']['url'], stream=True) if r.status_code == 200: if debug_mode: log.debug('Trying to write ICON to {addon_path}'.format(addon_path=addon_icon)) try: with open(addon_icon, 'wb') as f: for chunk in r.iter_content(1024): f.write(chunk) except: return False else: return False try: texture_file = 'Textures13.db' for file in glob.glob(xbmc.translatePath("special://database") + os.sep + "*Textures*"): texture_file = file DB = os.path.join(xbmc.translatePath("special://database"), texture_file) db = sqlite.connect(DB) query = "SELECT cachedurl FROM texture WHERE url LIKE '%addons%" + ADDON_ID + "%icon.png';" rows = db.execute(query) for row in rows: thumb = os.path.join(xbmc.translatePath("special://thumbnails"), unicode(row[0])) if os.path.isfile(thumb): os.remove(thumb) query = "DELETE FROM texture WHERE url LIKE '%addons%" + ADDON_ID + "%icon.png';" db.execute(query) db.commit() db.close() except: return False except: pass
def get_channels_for_user(self): if self._debug_mode: log.debug('Executing: api.get_channels_for_user') channels_url = '{api_url}/TRAY/LIVECHANNELS?orderBy=orderId&sortOrder=asc&from=0&to=999&dfilter_channels=subscription'.format( api_url=self._api_url) data = self.download(url=channels_url, type='get', code=[200], data=None, json_data=False, data_return=True, return_json=True, retry=True, check_data=True) if not data or not check_key(data['resultObj'], 'containers'): if self._debug_mode: log.debug('Failure to retrieve expected data') log.debug('Execution Done: api.get_channels_for_user') return False write_file(file="channels.json", data=data['resultObj']['containers'], isJSON=True) self.create_playlist() if self._debug_mode: log.debug('Execution Done: api.get_channels_for_user') return True
def create_playlist(self): if self._debug_mode: log.debug('Executing: api.create_playlist') prefs = load_file(file="channel_prefs.json", isJSON=True) channels = load_file(file="channels.json", isJSON=True) playlist_all = u'#EXTM3U\n' playlist = u'#EXTM3U\n' for row in channels: channeldata = self.get_channel_data(row=row) id = unicode(channeldata['channel_id']) if len(id) > 0: path = 'plugin://{addonid}/?_=play_video&channel={channel}&id={asset}&type=channel&_l=.pvr'.format( addonid=ADDON_ID, channel=channeldata['channel_id'], asset=channeldata['asset_id']) playlist_all += u'#EXTINF:-1 tvg-id="{id}" tvg-chno="{channel}" tvg-name="{name}" tvg-logo="{logo}" group-title="TV" radio="false",{name}\n{path}\n'.format( id=channeldata['channel_id'], channel=channeldata['channel_number'], name=channeldata['label'], logo=channeldata['station_image_large'], path=path) if not prefs or not check_key( prefs, id) or prefs[id]['epg'] == 'true': playlist += u'#EXTINF:-1 tvg-id="{id}" tvg-chno="{channel}" tvg-name="{name}" tvg-logo="{logo}" group-title="TV" radio="false",{name}\n{path}\n'.format( id=channeldata['channel_id'], channel=channeldata['channel_number'], name=channeldata['label'], logo=channeldata['station_image_large'], path=path) self._channels_age = time.time() settings.setInt(key='_channels_age', value=self._channels_age) if self._debug_mode: log.debug('Setting _channels_age to: {channels_age}'.format( channels_age=self._channels_age)) log.debug('Writing tv.m3u8: {playlist}'.format(playlist=playlist)) write_file(file="tv.m3u8", data=playlist, isJSON=False) write_file(file="tv_all.m3u8", data=playlist_all, isJSON=False) combine_playlist() if self._debug_mode: log.debug('Execution Done: api.create_playlist')
def parse_url(url): if url.startswith('?'): params = dict(parse_qsl(url.lstrip('?'), keep_blank_values=True)) for key in params: params[key] = unquote(params[key]) _url = params.pop('_', '') else: params = {} _url = url params['_url'] = url function = _routes.get(_url) if not function: raise RouterError(_(_.ROUTER_NO_FUNCTION, raw_url=url, parsed_url=_url)) log.debug('Router Parsed: \'{0}\' => {1} {2}'.format( url, function.__name__, params)) return function, params
def check_data(self, resp, json=False): if self._debug_mode: log.debug('Executing: api.check_data') log.debug('Vars: resp={resp}, json={json}'.format(resp='Unaltered response, see above', json=json)) if self._debug_mode: log.debug('Execution Done: api.check_data') return True
def vod_seasons(self, id): if self._debug_mode: log.debug('Executing: api.vod_seasons') log.debug('Vars: id={id}'.format(id=id)) seasons = [] if self._debug_mode: log.debug('Execution Done: api.vod_seasons') return seasons
def clear_session(self): if self._debug_mode: log.debug('Executing: api.clear_session') settings.remove(key='_cookies') self._cookies = '' try: self._session.clear_cookies() if self._debug_mode: log.debug('Execution Done: api.get_channels_for_user') return True except: if self._debug_mode: log.debug('Failure clearing session cookies') log.debug('Execution Done: api.get_channels_for_user') return False
def vod_subscription(self): if self._debug_mode: log.debug('Executing: api.vod_subscription') subscription = [] series_url = '{api_url}/TRAY/SEARCH/VOD?from=1&to=9999&filter_contentType=GROUP_OF_BUNDLES,VOD&filter_contentSubtype=SERIES,VOD&filter_contentTypeExtended=VOD&filter_excludedGenres=erotiek&filter_technicalPackages=10078,10081,10258,10255&dfilter_packages=matchSubscription&orderBy=activationDate&sortOrder=desc'.format( api_url=self._api_url) data = self.download(url=series_url, type='get', code=[200], data=None, json_data=False, data_return=True, return_json=True, retry=True, check_data=True) if not data or not check_key(data['resultObj'], 'containers'): if self._debug_mode: log.debug('Failure to retrieve expected data') log.debug('Execution Done: api.vod_subscription') return False for row in data['resultObj']['containers']: subscription.append(row['metadata']['contentId']) write_file(file='vod_subscription.json', data=subscription, isJSON=True) if self._debug_mode: log.debug('Execution Done: api.vod_subscription') return True
def test_channels(self, tested=False, channel=None): if self._debug_mode: log.debug('Executing: api.test_channels') log.debug('Vars: tested={tested}, channel={channel}'.format(tested=tested, channel=channel)) if channel: channel = unicode(channel) try: if not self._last_login_success or not settings.getBool(key='run_tests'): return 5 settings.setBool(key='_test_running', value=True) channels = load_file(file="channels.json", isJSON=True) results = load_file(file="channel_test.json", isJSON=True) count = 0 first = True last_tested_found = False test_run = False user_agent = settings.get(key='_user_agent') if not results: results = {} for row in channels: if count == 5 or (count == 1 and tested): if test_run: self.update_prefs() settings.setBool(key='_test_running', value=False) return count channeldata = self.get_channel_data(row=row, channelno=1) id = unicode(channeldata['channel_id']) if len(id) > 0: if channel: if not id == channel: continue elif tested and check_key(results, 'last_tested'): if unicode(results['last_tested']) == id: last_tested_found = True continue elif last_tested_found: pass else: continue if check_key(results, id) and not tested and not first: continue livebandwidth = 0 replaybandwidth = 0 live = 'false' replay = 'false' epg = 'false' guide = 'false' if settings.getInt(key='_last_playing') > int(time.time() - 300): if test_run: self.update_prefs() settings.setBool(key='_test_running', value=False) return 5 playdata = self.play_url(type='channel', channel=id, id=id, test=True) if first and not self._last_login_success: if test_run: self.update_prefs() settings.setBool(key='_test_running', value=False) return 5 if len(playdata['path']) > 0: CDMHEADERS = CONST_BASE_HEADERS CDMHEADERS['User-Agent'] = user_agent self._session2 = Session(headers=CDMHEADERS) resp = self._session2.get(playdata['path']) if resp.status_code == 200: livebandwidth = find_highest_bandwidth(xml=resp.text) live = 'true' if check_key(results, id) and first and not tested: first = False if live == 'true': continue else: if test_run: self.update_prefs() settings.setBool(key='_test_running', value=False) return 5 first = False counter = 0 while not self._abortRequested and not xbmc.Monitor().abortRequested() and counter < 5: if self._abortRequested or xbmc.Monitor().waitForAbort(1): self._abortRequested = True break counter += 1 if settings.getInt(key='_last_playing') > int(time.time() - 300): if test_run: self.update_prefs() settings.setBool(key='_test_running', value=False) return 5 if self._abortRequested or xbmc.Monitor().abortRequested(): return 5 self._session.headers = CONST_BASE_HEADERS self._session.headers.update({'Authorization': 'Bearer ' + self._session_token}) yesterday = datetime.datetime.now() - datetime.timedelta(1) fromtime = datetime.datetime.strftime(yesterday, '%Y-%m-%dT%H:%M:%S.000Z') tilltime = datetime.datetime.strftime(yesterday, '%Y-%m-%dT%H:%M:59.999Z') program_url = "{api_url}/schedule?channels={id}&from={fromtime}&until={tilltime}".format(api_url=CONST_DEFAULT_API, id=id, fromtime=fromtime, tilltime=tilltime); data = self.download(url=program_url, type="get", code=[200], data=None, json_data=False, data_return=True, return_json=True, retry=True, check_data=False, allow_redirects=False) if data and check_key(data, 'epg') and check_key(data['epg'][0], 'id'): if settings.getInt(key='_last_playing') > int(time.time() - 300): if test_run: self.update_prefs() settings.setBool(key='_test_running', value=False) return 5 playdata = self.play_url(type='program', channel=id, id=data['epg'][0]['id'], test=True) if len(playdata['path']) > 0: CDMHEADERS = CONST_BASE_HEADERS CDMHEADERS['User-Agent'] = user_agent self._session2 = Session(headers=CDMHEADERS) resp = self._session2.get(playdata['path']) if resp.status_code == 200: replaybandwidth = find_highest_bandwidth(xml=resp.text) replay = 'true' if os.path.isfile(ADDON_PROFILE + id + '_replay.json'): guide = 'true' if live == 'true': epg = 'true' results[id] = { 'id': id, 'live': live, 'replay': replay, 'livebandwidth': livebandwidth, 'replaybandwidth': replaybandwidth, 'epg': epg, 'guide': guide, } results['last_tested'] = id if not self._abortRequested: write_file(file="channel_test.json", data=results, isJSON=True) test_run = True counter = 0 while not self._abortRequested and not xbmc.Monitor().abortRequested() and counter < 15: if self._abortRequested or xbmc.Monitor().waitForAbort(1): self._abortRequested = True break counter += 1 if settings.getInt(key='_last_playing') > int(time.time() - 300): if test_run: self.update_prefs() settings.setBool(key='_test_running', value=False) return 5 if self._abortRequested or xbmc.Monitor().abortRequested(): return 5 count += 1 except: if test_run: self.update_prefs() count = 5 settings.setBool(key='_test_running', value=False) if self._debug_mode: log.debug('Execution Done: api.test_channels') return count
def get_channel_data(self, row, channelno=0): if self._debug_mode: log.debug('Executing: api.get_channel_data') log.debug('Vars: row={row}, channelno={channelno}'.format(row=row, channelno=channelno)) channeldata = { 'channel_id': '', 'channel_number': int(channelno), 'description': '', 'label': '', 'station_image_large': '', } if not check_key(row, 'id') or not check_key(row, 'title'): if self._debug_mode: log.debug('Failure to retrieve expected data') log.debug('Execution Done: api.get_channel_data') return channeldata #if '18+' in row['title']: # if self._debug_mode: # log.debug('Skipping XXX') # # return channeldata path = ADDON_PROFILE + "images" + os.sep + unicode(row['id']) + ".png" image = '' if os.path.isfile(path): image = path else: if check_key(row, 'images') and check_key(row['images'][0], 'url'): image = row['images'][0]['url'] channeldata['channel_id'] = row['id'] channeldata['label'] = row['title'] channeldata['station_image_large'] = image if self._debug_mode: log.debug('Returned data: {channeldata}'.format(channeldata=channeldata)) log.debug('Execution Done: api.get_channel_data') return channeldata
def change_icon(): try: settingsJSON = load_file(file='settings.json', isJSON=True) if check_key(settingsJSON, 'icon') and check_key(settingsJSON['icon'], 'md5'): addon_icon = ADDON_PATH + os.sep + "icon.png" if debug_mode: log.debug('ICON settings key and MD5 found') log.debug('ICON settings MD5: {mdfive}'.format(mdfive=settingsJSON['icon']['md5'])) log.debug('Addon path icon.png MD5: {mdfive}'.format(mdfive=md5sum(addon_icon))) if not md5sum(addon_icon) or settingsJSON['icon']['md5'] != md5sum(addon_icon): if debug_mode: log.debug('No icon.png found in Addon Path or ICON settings MD5 does not match Addon Path icon.png MD5, attempting to change ICON') log.debug('Downloading ICON from {url}'.format(url=settingsJSON['icon']['url'])) r = requests.get(settingsJSON['icon']['url'], stream=True) if r.status_code == 200: if debug_mode: log.debug('Trying to write ICON to {addon_path}'.format(addon_path=addon_icon)) try: with open(addon_icon, 'wb') as f: for chunk in r.iter_content(1024): f.write(chunk) if debug_mode: log.debug('Succesfully written ICON to {addon_path}'.format(addon_path=addon_icon)) except: if debug_mode: log.debug('Error while writing ICON to {addon_path}'.format(addon_path=addon_icon)) return False else: if debug_mode: log.debug('Error trying to download ICON from url, Status code: {code}'.format(code=r.status_code)) return False try: from sqlite3 import dbapi2 as sqlite3 if debug_mode: log.debug('SQLite imported from SQLite3') except: from pysqlite2 import dbapi2 as sqlite if debug_mode: log.debug('SQLite imported from PySQLite2') try: texture_file = 'Textures13.db' for file in glob.glob(xbmc.translatePath("special://database") + os.sep + "*Textures*"): texture_file = file if debug_mode: log.debug('Texture File: {texture}'.format(texture=texture_file)) DB = os.path.join(xbmc.translatePath("special://database"), texture_file) if debug_mode: log.debug('Texture File Path: {texture}'.format(texture=DB)) db = sqlite.connect(DB) query = "SELECT cachedurl FROM texture WHERE url LIKE '%addons%" + ADDON_ID + "%icon.png';" if debug_mode: log.debug('DB Query: {query}'.format(query=query)) rows = db.execute(query) for row in rows: thumb = os.path.join(xbmc.translatePath("special://thumbnails"), unicode(row[0])) if debug_mode: log.debug('Thumb Found: {thumb}'.format(thumb=thumb)) if os.path.isfile(thumb): os.remove(thumb) if debug_mode: log.debug('Thumb Removed: {thumb}'.format(thumb=thumb)) query = "DELETE FROM texture WHERE url LIKE '%addons%" + ADDON_ID + "%icon.png';" if debug_mode: log.debug('DB Query: {query}'.format(query=query)) db.execute(query) db.commit() db.close() if debug_mode: log.debug('DB Queries completed, changing addon done') log.debug('ICON settings MD5: {mdfive}'.format(mdfive=settingsJSON['icon']['md5'])) log.debug('Addon Path icon.png MD5: {mdfive}'.format(mdfive=md5sum(ADDON_PATH + "icon.png"))) except: return False else: if debug_mode: log.debug('ICON settings MD5 matches Addon Path icon.png MD5, skipping') else: if debug_mode: log.debug('ICON settings key not found') except: if debug_mode: log.debug('Exception while trying to change ICON')
def login(self, username, password, channels=False, retry=True): if self._debug_mode: log.debug('Executing: api.login') log.debug( 'Vars: username={username}, password={password}, channels={channels}, retry={retry}' .format(username=username, password=password, channels=channels, retry=retry)) settings.remove(key='_cookies') self._cookies = '' self._session = Session(cookies_key='_cookies') session_url = '{api_url}/USER/SESSIONS/'.format(api_url=self._api_url) if self._debug_mode: log.debug('Clear Setting _cookies') log.debug('Creating new Requests Session') log.debug('Request Session Headers') log.debug(self._session.headers) email_or_pin = settings.getBool(key='email_instead_of_customer') if email_or_pin: session_post_data = { "credentialsExtAuth": { 'credentials': { 'loginType': 'UsernamePassword', 'username': username, 'password': password, 'appId': 'KPN', }, 'remember': 'Y', 'deviceInfo': { 'deviceId': self._devicekey, 'deviceIdType': 'DEVICEID', 'deviceType': 'PCTV', 'deviceVendor': settings.get(key='_browser_name'), 'deviceModel': settings.get(key='_browser_version'), 'deviceFirmVersion': settings.get(key='_os_name'), 'appVersion': settings.get(key='_os_version') } }, } else: session_post_data = { "credentialsStdAuth": { 'username': username, 'password': password, 'remember': 'Y', 'deviceRegistrationData': { 'deviceId': settings.get(key='_devicekey'), 'accountDeviceIdType': 'DEVICEID', 'deviceType': 'PCTV', 'vendor': settings.get(key='_browser_name'), 'model': settings.get(key='_browser_version'), 'deviceFirmVersion': settings.get(key='_os_name'), 'appVersion': settings.get(key='_os_version') } }, } data = self.download(url=session_url, type='post', code=[200], data=session_post_data, json_data=True, data_return=True, return_json=True, retry=retry, check_data=False) if not data or not check_key( data, 'resultCode') or data['resultCode'] == 'KO': if self._debug_mode: log.debug('Failure to retrieve expected data') log.debug('Execution Done: api.login') if email_or_pin: gui.ok(message=_.LOGIN_ERROR2, heading=_.LOGIN_ERROR_TITLE) else: gui.ok(message=_.LOGIN_ERROR, heading=_.LOGIN_ERROR_TITLE) self.clear_session() return False self._session_age = time.time() settings.setInt(key='_session_age', value=self._session_age) if self._debug_mode: log.debug('Settings _channels_age: {channels_age}'.format( channels_age=self._channels_age)) log.debug('Time - 86400 seconds: {time}'.format( time=int(time.time() - 86400))) if channels or self._channels_age < int(time.time() - 86400): self.get_channels_for_user() self.vod_subscription() self._username = username self._password = password if settings.getBool(key='save_password', default=False): set_credentials(username=username, password=password) else: set_credentials(username=username, password='') self.logged_in = True if self._debug_mode: log.debug('Execution Done: api.login') return True
def new_session(self, force=False, retry=True, channels=False): self.check_vars() if self._debug_mode: log.debug('Executing: api.new_session') log.debug( 'Vars: force={force}, retry={retry}, channels={channels}'. format(force=force, retry=retry, channels=channels)) log.debug('Cookies: {cookies}'.format(cookies=self._cookies)) username = self._username password = self._password if len(self._cookies) > 0 and len( username ) > 0 and not force and not channels and self._session_age > int( time.time() - 7200) and self._last_login_success: self.logged_in = True try: self._session except: self._session = Session(cookies_key='_cookies') if self._debug_mode: log.debug('Creating new Requests Session') log.debug('Request Session Headers') log.debug(self._session.headers) log.debug('api.logged_in: {logged_in}'.format( logged_in=self.logged_in)) return True self.logged_in = False if self._debug_mode: log.debug( 'api.logged_in: {logged_in}'.format(logged_in=self.logged_in)) if not len(username) > 0: if self._debug_mode: log.debug('Username length = 0') log.debug('Execution Done: api.new_session') settings.setBool(key="_last_login_success", value=self.logged_in) self._last_login_success = self.logged_in return False if not len(password) > 0: email_or_pin = settings.getBool(key='email_instead_of_customer') if not force: if self._debug_mode: log.debug('Password length = 0 and force is false') log.debug('Execution Done: api.new_session') settings.setBool(key="_last_login_success", value=self.logged_in) self._last_login_success = self.logged_in return False if email_or_pin: password = gui.input(message=_.ASK_PASSWORD2, hide_input=True).strip() else: password = gui.numeric(message=_.ASK_PASSWORD).strip() if not len(password) > 0: if self._debug_mode: log.debug('Password length = 0') log.debug('Execution Done: api.new_session') if email_or_pin: gui.ok(message=_.EMPTY_PASS2, heading=_.LOGIN_ERROR_TITLE) else: gui.ok(message=_.EMPTY_PASS, heading=_.LOGIN_ERROR_TITLE) settings.setBool(key="_last_login_success", value=self.logged_in) self._last_login_success = self.logged_in return False self.login(username=username, password=password, channels=channels, retry=retry) if self._debug_mode: log.debug('Execution Done: api.new_session') log.debug( 'api.logged_in: {logged_in}'.format(logged_in=self.logged_in)) settings.setBool(key="_last_login_success", value=self.logged_in) self._last_login_success = self.logged_in if self.logged_in: return True return False
def download(self, url, type, code=None, data=None, json_data=True, data_return=True, return_json=True, retry=True, check_data=True, allow_redirects=True): if self._abortRequested or xbmc.Monitor().abortRequested(): return None if self._debug_mode: log.debug('Executing: api.download') log.debug( 'Vars: url={url}, type={type}, code={code}, data={data}, json_data={json_data}, data_return={data_return}, return_json={return_json}, retry={retry}, check_data={check_data}, allow_redirects={allow_redirects}' .format(url=url, type=type, code=code, data=data, json_data=json_data, data_return=data_return, return_json=return_json, retry=retry, check_data=check_data, allow_redirects=allow_redirects)) if type == "post" and data: if json_data: resp = self._session.post(url, json=data, allow_redirects=allow_redirects) else: resp = self._session.post(url, data=data, allow_redirects=allow_redirects) else: resp = getattr(self._session, type)(url, allow_redirects=allow_redirects) if self._debug_mode: log.debug('Response') log.debug(resp.text) log.debug('Response status code: {status_code}'.format( status_code=resp.status_code)) if (code and not resp.status_code in code) or ( check_data and not self.check_data(resp=resp)): if not retry: if self._debug_mode: log.debug('Not retrying') log.debug('Returned data: None') log.debug('Execution Done: api.download') return None if self._debug_mode: log.debug('Trying to update login data') self.new_session(force=True, retry=False) if not self.logged_in: if self._debug_mode: log.debug('Not logged in at retry') log.debug('Returned data: None') log.debug('Execution Done: api.download') return None if type == "post" and data: if json_data: resp = self._session.post(url, json=data, allow_redirects=allow_redirects) else: resp = self._session.post(url, data=data, allow_redirects=allow_redirects) else: resp = getattr(self._session, type)(url, allow_redirects=allow_redirects) if self._debug_mode: log.debug('Response') log.debug(resp.text) log.debug('Response status code: {status_code}'.format( status_code=resp.status_code)) if (code and not resp.status_code in code) or ( check_data and not self.check_data(resp=resp)): if self._debug_mode: log.debug('Failure on retry') log.debug('Returned data: None') log.debug('Execution Done: api.download') return None if data_return: try: if return_json: try: returned_data = json.loads(resp.json().decode('utf-8')) except: returned_data = resp.json() if self._debug_mode: log.debug( 'Returned data: {data}'.format(data=returned_data)) log.debug('Execution Done: api.download') return returned_data else: if self._debug_mode: log.debug( 'Returned data: Unaltered response, see above') log.debug('Execution Done: api.download') return resp except: pass if self._debug_mode: log.debug('Returned data: True') log.debug('Execution Done: api.download') return True
def check_vars(self): try: self._debug_mode except: self._debug_mode = settings.getBool(key='enable_debug') if self._debug_mode: log.debug('Executing: api.check_vars') try: self._cookies except: self._cookies = settings.get(key='_cookies') try: self._session_age except: self._session_age = settings.getInt(key='_session_age') try: self._last_login_success except: self._last_login_success = settings.getBool( key='_last_login_success') try: self._channels_age except: self._channels_age = settings.getInt(key='_channels_age') try: self._enable_cache except: self._enable_cache = settings.getBool(key='enable_cache') try: self._api_url except: self._api_url = settings.get(key='_api_url') try: self._devicekey except: self._devicekey = settings.get(key='_devicekey') try: self._username except: try: creds except: creds = get_credentials() self._username = creds['username'] try: self._abortRequested except: self._abortRequested = False try: self._password except: try: creds except: creds = get_credentials() self._password = creds['password'] if self._debug_mode: log.debug('Execution Done: api.check_vars')
def _download(url, dst, dst_path, arch, md5=None): filename = url.split('/')[-1] tmp = ADDON_PROFILE + "tmp" + os.sep + "widevine" downloaded = 0 if os.path.exists(dst_path): if md5 and md5sum(dst_path) == md5: log.debug('MD5 of local file {} same. Skipping download'.format( filename)) return True elif not gui.yes_no(_.NEW_IA_VERSION): return False else: if os.path.exists(dst_path): os.remove(dst_path) from .session import Session with gui.progress(_(_.IA_DOWNLOADING_FILE, url=filename), heading=_.IA_WIDEVINE_DRM) as progress: resp = Session().get(url, stream=True) if resp.status_code != 200: raise InputStreamError( _(_.ERROR_DOWNLOADING_FILE, filename=filename)) total_length = float(resp.headers.get('content-length', 1)) with open(tmp, 'wb') as f: for chunk in resp.iter_content(chunk_size=SESSION_CHUNKSIZE): f.write(chunk) downloaded += len(chunk) downloadperc = int(downloaded) * 100 downloadperc2 = int(downloadperc) // int(total_length) percent = int(downloadperc2) if progress.iscanceled(): progress.close() resp.close() progress.update(percent) if os.path.isfile(tmp): if 'arm' in arch: with open(tmp, "rb") as encoded_file: decoded_string = base64.b64decode(encoded_file.read()) with open(dst_path, "wb") as decoded_file: decoded_file.write(decoded_string) else: with ZipFile(tmp, 'r') as zipObj: zipObj.extractall(ADDON_PROFILE + "tmp" + os.sep) if os.path.isfile(ADDON_PROFILE + "tmp" + os.sep + dst): shutil.copy(ADDON_PROFILE + "tmp" + os.sep + dst, dst_path) for file in glob.glob(ADDON_PROFILE + "tmp" + os.sep + "*"): os.remove(file) if progress.iscanceled(): return False checksum = md5sum(dst_path) if checksum != md5: if os.path.exists(dst_path): os.remove(dst_path) raise InputStreamError( _(_.MD5_MISMATCH, filename=filename, local_md5=checksum, remote_md5=md5)) return True
def play_url(self, type, channel=None, id=None, test=False, from_beginning=False): if self._debug_mode: log.debug('Executing: api.play_url') log.debug( 'Vars: type={type}, channel={channel}, id={id}, test={test}'. format(type=type, channel=channel, id=id, test=test)) playdata = {'path': '', 'license': '', 'token': ''} license = '' asset_id = '' militime = int(time.time() * 1000) typestr = 'PROGRAM' info = [] program_id = None if not test: while not self._abortRequested and not xbmc.Monitor( ).abortRequested() and settings.getBool(key='_test_running'): settings.setInt(key='_last_playing', value=time.time()) if self._abortRequested or xbmc.Monitor().waitForAbort(1): self._abortRequested = True break if self._abortRequested or xbmc.Monitor().abortRequested(): return playdata if type == 'channel': if not test: info_url = '{api_url}/TRAY/SEARCH/LIVE?maxResults=1&filter_airingTime=now&filter_channelIds={channel}&orderBy=airingStartTime&sortOrder=desc'.format( api_url=self._api_url, channel=channel) data = self.download(url=info_url, type='get', code=[200], data=None, json_data=False, data_return=True, return_json=True, retry=True, check_data=True) if not data or not check_key(data['resultObj'], 'containers'): if self._debug_mode: log.debug('Failure to retrieve expected data') log.debug('Execution Done: api.play_url') return playdata for row in data['resultObj']['containers']: program_id = row['id'] info = data play_url = '{api_url}/CONTENT/VIDEOURL/LIVE/{channel}/{id}/?deviceId={device_key}&profile=G02&time={time}'.format( api_url=self._api_url, channel=channel, id=id, device_key=self._devicekey, time=militime) else: if type == 'program': typestr = "PROGRAM" else: typestr = "VOD" program_id = id program_url = '{api_url}/CONTENT/USERDATA/{type}/{id}'.format( api_url=self._api_url, type=typestr, id=id) data = self.download(url=program_url, type='get', code=[200], data=None, json_data=False, data_return=True, return_json=True, retry=True, check_data=True) if not data or not check_key(data['resultObj'], 'containers'): if self._debug_mode: log.debug('Failure to retrieve expected data') log.debug('Execution Done: api.play_url') return playdata for row in data['resultObj']['containers']: if check_key(row, 'entitlement') and check_key( row['entitlement'], 'assets'): for asset in row['entitlement']['assets']: if type == 'program': if check_key(asset, 'videoType') and check_key( asset, 'programType' ) and asset['videoType'] == 'SD_DASH_PR' and asset[ 'programType'] == 'CUTV': asset_id = asset['assetId'] break else: if check_key(asset, 'videoType') and check_key( asset, 'assetType' ) and asset['videoType'] == 'SD_DASH_PR' and asset[ 'assetType'] == 'MASTER': if check_key( asset, 'rights') and asset['rights'] == 'buy': gui.ok(message=_.NO_STREAM_AUTH, heading=_.PLAY_ERROR) return playdata asset_id = asset['assetId'] break if len(unicode(asset_id)) == 0: if self._debug_mode: log.debug('Failure, empty asset_id') log.debug('Execution Done: api.play_url') return playdata play_url = '{api_url}/CONTENT/VIDEOURL/{type}/{id}/{asset_id}/?deviceId={device_key}&profile=G02&time={time}'.format( api_url=self._api_url, type=typestr, id=id, asset_id=asset_id, device_key=self._devicekey, time=militime) if self._abortRequested or xbmc.Monitor().abortRequested(): return playdata if program_id and not test: info_url = '{api_url}/CONTENT/DETAIL/{type}/{id}'.format( api_url=self._api_url, type=typestr, id=program_id) data = self.download(url=info_url, type='get', code=[200], data=None, json_data=False, data_return=True, return_json=True, retry=True, check_data=True) if not data or not check_key(data['resultObj'], 'containers'): if self._debug_mode: log.debug('Failure to retrieve expected data') log.debug('Execution Done: api.play_url') return playdata info = data if self._abortRequested or xbmc.Monitor().waitForAbort(1): return playdata data = self.download(url=play_url, type='get', code=[200], data=None, json_data=False, data_return=True, return_json=True, retry=True, check_data=True) if not data or not check_key( data['resultObj'], 'token') or not check_key( data['resultObj'], 'src') or not check_key( data['resultObj']['src'], 'sources') or not check_key( data['resultObj']['src']['sources'], 'src'): if self._debug_mode: log.debug('Failure, empty token or source') log.debug('Execution Done: api.play_url') return playdata if check_key( data['resultObj']['src']['sources'], 'contentProtection') and check_key( data['resultObj']['src']['sources']['contentProtection'], 'widevine') and check_key( data['resultObj']['src']['sources'] ['contentProtection']['widevine'], 'licenseAcquisitionURL'): license = data['resultObj']['src']['sources']['contentProtection'][ 'widevine']['licenseAcquisitionURL'] path = data['resultObj']['src']['sources']['src'] token = data['resultObj']['token'] if not test: real_url = "{hostscheme}://{netloc}".format( hostscheme=urlparse(path).scheme, netloc=urlparse(path).netloc) proxy_url = "http://127.0.0.1:{proxy_port}".format( proxy_port=settings.getInt(key='_proxyserver_port')) if self._debug_mode: log.debug('Real url: {real_url}'.format(real_url=real_url)) log.debug('Proxy url: {proxy_url}'.format(proxy_url=proxy_url)) settings.set(key='_stream_hostname', value=real_url) path = path.replace(real_url, proxy_url) settings.setInt(key='_drm_token_age', value=time.time()) settings.set(key='_renew_path', value=path) settings.set(key='_renew_token', value=token) playdata = { 'path': path, 'license': license, 'token': token, 'type': typestr, 'info': info } if self._debug_mode: log.debug( 'Returned Playdata: {playdata}'.format(playdata=playdata)) log.debug('Execution Done: api.play_url') return playdata
def test_channels(self, tested=False, channel=None): if self._debug_mode: log.debug('Executing: api.test_channels') log.debug('Vars: tested={tested}, channel={channel}'.format( tested=tested, channel=channel)) if channel: channel = unicode(channel) try: if not self._last_login_success or not settings.getBool( key='run_tests'): return 5 settings.setBool(key='_test_running', value=True) channels = load_file(file="channels.json", isJSON=True) results = load_file(file="channel_test.json", isJSON=True) count = 0 first = True last_tested_found = False test_run = False user_agent = settings.get(key='_user_agent') if not results: results = {} for row in channels: if count == 5 or (count == 1 and tested): if test_run: self.update_prefs() settings.setBool(key='_test_running', value=False) return count channeldata = self.get_channel_data(row=row) id = unicode(channeldata['channel_id']) if len(id) > 0: if channel: if not id == channel: continue elif tested and check_key(results, 'last_tested'): if unicode(results['last_tested']) == id: last_tested_found = True continue elif last_tested_found: pass else: continue if check_key(results, id) and not tested and not first: continue livebandwidth = 0 replaybandwidth = 0 live = 'false' replay = 'false' epg = 'false' guide = 'false' if settings.getInt(key='_last_playing') > int(time.time() - 300): if test_run: self.update_prefs() settings.setBool(key='_test_running', value=False) return 5 playdata = self.play_url(type='channel', channel=id, id=channeldata['asset_id'], test=True) if first and not self._last_login_success: if test_run: self.update_prefs() settings.setBool(key='_test_running', value=False) return 5 if len(playdata['path']) > 0: CDMHEADERS = CONST_BASE_HEADERS CDMHEADERS['User-Agent'] = user_agent playdata['path'] = playdata['path'].split("&", 1)[0] self._session2 = Session(headers=CDMHEADERS) resp = self._session2.get(playdata['path']) if resp.status_code == 200: livebandwidth = find_highest_bandwidth( xml=resp.text) live = 'true' if check_key(results, id) and first and not tested: first = False if live == 'true': continue else: if test_run: self.update_prefs() settings.setBool(key='_test_running', value=False) return 5 first = False counter = 0 while not self._abortRequested and not xbmc.Monitor( ).abortRequested() and counter < 5: if self._abortRequested or xbmc.Monitor().waitForAbort( 1): self._abortRequested = True break counter += 1 if settings.getInt( key='_last_playing') > int(time.time() - 300): if test_run: self.update_prefs() settings.setBool(key='_test_running', value=False) return 5 if self._abortRequested or xbmc.Monitor().abortRequested(): return 5 program_url = '{api_url}/TRAY/AVA/TRENDING/YESTERDAY?maxResults=1&filter_channelIds={channel}'.format( api_url=self._api_url, channel=channeldata['channel_id']) data = self.download(url=program_url, type='get', code=[200], data=None, json_data=False, data_return=True, return_json=True, retry=False, check_data=True) if data and check_key( data['resultObj'], 'containers') and check_key( data['resultObj']['containers'][0], 'id'): if settings.getInt( key='_last_playing') > int(time.time() - 300): if test_run: self.update_prefs() settings.setBool(key='_test_running', value=False) return 5 playdata = self.play_url( type='program', channel=id, id=data['resultObj']['containers'][0]['id'], test=True) if len(playdata['path']) > 0: CDMHEADERS = CONST_BASE_HEADERS CDMHEADERS['User-Agent'] = user_agent playdata['path'] = playdata['path'].split( "&min_bitrate", 1)[0] self._session2 = Session(headers=CDMHEADERS) resp = self._session2.get(playdata['path']) if resp.status_code == 200: replaybandwidth = find_highest_bandwidth( xml=resp.text) replay = 'true' if os.path.isfile(ADDON_PROFILE + id + '_replay.json'): guide = 'true' if live == 'true': epg = 'true' results[id] = { 'id': id, 'live': live, 'replay': replay, 'livebandwidth': livebandwidth, 'replaybandwidth': replaybandwidth, 'epg': epg, 'guide': guide, } results['last_tested'] = id if not self._abortRequested: write_file(file="channel_test.json", data=results, isJSON=True) test_run = True counter = 0 while not self._abortRequested and not xbmc.Monitor( ).abortRequested() and counter < 15: if self._abortRequested or xbmc.Monitor().waitForAbort( 1): self._abortRequested = True break counter += 1 if settings.getInt( key='_last_playing') > int(time.time() - 300): if test_run: self.update_prefs() settings.setBool(key='_test_running', value=False) return 5 if self._abortRequested or xbmc.Monitor().abortRequested(): return 5 count += 1 except: if test_run: self.update_prefs() count = 5 settings.setBool(key='_test_running', value=False) if self._debug_mode: log.debug('Execution Done: api.test_channels') return count
def login(self, username, password, channels=False, retry=True): if self._debug_mode: log.debug('Executing: api.login') log.debug('Vars: username={username}, password={password}, channels={channels}, retry={retry}'.format(username=username, password=password, channels=channels, retry=retry)) oauth = '' settings.remove(key='_cookies') self._cookies = '' settings.remove(key='_session_token') self._session_token = '' self._session = Session(cookies_key='_cookies') self._session.headers = CONST_BASE_HEADERS auth_url = '{login_url}/authenticate?redirect_uri=https%3A%2F%2Flivetv.canaldigitaal.nl%2Fauth.aspx&state={state}&response_type=code&scope=TVE&client_id=StreamGroup'.format(login_url=CONST_LOGIN_URL, state=int(time.time())) if self._debug_mode: log.debug('Clear Setting _cookies') log.debug('Creating new Requests Session') log.debug('Request Session Headers') log.debug(self._session.headers) data = self.download(url=auth_url, type="get", code=[200], data=None, json_data=False, data_return=True, return_json=False, retry=retry, check_data=False, allow_redirects=False) if not data: if self._debug_mode: log.debug('Failure to retrieve expected data') log.debug('Execution Done: api.login') gui.ok(message=_.LOGIN_ERROR, heading=_.LOGIN_ERROR_TITLE) self.clear_session() return False self._session.headers = CONST_LOGIN_HEADERS self._session.headers.update({'Referer': auth_url}) session_post_data = { "Password": password, "Username": username, } if self._debug_mode: log.debug('Request Session Headers') log.debug(self._session.headers) resp = self.download(url=CONST_LOGIN_URL, type="post", code=None, data=session_post_data, json_data=False, data_return=True, return_json=False, retry=retry, check_data=False, allow_redirects=False) if (resp.status_code != 302): if self._debug_mode: log.debug('Failure to retrieve expected data') log.debug('Execution Done: api.login') gui.ok(message=_.LOGIN_ERROR, heading=_.LOGIN_ERROR_TITLE) self.clear_session() return False params = parse_qs(urlparse(resp.headers['Location']).query) if check_key(params, 'code'): oauth = params['code'][0] if self._debug_mode: log.debug('Params: {params}'.format(params=params)) log.debug('OAuth: {oauth}'.format(oauth=oauth)) if len(oauth) == 0: if self._debug_mode: log.debug('Failure to retrieve expected data') log.debug('Execution Done: api.login') gui.ok(message=_.LOGIN_ERROR, heading=_.LOGIN_ERROR_TITLE) self.clear_session() return False challenge_url = "{base_url}/m7be2iphone/challenge.aspx".format(base_url=CONST_BASE_URL) browser_name = settings.get(key='_browser_name') session_post_data = { "autotype": "nl", "app": "cds", "prettyname": browser_name, "model": "web", "serial": self._devicekey, "oauthcode": oauth } self._session.headers = CONST_BASE_HEADERS self._session.headers.update({'Content-Type': 'application/json;charset=UTF-8'}) if self._debug_mode: log.debug('Request Session Headers') log.debug(self._session.headers) data = self.download(url=challenge_url, type="post", code=[200], data=session_post_data, json_data=True, data_return=True, return_json=True, retry=retry, check_data=False, allow_redirects=False) if not data or not check_key(data, 'id') or not check_key(data, 'secret'): if check_key(data, 'error') and data['error'] == 'toomany': gui.ok(message=_.TOO_MANY_DEVICES, heading=_.LOGIN_ERROR_TITLE) else: gui.ok(message=_.LOGIN_ERROR, heading=_.LOGIN_ERROR_TITLE) if self._debug_mode: log.debug('Failure to retrieve expected data') log.debug('Execution Done: api.login') self.clear_session() return False login_url = "{base_url}/m7be2iphone/login.aspx".format(base_url=CONST_BASE_URL) self._session.headers = CONST_BASE_HEADERS self._session.headers.update({'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'}) if self._debug_mode: log.debug('Request Session Headers') log.debug(self._session.headers) secret = '{id}\t{secr}'.format(id=data['id'], secr=data['secret']) session_post_data = { "secret": secret, "uid": self._devicekey, "app": "cds", } resp = self.download(url=login_url, type="post", code=None, data=session_post_data, json_data=False, data_return=True, return_json=False, retry=retry, check_data=False, allow_redirects=False) if (resp.status_code != 302): if self._debug_mode: log.debug('Failure to retrieve expected data') log.debug('Execution Done: api.login') gui.ok(message=_.LOGIN_ERROR, heading=_.LOGIN_ERROR_TITLE) self.clear_session() return False ssotoken_url = "{base_url}/m7be2iphone/capi.aspx?z=ssotoken".format(base_url=CONST_BASE_URL) self._session.headers = CONST_BASE_HEADERS if self._debug_mode: log.debug('Request Session Headers') log.debug(self._session.headers) data = self.download(url=ssotoken_url, type="get", code=[200], data=None, json_data=False, data_return=True, return_json=True, retry=retry, check_data=False, allow_redirects=False) if not data or not check_key(data, 'ssotoken'): if self._debug_mode: log.debug('Failure to retrieve expected data') log.debug('Execution Done: api.login') gui.ok(message=_.LOGIN_ERROR, heading=_.LOGIN_ERROR_TITLE) self.clear_session() return False session_url = "{api_url}/session".format(api_url=CONST_DEFAULT_API) session_post_data = { "sapiToken": data['ssotoken'], "deviceType": "PC", "deviceModel": browser_name, "osVersion": '{name} {version}'.format(name=settings.get(key='_os_name'), version=settings.get(key='_os_version')), "deviceSerial": self._devicekey, "appVersion": settings.get(key='_browser_version'), "brand": "cds" } self._session.headers = CONST_BASE_HEADERS self._session.headers.update({'Content-Type': 'application/json;charset=UTF-8'}) if self._debug_mode: log.debug('Request Session Headers') log.debug(self._session.headers) data = self.download(url=session_url, type="post", code=[200], data=session_post_data, json_data=True, data_return=True, return_json=True, retry=retry, check_data=False, allow_redirects=False) if not data or not check_key(data, 'token'): if self._debug_mode: log.debug('Failure to retrieve expected data') log.debug('Execution Done: api.login') gui.ok(message=_.LOGIN_ERROR, heading=_.LOGIN_ERROR_TITLE) self.clear_session() return False self._session_token = data['token'] settings.set(key='_session_token', value=self._session_token) self._session_age = time.time() settings.setInt(key='_session_age', value=self._session_age) if self._debug_mode: log.debug('Session Token: {session_token}'.format(session_token=self._session_token)) log.debug('Settings _channels_age: {channels_age}'.format(channels_age=self._channels_age)) log.debug('Time - 86400 seconds: {time}'.format(time=int(time.time() - 86400))) if channels or self._channels_age < int(time.time() - 86400): self.get_channels_for_user() self._username = username self._password = password if settings.getBool(key='save_password', default=False): set_credentials(username=username, password=password) else: set_credentials(username=username, password='') self.logged_in = True self._session.headers = CONST_BASE_HEADERS self._session.headers.update({'Authorization': 'Bearer ' + self._session_token}) if self._debug_mode: log.debug('Request Session Headers') log.debug(self._session.headers) log.debug('Execution Done: api.login') return True
def emit(signal, *args, **kwargs): log.debug("SIGNAL: {}".format(signal)) for f in _signals.get(signal, []): f(*args, **kwargs)
def get_channel_data(self, row): if self._debug_mode: log.debug('Executing: api.get_channel_data') log.debug('Vars: row={row}'.format(row=row)) asset_id = '' channeldata = { 'channel_id': '', 'channel_number': '', 'description': '', 'label': '', 'station_image_large': '', } if not check_key(row, 'metadata') or not check_key( row['metadata'], 'channelId') or not check_key( row['metadata'], 'externalId') or not check_key( row['metadata'], 'orderId') or not check_key( row['metadata'], 'channelName'): if self._debug_mode: log.debug('Failure to retrieve expected data') log.debug('Execution Done: api.get_channel_data') return channeldata if check_key(row, 'assets'): for asset in row['assets']: if check_key(asset, 'videoType') and check_key( asset, 'assetId') and asset['videoType'] == 'SD_DASH_PR': asset_id = asset['assetId'] break path = ADDON_PROFILE + "images" + os.sep + unicode( row['metadata']['channelId']) + ".png" if os.path.isfile(path): image = path else: image = '{images_url}/logo/{external_id}/256.png'.format( images_url=CONST_IMAGE_URL, external_id=row['metadata']['externalId']) channeldata = { 'channel_id': row['metadata']['channelId'], 'channel_number': int(row['metadata']['orderId']), 'description': '', 'label': row['metadata']['channelName'], 'station_image_large': image, 'asset_id': asset_id } if self._debug_mode: log.debug( 'Returned data: {channeldata}'.format(channeldata=channeldata)) log.debug('Execution Done: api.get_channel_data') return channeldata
def vod_season(self, id): if self._debug_mode: log.debug('Executing: api.vod_season') log.debug('Vars: id={id}'.format(id=id)) season = [] episodes = [] program_url = '{api_url}/CONTENT/DETAIL/BUNDLE/{id}'.format( api_url=self._api_url, id=id) file = "cache" + os.sep + "vod_season_" + unicode(id) + ".json" if self._enable_cache and not is_file_older_than_x_minutes( file=ADDON_PROFILE + file, minutes=10): data = load_file(file=file, isJSON=True) else: data = self.download(url=program_url, type='get', code=[200], data=None, json_data=False, data_return=True, return_json=True, retry=True, check_data=True) if data and check_key(data['resultObj'], 'containers') and self._enable_cache: write_file(file=file, data=data, isJSON=True) if not data or not check_key(data['resultObj'], 'containers'): if self._debug_mode: log.debug('Failure to retrieve expected data') log.debug('Execution Done: api.vod_season') return None for row in data['resultObj']['containers']: for currow in row['containers']: if check_key(currow, 'metadata') and check_key( currow['metadata'], 'season') and currow['metadata'][ 'contentSubtype'] == 'EPISODE' and not currow[ 'metadata']['episodeNumber'] in episodes: asset_id = '' for asset in currow['assets']: if check_key( asset, 'videoType' ) and asset['videoType'] == 'SD_DASH_PR' and check_key( asset, 'assetType' ) and asset['assetType'] == 'MASTER': asset_id = asset['assetId'] break episodes.append(currow['metadata']['episodeNumber']) season.append({ 'id': currow['metadata']['contentId'], 'assetid': asset_id, 'duration': currow['metadata']['duration'], 'title': currow['metadata']['episodeTitle'], 'episodeNumber': '{season}.{episode}'.format( season=currow['metadata']['season'], episode=currow['metadata']['episodeNumber']), 'desc': currow['metadata']['shortDescription'], 'image': currow['metadata']['pictureUrl'] }) if self._debug_mode: log.debug('Execution Done: api.vod_season') return season
def get_channels_for_user(self): self._session.headers = CONST_BASE_HEADERS self._session.headers.update({'Authorization': 'Bearer ' + self._session_token}) if self._debug_mode: log.debug('Executing: api.get_channels_for_user') log.debug('Request Session Headers') log.debug(self._session.headers) channels_url = "{api_url}/assets?query=channels,3&limit=999&from=0".format(api_url=CONST_DEFAULT_API); data = self.download(url=channels_url, type="get", code=[200], data=None, json_data=False, data_return=True, return_json=True, retry=True, check_data=False, allow_redirects=False) if not data or not check_key(data, 'assets'): if self._debug_mode: log.debug('Failure to retrieve expected data') log.debug('Execution Done: api.get_channels_for_user') return False write_file(file="channels.json", data=data['assets'], isJSON=True) self.create_playlist() if self._debug_mode: log.debug('Execution Done: api.get_channels_for_user') return True
def play_url(self, type, channel=None, id=None, test=False, from_beginning='False'): self._session.headers = CONST_BASE_HEADERS self._session.headers.update({'Authorization': 'Bearer ' + self._session_token}) if self._debug_mode: log.debug('Executing: api.play_url') log.debug('Vars: type={type}, channel={channel}, id={id}, test={test}'.format(type=type, channel=channel, id=id, test=test)) log.debug('Request Session Headers') log.debug(self._session.headers) playdata = {'path': '', 'license': None, 'info': None} if not type or not len(unicode(type)) > 0: if self._debug_mode: log.debug('Failure executing api.play_url, no type set') log.debug('Execution Done: api.play_url') return playdata if not test: while not self._abortRequested and not xbmc.Monitor().abortRequested() and settings.getBool(key='_test_running'): settings.setInt(key='_last_playing', value=time.time()) if self._abortRequested or xbmc.Monitor().waitForAbort(1): self._abortRequested = True break if self._abortRequested or xbmc.Monitor().abortRequested(): return playdata if type == 'channel': info_url = '{api_url}/assets/{channel}'.format(api_url=CONST_DEFAULT_API, channel=channel) else: info_url = '{api_url}/assets/{id}'.format(api_url=CONST_DEFAULT_API, id=id) play_url = info_url + '/play' if not test: data = self.download(url=info_url, type="get", code=[200], data=None, json_data=False, data_return=True, return_json=True, retry=True, check_data=True, allow_redirects=True) if not data or not check_key(data, 'id'): if self._debug_mode: log.debug('Failure to retrieve expected data') log.debug('Execution Done: api.play_url') return playdata session_post_data = { "player": { "name":"Bitmovin", "version":"8.22.0", "capabilities": { "mediaTypes": ["DASH","HLS","MSSS","Unspecified"], "drmSystems": ["Widevine"], }, "drmSystems": ["Widevine"], }, } if type == 'channel' and check_key(data, 'params') and check_key(data['params'], 'now') and check_key(data['params']['now'], 'id'): play_url2 = '{api_url}/assets/{id}/play'.format(api_url=CONST_DEFAULT_API, id=data['params']['now']['id']) info = data['params']['now'] data = self.download(url=play_url2, type="post", code=[200], data=session_post_data, json_data=True, data_return=True, return_json=True, retry=True, check_data=True, allow_redirects=True) if data and check_key(data, 'url'): if not settings.getBool(key='ask_start_from_beginning') or not gui.yes_no(message=_.START_FROM_BEGINNING, heading=info['title']): data = self.download(url=play_url, type="post", code=[200], data=session_post_data, json_data=True, data_return=True, return_json=True, retry=True, check_data=True, allow_redirects=True) else: data = self.download(url=play_url, type="post", code=[200], data=session_post_data, json_data=True, data_return=True, return_json=True, retry=True, check_data=True, allow_redirects=True) else: info = data data = self.download(url=play_url, type="post", code=[200], data=session_post_data, json_data=True, data_return=True, return_json=True, retry=True, check_data=True, allow_redirects=True) else: if self._abortRequested or xbmc.Monitor().abortRequested(): return playdata data = self.download(url=play_url, type="post", code=[200], data=session_post_data, json_data=True, data_return=True, return_json=True, retry=True, check_data=True, allow_redirects=True) if not data or not check_key(data, 'url'): if self._debug_mode: log.debug('Failure to retrieve expected data') log.debug('Execution Done: api.play_url') return playdata if check_key(data, 'drm') and check_key(data['drm'], 'licenseUrl'): license = data['drm']['licenseUrl'] path = data['url'] if not test: real_url = "{hostscheme}://{netloc}".format(hostscheme=urlparse(path).scheme, netloc=urlparse(path).netloc) proxy_url = "http://127.0.0.1:{proxy_port}".format(proxy_port=settings.getInt(key='_proxyserver_port')) if self._debug_mode: log.debug('Real url: {real_url}'.format(real_url=real_url)) log.debug('Proxy url: {proxy_url}'.format(proxy_url=proxy_url)) settings.set(key='_stream_hostname', value=real_url) path = path.replace(real_url, proxy_url) playdata = {'path': path, 'license': license, 'info': info} if self._debug_mode: log.debug('Returned Playdata: {playdata}'.format(playdata=playdata)) log.debug('Execution Done: api.play_url') return playdata