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 do_GET(self): URL = settings.get(key='_stream_hostname') + str(self.path).replace( 'WIDEVINETOKEN', settings.get(key='_drm_token')) if "manifest.mpd" in self.path or "Manifest" in self.path: HEADERS = CONST_BASE_HEADERS for header in self.headers: if self.headers[ header] is not None and header in CONST_ALLOWED_HEADERS: HEADERS[header] = self.headers[header] self._session = Session(headers=HEADERS) r = self._session.get(URL) xml = r.text xml = set_duration(xml=xml) if settings.getBool(key='force_highest_bandwidth'): xml = force_highest_bandwidth(xml=xml) if settings.getBool(key="disableac3") == True: xml = remove_ac3(xml=xml) self.send_response(r.status_code) r.headers['Content-Length'] = len(xml) for header in r.headers: if not 'Content-Encoding' in header and not 'Transfer-Encoding' in header: self.send_header(header, r.headers[header]) self.end_headers() try: xml = xml.encode('utf-8') except: pass try: self.wfile.write(xml) except: pass else: self._now_playing = time.time() try: if self._last_playing + 60 < self._now_playing: self._last_playing = time.time() settings.setInt(key='_last_playing', value=self._last_playing) except: self._last_playing = time.time() settings.setInt(key='_last_playing', value=self._last_playing) self.send_response(302) self.send_header('Location', URL) self.end_headers()
def do_GET(self): try: self._stream_url except: self._stream_url = settings.get(key='_stream_hostname') if ".mpd" in self.path: self._stream_url = settings.get(key='_stream_hostname') session = Session(cookies_key='_cookies') r = session.get(self._stream_url + str(self.path)) xml = r.text xml = set_duration(xml=xml) if settings.getBool(key='force_highest_bandwidth'): xml = force_highest_bandwidth(xml=xml) self.send_response(r.status_code) r.headers['Content-Length'] = len(xml) for header in r.headers: if not 'Content-Encoding' in header and not 'Transfer-Encoding' in header: self.send_header(header, r.headers[header]) self.end_headers() try: xml = xml.encode('utf-8') except: pass try: self.wfile.write(xml) except: pass else: self._now_playing = time.time() try: if self._last_playing + 60 < self._now_playing: self._last_playing = time.time() settings.setInt(key='_last_playing', value=self._last_playing) except: self._last_playing = time.time() settings.setInt(key='_last_playing', value=self._last_playing) self.send_response(302) self.send_header('Location', self._stream_url + str(self.path)) self.end_headers()
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 play_video(type=None, channel=None, id=None, catchup=None, duration=0, **kwargs): properties = {} if not type and not len(type) > 0: return False if (catchup and len(catchup) > 0) or type == 'program': if catchup and len(catchup) > 0: id = catchup properties['seekTime'] = 1 type = 'program' playdata = api.play_url(type=type, channel=channel, id=id) if not playdata or not check_key(playdata, 'path') or not check_key( playdata, 'token'): return False CDMHEADERS = CONST_BASE_HEADERS CDMHEADERS['User-Agent'] = settings.get(key='_user_agent') if type == 'channel': playdata['path'] = playdata['path'].split("&", 1)[0] else: playdata['path'] = playdata['path'].split("&min_bitrate", 1)[0] if check_key(playdata, 'license'): item_inputstream = inputstream.Widevine( license_key=playdata['license'], ) else: item_inputstream = inputstream.MPD() settings.setInt(key='_stream_duration', value=duration) listitem = plugin.Item( properties=properties, path=playdata['path'], headers=CDMHEADERS, inputstream=item_inputstream, ) return listitem
def get_channels_for_user(self, location): channels_url = '{channelsurl}?byLocationId={location}&includeInvisible=true&personalised=true'.format( channelsurl=settings.get('_channels_url'), location=location) 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) if data and check_key(data, 'entryCount') and check_key( data, 'channels'): settings.setInt(key='_channels_age', value=time.time()) write_file(file="channels.json", data=data['channels'], isJSON=True) playlist = u'#EXTM3U\n' for row in sorted( data['channels'], key=lambda r: float(r.get('channelNumber', 'inf'))): channeldata = self.get_channel_data(row=row) urldata = get_play_url(content=channeldata['stream']) if urldata and check_key(urldata, 'play_url') and check_key( urldata, 'locator'): path = 'plugin://{addonid}/?_=play_video&type=channel&id={play_url}&locator={locator}&_l=.pvr'.format( addonid=ADDON_ID, play_url=quote(urldata['play_url']), locator=quote(urldata['locator'])) 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) write_file(file="tv.m3u8", data=playlist, isJSON=False) combine_playlist()
def get_channels_for_user(self): channels_url = '{api_url}/TRAY/LIVECHANNELS?orderBy=orderId&sortOrder=asc&from=0&to=999&dfilter_channels=subscription'.format(api_url=settings.get(key='_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 data and check_key(data['resultObj'], 'containers'): settings.setInt(key='_channels_age', value=time.time()) write_file(file="channels.json", data=data['resultObj']['containers'], isJSON=True) playlist = u'#EXTM3U\n' for row in data['resultObj']['containers']: channeldata = self.get_channel_data(row=row) 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 += 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) write_file(file="tv.m3u8", data=playlist, isJSON=False) combine_playlist()
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 get_channels_for_user(self, channels): settings.setInt(key='_channels_age', value=time.time()) write_file(file="channels.json", data=channels, isJSON=True) data = u'#EXTM3U\n' for row in channels: channeldata = self.get_channel_data(rows=channels, row=row) path = 'plugin://{addonid}/?_=play_video&channel={channel}&type=channel&_l=.pvr'.format( addonid=ADDON_ID, channel=channeldata['channel_id']) data += 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) write_file(file="tv.m3u8", data=data, isJSON=False) combine_playlist()
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 play_video(type=None, channel=None, id=None, catchup=None, duration=0, **kwargs): properties = {} if not type and not len(type) > 0: return False if (catchup and len(catchup) > 0) or type == 'program': if catchup and len(catchup) > 0: id = catchup properties['seekTime'] = 1 type = 'program' playdata = api.play_url(type=type, channel=channel, id=id) if not playdata or not check_key(playdata, 'path') or not check_key( playdata, 'token') or not check_key(playdata, 'sessionid'): return False CDMHEADERS = { 'User-Agent': settings.get(key='_user_agent'), 'Authorization': 'Bearer ' + playdata['token'], } settings.setInt(key='_stream_duration', value=duration) listitem = plugin.Item( properties=properties, path=playdata['path'], headers=CDMHEADERS, inputstream=inputstream.Widevine(license_key=playdata['license'], ), ) return listitem
def download_epg(): settings.setInt(key='_epgrun', value=1) settings.setInt(key='_epgruntime', value=time.time()) if settings.getBool(key="minimalChannels"): resp = requests.get(url=CONST_MINIMALEPG) else: resp = requests.get(url=CONST_EPG) zipfile = ZipFile(BytesIO(resp.content)) zipfile.extractall(ADDON_PROFILE) zipfile.close() for file in glob.glob(ADDON_PROFILE + os.sep + "*_replay.xml"): if is_file_older_than_x_days(file=file, days=7): os.remove(file) for file in glob.glob(ADDON_PROFILE + os.sep + "*_replay.json"): if is_file_older_than_x_days(file=file, days=7): os.remove(file) settings.setInt("_epgrun", 0)
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 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 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 play_video(type=None, id=None, locator=None, catchup=None, duration=0, **kwargs): properties = {} label = '' info = {} art = {} if not type or not len(type) > 0: return False if (catchup and len(catchup) > 0) or type=='program': if catchup and len(catchup) > 0: id = catchup properties['seekTime'] = 1 type = 'program' if not id or not len(id) > 0: return False if type == "program": listings_url = "{listings_url}/{id}".format(listings_url=settings.get(key='_listings_url'), id=id) data = api.download(url=listings_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, 'program') or not check_key(data['program'], 'videoStreams'): gui.ok(message=_.STREAM_NOT_AVAILABLE, heading=_.STREAM_NOT_FOUND) return False urldata = get_play_url(content=data['program']['videoStreams']) if not urldata or not check_key(urldata, 'play_url') or not check_key(urldata, 'locator'): gui.ok(message=_.STREAM_NOT_AVAILABLE, heading=_.STREAM_NOT_FOUND) return False playdata = api.play_url(type='program', path=urldata['play_url'], locator=urldata['locator']) if check_key(data['program'], 'duration'): duration = int(data['program']['duration']) elif check_key(data, 'startTime') and check_key(data, 'endTime'): duration = int(int(data['endTime']) - int(data['startTime'])) // 1000 label = data['program']['title'] info = { 'plot': data['program']['description'], 'duration': duration, 'mediatype': 'video'} art = {'thumb': get_image("boxart", data['program']['images'])} elif type == "vod": playdata = api.play_url(type='vod', path=id) elif type == "channel": if not locator or not len(locator) > 0: return False playdata = api.play_url(type='channel', path=id, locator=locator) if not check_key(playdata, 'path') or not check_key(playdata, 'license') or not check_key(playdata, 'token') or not check_key(playdata, 'locator'): return False user_agent = settings.get(key='_user_agent') creds = get_credentials() CDMHEADERS = { 'User-Agent': user_agent, 'X-Client-Id': settings.get(key='_client_id') + '||' + user_agent, 'X-OESP-Token': settings.get(key='_access_token'), 'X-OESP-Username': creds['username'], 'X-OESP-License-Token': settings.get(key='_drm_token'), 'X-OESP-DRM-SchemeIdUri': 'urn:uuid:edef8ba9-79d6-4ace-a3c8-27dcd51d21ed', 'X-OESP-Content-Locator': playdata['locator'], } settings.setInt(key='_stream_duration', value=duration) listitem = plugin.Item( properties = properties, label = label, info = info, art = art, playable = True, path = playdata['path'], headers = CDMHEADERS, inputstream = inputstream.Widevine( license_key = playdata['license'], media_renewal_url = plugin.url_for(func_or_url=renew_token, id=playdata['path'], type=type, locator=playdata['locator']), media_renewal_time = 60, ), ) return listitem
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