def update_api_url(): settingsJSON = load_file(file='settings.json', isJSON=True) try: settings.set(key='_api_url', value=settingsJSON['api_url']) except: settings.set(key='_api_url', value=CONST_DEFAULT_API)
def update_user_agent(): settingsJSON = load_file(file='settings.json', isJSON=True) try: settings.set(key='_user_agent', value=settingsJSON['user_agent']) except: settings.set(key='_user_agent', value=DEFAULT_USER_AGENT)
def update_img_size(): settingsJSON = load_file(file='settings.json', isJSON=True) try: settings.set(key='_img_size', value=settingsJSON['img_size']) except: settings.set(key='_img_size', value=CONST_DEFAULT_IMG_SIZE)
def search(query=None, **kwargs): items = [] if not query: query = gui.input(message=_.SEARCH, default='').strip() if not query: return for x in reversed(list(range(2, 10))): settings.set(key='_search' + unicode(x), value=settings.get(key='_search' + unicode(x - 1))) settings.set(key='_search1', value=query) folder = plugin.Folder(title=_(_.SEARCH_FOR, query=query)) data = load_file(file='list_replay.json', isJSON=True) processed = process_replaytv_search(data=data, start=0, search=query) items += processed['items'] items[:] = sorted(items, key=_sort_replay_items, reverse=True) items = items[:25] folder.add_items(items) return folder
def login(**kwargs): if len(settings.get(key='_devicekey')) == 0: settings.set(key='_devicekey', value=''.join( random.choice(string.ascii_uppercase + string.ascii_lowercase + string.digits) for _ in range(64))) creds = get_credentials() username = gui.numeric(message=_.ASK_USERNAME, default=creds['username']).strip() if not len(username) > 0: gui.ok(message=_.EMPTY_USER, heading=_.LOGIN_ERROR_TITLE) return password = gui.numeric(message=_.ASK_PASSWORD).strip() if not len(password) > 0: gui.ok(message=_.EMPTY_PASS, heading=_.LOGIN_ERROR_TITLE) return api.login(username=username, password=password, channels=True) plugin.logged_in = api.logged_in gui.refresh()
def _reset(**kwargs): if not gui.yes_no(_.PLUGIN_RESET_YES_NO): return _close() try: xbmc.executeJSONRPC( '{{"jsonrpc":"2.0","id":1,"method":"Addons.SetAddonEnabled","params":{{"addonid":"{}","enabled":false}}}}' .format(ADDON_ID)) proxyport = settings.getInt(key='_proxyserver_port') shutil.rmtree(ADDON_PROFILE) settings.setInt(key='_proxyserver_port', value=proxyport) system, arch = get_system_arch() settings.set(key="_system", value=system) settings.set(key="_arch", value=arch) download_files() update_settings() change_icon() except: pass xbmc.executeJSONRPC( '{{"jsonrpc":"2.0","id":1,"method":"Addons.SetAddonEnabled","params":{{"addonid":"{}","enabled":true}}}}' .format(ADDON_ID)) gui.notification(_.PLUGIN_RESET_OK) signals.emit(signals.AFTER_RESET) gui.refresh()
def startup(): system, arch = get_system_arch() settings.set(key="_system", value=system) settings.set(key="_arch", value=arch) settings.setInt(key='_proxyserver_port', value=find_free_port()) hourly() daily() change_icon() if settings.getBool(key='enable_simple_iptv') == True: try: IPTV_SIMPLE = xbmcaddon.Addon(id="pvr.iptvsimple") if IPTV_SIMPLE.getSetting("epgPath") == ( ADDON_PROFILE + "epg.xml") and IPTV_SIMPLE.getSetting("m3uPath") == ( ADDON_PROFILE + "playlist.m3u8"): user_agent = settings.get(key='_user_agent') if IPTV_SIMPLE.getSetting("userAgent") != user_agent: IPTV_SIMPLE.setSetting("userAgent", user_agent) xbmc.executeJSONRPC( '{{"jsonrpc":"2.0","id":1,"method":"Addons.SetAddonEnabled","params":{{"addonid":"{}","enabled":false}}}}' .format(IPTV_SIMPLE_ADDON_ID)) xbmc.sleep(2000) xbmc.executeJSONRPC( '{{"jsonrpc":"2.0","id":1,"method":"Addons.SetAddonEnabled","params":{{"addonid":"{}","enabled":true}}}}' .format(IPTV_SIMPLE_ADDON_ID)) except: pass
def get_play_token(self, locator, force=False): if settings.getInt(key='_drm_token_age') < int(time.time() - 50) and ( settings.getInt(key='_tokenrun') == 0 or settings.getInt(key='_tokenruntime') < int(time.time() - 30)): force = True if locator != settings.get(key='_drm_locator') or settings.getInt( key='_drm_token_age') < int(time.time() - 90) or force == True: settings.setInt(key='_tokenrun', value=1) settings.setInt(key='_tokenruntime', value=time.time()) data = self.download(url=settings.get(key='_token_url'), type="post", code=[200], data={"contentLocator": locator}, json_data=True, data_return=True, return_json=True, retry=True, check_data=False) if not data or not check_key(data, 'token'): settings.setInt(key="_tokenrun", value=0) return None settings.set(key='_drm_token', value=data['token']) settings.setInt(key='_drm_token_age', value=time.time()) settings.set(key='_drm_locator', value=locator) settings.setInt(key="_tokenrun", value=0) return data['token'] return settings.get(key='_drm_token')
def download_epg(): settings.setInt(key='_epgrun', value=1) settings.setInt(key='_epgruntime', value=time.time()) if settings.getBool(key="minimalChannels"): url = CONST_MINIMALEPG else: url = CONST_EPG if ADDON_ID == "plugin.video.ziggo" and settings.getBool(key='_base_v3') == True: url = url.replace('epg.xml.', 'epg.xml.v3.') resp = requests.get(url=url) settings.set(key='_epg_md5', value=hashlib.md5(resp.content).hexdigest()) zipfile = ZipFile(BytesIO(resp.content)) zipfile.extractall(ADDON_PROFILE) zipfile.close() for file in glob.glob(ADDON_PROFILE + "*_replay.xml"): if is_file_older_than_x_days(file=file, days=7): os.remove(file) for file in glob.glob(ADDON_PROFILE + "*_replay.json"): if is_file_older_than_x_days(file=file, days=7): os.remove(file) settings.setInt("_epgrun", 0)
def download_vod(): url = CONST_VOD if ADDON_ID == "plugin.video.ziggo" and settings.getBool(key='_base_v3') == True: url = url.replace('vod.', 'vod.v3.') resp = requests.get(url=url) write_file(file='vod.json', data=resp.text, isJSON=False) settings.set(key='_vod_md5', value=hashlib.md5(resp.content).hexdigest())
def search(query=None, **kwargs): items = [] if not query: query = gui.input(message=_.SEARCH, default='').strip() if not query: return for x in reversed(list(range(2, 10))): settings.set(key='_search' + unicode(x), value=settings.get(key='_search' + unicode(x - 1))) settings.set(key='_search1', value=query) folder = plugin.Folder(title=_(_.SEARCH_FOR, query=query)) data = load_file(file='list_replay.json', isJSON=True) processed = process_replaytv_search(data=data, start=0, search=query) items += processed['items'] if settings.getBool('showMoviesSeries') == True: processed = process_vod_content(data=load_file(file='vod.json', isJSON=True)['series'], start=0, search=query, type=_.SERIES) items += processed['items'] processed = process_vod_content(data=load_file(file='vod.json', isJSON=True)['movies'], start=0, search=query, type=_.MOVIES) items += processed['items'] processed = process_vod_content(data=load_file( file='vod.json', isJSON=True)['kidsseries'], start=0, search=query, type=_.KIDS_SERIES) items += processed['items'] processed = process_vod_content(data=load_file( file='vod.json', isJSON=True)['kidsmovies'], start=0, search=query, type=_.KIDS_MOVIES) items += processed['items'] items[:] = sorted(items, key=_sort_replay_items, reverse=True) items = items[:25] folder.add_items(items) return folder
def download_images(): resp = requests.get(url=CONST_IMAGES) settings.set(key='_images_md5', value=hashlib.md5(resp.content).hexdigest()) zipfile = ZipFile(BytesIO(resp.content)) zipfile.extractall(ADDON_PROFILE) zipfile.close() for file in glob.glob(ADDON_PROFILE + "images" + os.sep + "*.png"): if is_file_older_than_x_days(file=file, days=7): os.remove(file)
def online_search(query=None, **kwargs): if not query: query = gui.input(message=_.SEARCH, default='').strip() if not query: return for x in reversed(list(range(2, 10))): settings.set(key='_search' + unicode(x), value=settings.get(key='_search' + unicode(x - 1))) settings.set(key='_search_type' + unicode(x), value=settings.get(key='_search_type' + unicode(x - 1))) settings.set(key='_search1', value=query) settings.set(key='_search_type1', value=' (Online)') folder = plugin.Folder(title=_(_.SEARCH_FOR, query=query)) data = api.online_search(search=query, vod=settings.getBool('showMoviesSeries')) if data: processed = process_online_search(data=data) if processed: folder.add_items(processed) return folder
def download_settings(): resp = requests.get(url=CONST_SETTINGS) write_file(file='settings.json', data=resp.text, isJSON=False) if settings.getBool(key='enable_radio') == True: resp = requests.get(url=CONST_RADIO) write_file(file='radio.m3u8', data=resp.text, isJSON=False) combine_playlist() settingsJSON = load_file(file='settings.json', isJSON=True) try: settings.set(key='_user_agent', value=settingsJSON['user_agent']) except: settings.set(key='_user_agent', value=DEFAULT_USER_AGENT)
def update_os_browser(): user_agent = settings.get(key='_user_agent') settings.set(key='_browser_name', value=uaparser.detect(user_agent)['browser']['name']) settings.set(key='_browser_version', value=uaparser.detect(user_agent)['browser']['version']) settings.set(key='_os_name', value=uaparser.detect(user_agent)['os']['name']) settings.set(key='_os_version', value=uaparser.detect(user_agent)['os']['version'])
def set_credentials(username, password): encoded = Credentials().encode_credentials(username, password) try: settings.set(key='_username', value=encoded['username'].decode('utf-8')) except: settings.set(key='_username', value=encoded['username']) try: settings.set(key='_pswd', value=encoded['password'].decode('utf-8')) except: settings.set(key='_pswd', value=encoded['password'])
def login(self, username, password, channels=False): settings.remove(key='_access_token') user_agent = settings.get(key='_user_agent') HEADERS = { 'User-Agent': user_agent, 'X-Client-Id': settings.get(key='_client_id') + "||" + user_agent, 'X-OESP-Token': '', 'X-OESP-Username': username, } self._session = Session(headers=HEADERS) data = self.download(url=settings.get(key='_session_url'), type="post", code=[200], data={ "username": username, "password": password }, json_data=True, data_return=True, return_json=True, retry=True, check_data=False) if not data or not check_key(data, 'oespToken'): gui.ok(message=_.LOGIN_ERROR, heading=_.LOGIN_ERROR_TITLE) return settings.set(key='_access_token', value=data['oespToken']) self._session.headers.update({'X-OESP-Token': data['oespToken']}) if channels == True or settings.getInt( key='_channels_age') < int(time.time() - 86400): self.get_channels_for_user(location=data['locationId']) if settings.getBool(key='save_password', default=False): set_credentials(username=username, password=password) else: set_credentials(username=username, password='') self.logged_in = True
def startup(): settings.setBool(key='_test_running', value=False) system, arch = get_system_arch() settings.set(key="_system", value=system) settings.set(key="_arch", value=arch) settings.setInt(key='_proxyserver_port', value=find_free_port()) channels = False if settings.getInt(key='_channels_age') < int(time.time() - 86400): channels = True api.new_session(force=False, retry=False, channels=channels) api.update_prefs() hourly(type=0) daily() change_icon() hourly(type=2)
def update_settings(): settingsJSON = load_file(file='settings.json', isJSON=True) try: base = settingsJSON['settings']['urls']['base'] if settings.getBool(key='_base_v3'): basethree = settingsJSON['settings']['urls']['alternativeAjaxBase'] else: basethree = base complete_base_url = '{base_url}/{country_code}/{language_code}'.format(base_url=basethree, country_code=settingsJSON['settings']['countryCode'], language_code=settingsJSON['settings']['languageCode']) settings.set(key='_base_url', value=complete_base_url + '/web') settings.set(key='_search_url', value=settingsJSON['settings']['routes']['search'].replace(base, basethree)) settings.set(key='_session_url', value=settingsJSON['settings']['routes']['session'].replace(base, basethree)) #settings.set(key='_token_url', value=settingsJSON['settings']['routes']['refreshToken'].replace(base, basethree)) settings.set(key='_channels_url', value=settingsJSON['settings']['routes']['channels'].replace(base, basethree)) settings.set(key='_token_url', value='{complete_base_url}/web/license/token'.format(complete_base_url=complete_base_url)) settings.set(key='_widevine_url', value='{complete_base_url}/web/license/eme'.format(complete_base_url=complete_base_url)) settings.set(key='_listings_url', value=settingsJSON['settings']['routes']['listings'].replace(base, basethree)) settings.set(key='_mediaitems_url', value=settingsJSON['settings']['routes']['mediaitems'].replace(base, basethree)) settings.set(key='_mediagroupsfeeds_url', value=settingsJSON['settings']['routes']['mediagroupsfeeds'].replace(base, basethree)) settings.set(key='_watchlist_url', value=settingsJSON['settings']['routes']['watchlist'].replace(base, basethree)) except: pass try: client_id = settingsJSON['client_id'] except: client_id = CONST_DEFAULT_CLIENTID settings.set(key='_client_id', value=client_id)
def play_url(self, type, channel=None, id=None): playdata = {'path': '', 'license': '', 'token': ''} license = '' asset_id = '' militime = int(time.time() * 1000) if type == 'channel': play_url = '{api_url}/CONTENT/VIDEOURL/LIVE/{channel}/{id}/?deviceId={device_key}&profile=G02&time={time}'.format(api_url=settings.get(key='_api_url'), channel=channel, id=id, device_key=settings.get(key='_devicekey'), time=militime) else: if type == 'program': typestr = "PROGRAM" else: typestr = "VOD" program_url = '{api_url}/CONTENT/USERDATA/{type}/{id}'.format(api_url=settings.get(key='_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'): 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(str(asset_id)) == 0: return playdata play_url = '{api_url}/CONTENT/VIDEOURL/{type}/{id}/{asset_id}/?deviceId={device_key}&profile=G02&time={time}'.format(api_url=settings.get(key='_api_url'), type=typestr, id=id, asset_id=asset_id, device_key=settings.get(key='_devicekey'), time=militime) 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'): 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'] real_url = "{hostscheme}://{hostname}".format(hostscheme=urlparse(path).scheme, hostname=urlparse(path).hostname) proxy_url = "http://127.0.0.1:{proxy_port}".format(proxy_port=settings.get(key='_proxyserver_port')) settings.set(key='_stream_hostname', value=real_url) path = path.replace(real_url, proxy_url) playdata = {'path': path, 'license': license, 'token': token} return playdata
def play_url(self, type, channel=None, id=None): playdata = {'path': '', 'license': '', 'token': '', 'sessionid': ''} if not type or not len(type) > 0: return playdata if type == 'channel' and channel: channel_url = 'https://www.tv-anywhere.nl/api/guide/details/{channel}'.format( channel=channel) data = self.download(url=channel_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, 'id'): return playdata id = data['id'] if not id: return playdata self._session.headers.update( {'Authorization': 'Bearer ' + settings.get(key='_session_token')}) session_post_data = { "DispatchTime": time.time(), "BusinessUnit": settings.get(key='_emp_businessunit'), "Customer": settings.get(key='_emp_customer'), "Payload": { 'Timestamp': time.time(), 'EventType': 'Playback.Aborted', 'OffsetTime': time.time(), }, "SessionId": settings.get(key='_play_session_id'), "ClockOffset": 0, } eventsink_send_url = '{emp_url}/eventsink/send'.format( emp_url=settings.get(key='_emp_url')) self.download(url=eventsink_send_url, type="post", code=None, data=session_post_data, json_data=True, data_return=False, return_json=False, retry=False, check_data=False) session_post_data = { "drm": "CENC", "format": "DASH", "type": "application/dash+xml", } play_url_path = '{emp_url}/v1/customer/{emp_customer}/businessunit/{emp_businessunit}/entitlement/channel/{channel}/program/{id}/play'.format( emp_url=settings.get(key='_emp_url'), emp_customer=settings.get(key='_emp_customer'), emp_businessunit=settings.get(key='_emp_businessunit'), channel=channel, id=id) data = self.download(url=play_url_path, type="post", code=[200], data=session_post_data, json_data=True, data_return=True, return_json=True, retry=True, check_data=True) if not data or check_key(data, 'message') or not check_key( data, 'cencConfig') or not check_key( data, 'mediaLocator') or not check_key( data, 'playSessionId'): return playdata license = data['cencConfig']['com.widevine.alpha'] path = data['mediaLocator'] sessionid = data['playSessionId'] token = data['playToken'] settings.set(key='_play_session_id', value=sessionid) session_post_data = { "BusinessUnit": settings.get(key='_emp_businessunit'), "Customer": settings.get(key='_emp_customer'), "SessionId": settings.get(key='_play_session_id'), } eventsink_init_url = '{emp_url}/eventsink/init'.format( emp_url=settings.get(key='_emp_url')) self.download(url=eventsink_init_url, type="post", code=None, data=session_post_data, json_data=True, data_return=False, return_json=False, retry=False, check_data=False) real_url = "{hostscheme}://{hostname}".format( hostscheme=urlparse(path).scheme, hostname=urlparse(path).hostname) proxy_url = "http://127.0.0.1:{proxy_port}".format( proxy_port=settings.get(key='_proxyserver_port')) settings.set(key='_stream_hostname', value=real_url) path = path.replace(real_url, proxy_url) playdata = { 'path': path, 'license': license, 'token': token, 'sessionid': sessionid } return playdata
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 play_url(self, type, path=None, locator=None): playdata = {'path': '', 'license': '', 'token': '', 'locator': ''} if not type or not len(type) > 0: return playdata if type == 'vod': if not path or not len(path) > 0: return playdata mediaitems_url = '{mediaitems_url}/{path}'.format( mediaitems_url=settings.get(key='_mediaitems_url'), path=path) data = self.download(url=mediaitems_url, type="get", code=[200], data=None, json_data=False, data_return=True, return_json=True, retry=True, check_data=False) if not data or not check_key(data, 'videoStreams'): return playdata urldata = get_play_url(content=data['videoStreams']) if urldata and check_key(urldata, 'play_url') and check_key( urldata, 'locator'): path = urldata['play_url'] locator = urldata['locator'] if not path or not locator or not len(path) > 0 or not len( locator) > 0: return playdata license = settings.get('_widevine_url') token = self.get_play_token(locator=locator, force=True) if not token or not len(token) > 0: gui.ok(message=_.NO_STREAM_AUTH, heading=_.PLAY_ERROR) return playdata token = 'WIDEVINETOKEN' token_regex = re.search(r"(?<=;vxttoken=)(.*?)(?=/)", path) if token_regex and token_regex.group(1) and len( token_regex.group(1)) > 0: path = path.replace(token_regex.group(1), token) else: if 'sdash/' in path: spliturl = path.split('sdash/', 1) if len(spliturl) == 2: path = '{urlpart1}sdash;vxttoken={token}/{urlpart2}?device=Orion-Replay-DASH'.format( urlpart1=spliturl[0], token=token, urlpart2=spliturl[1]) else: spliturl = path.rsplit('/', 1) if len(spliturl) == 2: path = '{urlpart1};vxttoken={token}/{urlpart2}'.format( urlpart1=spliturl[0], token=token, urlpart2=spliturl[1]) real_url = "{hostscheme}://{hostname}".format( hostscheme=urlparse(path).scheme, hostname=urlparse(path).hostname) proxy_url = "http://127.0.0.1:{proxy_port}".format( proxy_port=settings.get(key='_proxyserver_port')) settings.set(key='_stream_hostname', value=real_url) path = path.replace(real_url, proxy_url) playdata = { 'path': path, 'license': license, 'token': token, 'locator': locator } return playdata
def login(self, username, password, channels=False): settings.remove(key='_cookies') self._session = Session(cookies_key='_cookies') login_url = '{base_url}/inloggen'.format(base_url=CONST_BASE_URL) resp = self.download(url=login_url, type="get", code=None, data=None, json_data=False, data_return=True, return_json=False, retry=False, check_data=False) if resp.status_code != 200 and resp.status_code != 302: gui.ok(message=_.LOGIN_ERROR, heading=_.LOGIN_ERROR_TITLE) self.clear_session() return if self.check_data(resp=resp) == False: resp.encoding = 'utf-8' frmtoken = re.findall( r'name=\"form\[_token\]\"\s+value=\"([\S]*)\"', resp.text) session_post_data = { "form[password]": password, "form[email]": username, "form[login]": '', 'form[_token]': frmtoken[0], } resp = self.download(url=login_url, type="post", code=None, data=session_post_data, json_data=False, data_return=True, return_json=False, retry=False, check_data=False) if (resp.status_code != 200 and resp.status_code != 302) or self.check_data( resp=resp) == False: gui.ok(message=_.LOGIN_ERROR, heading=_.LOGIN_ERROR_TITLE) self.clear_session() return data = self.download( url='{base_url}/api/info'.format(base_url=CONST_BASE_URL), type="get", code=[200], data=None, json_data=False, data_return=True, return_json=True, retry=False, check_data=True) if not data or not check_key(data, 'sessionToken') or not check_key( data, 'emp'): gui.ok(message=_.LOGIN_ERROR, heading=_.LOGIN_ERROR_TITLE) self.clear_session() return settings.set(key='_session_token', value=data['sessionToken']) settings.set(key='_emp_url', value=data['emp']['url']) settings.set(key='_emp_customer', value=data['emp']['customer']) settings.set(key='_emp_businessunit', value=data['emp']['businessunit']) if channels == True or settings.getInt( key='_channels_age') < int(time.time() - 86400): self.get_channels_for_user(channels=data['channels']) if settings.getBool(key='save_password', default=False): set_credentials(username=username, password=password) else: set_credentials(username=username, password='') self.logged_in = True
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 update_settings(): settingsJSON = load_file(file='settings.json', isJSON=True) try: license_url = '{base_url}/{country_code}/{language_code}'.format(base_url=settingsJSON['settings']['urls']['base'], country_code=settingsJSON['settings']['countryCode'], language_code=settingsJSON['settings']['languageCode']) settings.set(key='_search_url', value=settingsJSON['settings']['routes']['search']) settings.set(key='_session_url', value=settingsJSON['settings']['routes']['session']) settings.set(key='_token_url', value=settingsJSON['settings']['routes']['refreshToken']) settings.set(key='_channels_url', value=settingsJSON['settings']['routes']['channels']) settings.set(key='_token_url', value='{license_url}/web/license/token'.format(license_url=license_url)) settings.set(key='_widevine_url', value='{license_url}/web/license/eme'.format(license_url=license_url)) settings.set(key='_listings_url', value=settingsJSON['settings']['routes']['listings']) settings.set(key='_mediaitems_url', value=settingsJSON['settings']['routes']['mediaitems']) settings.set(key='_mediagroupsfeeds_url', value=settingsJSON['settings']['routes']['mediagroupsfeeds']) settings.set(key='_watchlist_url', value=settingsJSON['settings']['routes']['watchlist']) except: pass try: client_id = settingsJSON['client_id'] except: client_id = CONST_DEFAULT_CLIENTID settings.set(key='_client_id', value=client_id)
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