def set_state(pin, state): if not INSTALLED: return log.debug('Set pin {} to {}'.format(pin, state)) out_pin = gpiozero.Device.pin_factory.pin(int(pin)) out_pin.output_with_state(int(state))
def _login(self, url, payload, params=None): data = self._session.post(url, data=payload, params=params).json() if 'errors' in data: try: msg = data['errors'][0]['code'] if msg == 'Streamco.Login.VPNDetected': msg = _.IP_ADDRESS_ERROR except: msg = '' raise APIError(_(_.LOGIN_ERROR, msg=msg)) userdata.set('token', data['jwToken']) userdata.set('expires', int(time.time() + (data['renew'] - data['now']) - 30)) userdata.set('user_id', data['userId']) userdata.set('profile_id', data['profile']['id']) userdata.set('profile_name', data['profile']['name']) userdata.set('profile_icon', data['profile']['iconImage']['url']) userdata.set('profile_kids', int(data['profile'].get('isKidsProfile', False))) self._set_authentication() try: log.debug('Token Data: {}'.format( json.dumps(jwt_data(userdata.get('token'))))) except: pass
def _refresh_token(self, force=False): if not force and userdata.get('expires', 0) > time() or not self.logged_in: return log.debug('Refreshing token') self._set_profile(userdata.get('profile_id'))
def process_attrib(attrib): if attrib not in e.attributes.keys(): return url = e.getAttribute(attrib) if '://' in url: e.setAttribute(attrib, PROXY_PATH + url) else: ## Fixed with https://github.com/xbmc/inputstream.adaptive/pull/606 base_url = get_parent_node(e, 'BaseURL') if base_url and not base_url.firstChild.nodeValue.endswith( '/'): base_url.firstChild.nodeValue = base_url.firstChild.nodeValue + '/' log.debug('Dash Fix: base_url / fixed') # Fixed with https://github.com/xbmc/inputstream.adaptive/pull/668 parent_template = get_parent_node(e, 'SegmentTemplate', levels=2) if parent_template: for key in parent_template.attributes.keys(): if key not in e.attributes.keys(): e.setAttribute( key, parent_template.getAttribute(key)) parent_template.parentNode.removeChild(parent_template) log.debug('Dash Fix: Double SegmentTemplate removed')
def play_channel(self, channel_id): variables = { 'deviceId': '', 'assetId': channel_id, 'channelId': channel_id, # 'playbackDevice': { # 'platform': 'Windows', # 'osVersion': '10', # 'drmType': 'WIDEVINE', # 'drmLevel': 'SW_SECURE_DECODE' # } } data = self._query_request(queries.START_LINEAR, variables)['data']['startLinearPlayback'] if data['__typename'] == 'SubscriptionNeeded': raise APIError('{} Subscription Required'.format( data['subscriptions'][0]['title'])) elif data['__typename'] == 'Geoblocked': raise APIError(_.GEO_ERROR) elif data['__typename'] != 'LinearPlaybackSources': raise APIError('Unkown error: {}'.format(data['__typename'])) try: self._query_request(queries.STOP_LINEAR, variables)['data']['stopLinearPlayback'] except: log.debug('Stop Linear Failed') return data['playbackSource']['streamUri'], data['playbackSource'][ 'drmLicense']['licenseUri']
def merged(cls): channel_updates = set() for override in Override.select(Override, Channel).join( Channel, on=(Channel.slug == Override.slug), attr='channel'): channel = override.channel for key in override.fields: if hasattr(channel, key): setattr(channel, key, override.fields[key]) else: log.debug('Skipping unknown override key: {}'.format(key)) channel.modified = True if not channel.custom else False channel.attribs.update(override.attribs) channel.properties.update(override.properties) channel_updates.add(channel) if not channel_updates: yield return with database.db.atomic() as transaction: try: Channel.bulk_update(channel_updates, fields=Channel._meta.fields) yield transaction.rollback() except Exception as e: transaction.rollback() raise
def _check_updates(): _time = int(time()) if _time < settings.getInt('_last_updates_check', 0) + UPDATES_CHECK_TIME: return settings.setInt('_last_updates_check', _time) new_md5 = session.get(ADDONS_MD5).text.split(' ')[0] if new_md5 == settings.get('addon_md5'): return settings.set('_addon_md5', new_md5) updates = [] slyguy_addons = session.gz_json(ADDONS_URL) slyguy_installed = [x['addonid'] for x in kodi_rpc('Addons.GetAddons', {'installed': True, 'enabled': True})['addons'] if x['addonid'] in slyguy_addons] for addon_id in slyguy_installed: addon = get_addon(addon_id, install=False) if not addon: continue cur_version = addon.getAddonInfo('version') new_version = slyguy_addons[addon_id]['version'] if LooseVersion(cur_version) < LooseVersion(new_version): updates.append([addon_id, cur_version, new_version]) if not updates: return log.debug('Updating repos due to {} addon updates'.format(len(updates))) xbmc.executebuiltin('UpdateAddonRepos')
def _parse_elements(elements, from_menu=False): entitlements = _get_entitlements() items = [] for elem in elements: elem['locked'] = entitlements and elem['channelCode'] not in entitlements if elem['locked'] and settings.getBool('hide_locked'): continue if elem['type'] == 'movie': item = _parse_movie(elem) elif elem['type'] == 'episode': item = _parse_episode(elem, from_menu=from_menu) elif elem['type'] == 'show': item = _parse_show(elem) elif elem['type'] == 'series': log.debug('Series! You should no longer see this. Let me know if you do...') continue else: continue items.append(item) return items
def episodes(series, season, **kwargs): series = api.series(series) folder = plugin.Folder(series['title'], fanart=_get_image(series['images'], 'fanart'), sort_methods=[ xbmcplugin.SORT_METHOD_EPISODE, xbmcplugin.SORT_METHOD_UNSORTED, xbmcplugin.SORT_METHOD_LABEL, xbmcplugin.SORT_METHOD_DATEADDED ]) for row in series['seasons']: if int(row['seasonNumber']) != int(season): continue for video in row['videos']: if not video['seasonEpisode']: log.debug('Skipping info video item: {}'.format( video['title'])) continue item = _process_video(video) folder.add_items(item) break return folder
def _manifest_middleware(self, data): url = self._session.get('manifest_middleware') if not url: return data data_path = xbmc.translatePath('special://temp/proxy.manifest') with open(data_path, 'wb') as f: f.write(data.encode('utf8')) url = add_url_args(url, _data_path=data_path, _headers=json.dumps(self._headers)) log.debug('PLUGIN MANIFEST MIDDLEWARE REQUEST: {}'.format(url)) dirs, files = run_plugin(url, wait=True) if not files: raise Exception('No data returned from plugin') path = unquote_plus(files[0]) split = path.split('|') data_path = split[0] if len(split) > 1: self._plugin_headers = dict( parse_qsl(u'{}'.format(split[1]), keep_blank_values=True)) with open(data_path, 'rb') as f: data = f.read().decode('utf8') if not ADDON_DEV: remove_file(data_path) return data
def start(): log.debug('Shared Service: Started') player = Player() proxy = Proxy() try: proxy.start() except Exception as e: log.error('Failed to start proxy server') log.exception(e) ## Inital wait on boot monitor.waitForAbort(5) try: while not monitor.abortRequested(): try: _check_news() except Exception as e: log.exception(e) try: _check_updates() except Exception as e: log.exception(e) if monitor.waitForAbort(5): break except KeyboardInterrupt: pass except Exception as e: log.exception(e) try: proxy.stop() except: pass log.debug('Shared Service: Stopped')
def _seek_file(f, index, truncate=True): cur_index = f.tell() if cur_index != index: log.debug('{} seeking from {} to {}'.format(f.name, cur_index, index)) f.seek(index, os.SEEK_SET) if truncate: f.truncate()
def _device_id(self): device_id = userdata.get('device_id') if device_id: return device_id device_id = settings.get('device_id') try: mac_address = uuid.getnode() if mac_address != uuid.getnode(): mac_address = '' except: mac_address = '' system, arch = get_system_arch() device_id = device_id.format(username=userdata.get('username'), mac_address=mac_address, system=system).strip() if not device_id: device_id = uuid.uuid4() log.debug('Raw device id: {}'.format(device_id)) device_id = hash_6(device_id, length=16) log.debug('Hashed device id: {}'.format(device_id)) userdata.set('device_id', device_id) return device_id
def device_login(self): device_id = self._device_id() payload = { 'deviceId': device_id, } data = self._request_json(DEVICE_REGISTER, type='post', json=payload, refresh_token=False) code = data['userCode'] log.debug('Device ID: {} | Device Code: {}'.format(device_id, code)) login = DeviceLogin(device_id, code) try: yield login finally: login.stop() if login.result: token_data = login.token_data() self._parse_tokens(token_data['accessToken'], token_data['idToken'])
def _get_url(self, method): url = self.path.lstrip('/').strip('\\') log.debug('{} IN: {}'.format(method, url)) self._headers = {} for header in self.headers: if header.lower() not in REMOVE_IN_HEADERS: self._headers[header.lower()] = self.headers[header] length = int(self._headers.get('content-length', 0)) self._post_data = self.rfile.read(length) if length else None self._session = PROXY_GLOBAL['session'] try: proxy_data = json.loads(get_kodi_string('_slyguy_quality')) if self._session.get('session_id') != proxy_data['session_id']: self._session = {} self._session.update(proxy_data) set_kodi_string('_slyguy_quality', '') except: pass PROXY_GLOBAL['session'] = self._session url = self._session.get('path_subs', {}).get(url) or url if url.lower().startswith('plugin'): url = self._update_urls(url, self._plugin_request(url)) return url
def get_integrations(): try: return Session().gz_json(INTEGRATIONS_URL) except Exception as e: log.debug('Failed to get integrations') log.exception(e) return {}
def _market_id(self): try: return self._session.get(MARKET_ID_URL, params={ 'apikey': 'web' }).json()['_id'] except: log.debug('Failed to get market id') return '-1'
def _refresh_token(self, force=False): if not force and userdata.get('expires', 0) > time() or not self.logged_in: return log.debug('Refreshing token') data = self._session.get(API_URL+'identity/refresh/{}'.format(userdata.get('refresh_token'))).json() self._process_token(data)
def callback(): function = settings.get('function') if not settings.getBool('silent', False): gui.notification(_(_.RUN_FUNCTION, function=function)) log.debug('Running function: {}'.format(function)) xbmc.executebuiltin(function)
def _plugin_request(self, url): log.debug('PLUGIN REQUEST: {}'.format(url)) dirs, files = run_plugin(url, wait=True) if not files: raise Exception('No data returned from plugin') data = json.loads(unquote_plus(files[0])) self._headers.update(data.get('headers', {})) return data['url']
def _process_source(self, source, method_name, file_path): remove_file(file_path) path = source.path.strip() source_type = source.source_type archive_type = source.archive_type if source_type == Source.TYPE_ADDON: addon_id = path addon, data = merge_info(addon_id, self.integrations, merging=True) if method_name not in data: raise Error('{} could not be found for {}'.format( method_name, addon_id)) template_tags = { '$ID': addon_id, '$FILE': file_path, '$IP': xbmc.getIPAddress(), } path = data[method_name] for tag in template_tags: path = path.replace(tag, template_tags[tag]) path = path.strip() if path.lower().startswith('plugin'): self._call_addon_method(path) return if path.lower().startswith('http'): source_type = Source.TYPE_URL else: source_type = Source.TYPE_FILE archive_extensions = { '.gz': Source.ARCHIVE_GZIP, '.xz': Source.ARCHIVE_XZ, } name, ext = os.path.splitext(path.lower()) archive_type = archive_extensions.get(ext, Source.ARCHIVE_NONE) if source_type == Source.TYPE_URL and path.lower().startswith('http'): log.debug('Downloading: {} > {}'.format(path, file_path)) Session().chunked_dl(path, file_path) elif not xbmcvfs.exists(path): raise Error(_(_.LOCAL_PATH_MISSING, path=path)) else: log.debug('Copying local file: {} > {}'.format(path, file_path)) xbmcvfs.copy(path, file_path) if archive_type == Source.ARCHIVE_GZIP: gzip_extract(file_path) elif archive_type == Source.ARCHIVE_XZ: xz_extract(file_path)
def stop(self): if not self.started: return self._server.shutdown() self._server.server_close() self._server.socket.close() self._httpd_thread.join() self.started = False log.debug("Proxy: Stopped")
def _parse_m3u8(self, response): m3u8 = response.stream.content.decode('utf8') is_master = False if '#EXTM3U' not in m3u8: raise Exception('Invalid m3u8') if '#EXT-X-STREAM-INF' in m3u8: is_master = True file_name = 'master' else: file_name = 'sub' if ADDON_DEV: start = time.time() _m3u8 = m3u8.encode('utf8') _m3u8 = b"\n".join( [ll.rstrip() for ll in _m3u8.splitlines() if ll.strip()]) with open( xbmc.translatePath('special://temp/' + file_name + '-in.m3u8'), 'wb') as f: f.write(_m3u8) if is_master: m3u8 = self._manifest_middleware(m3u8) m3u8 = self._parse_m3u8_master(m3u8, response.url) else: m3u8 = self._parse_m3u8_sub(m3u8, response.url) base_url = urljoin(response.url, '/') m3u8 = re.sub(r'^/', r'{}'.format(base_url), m3u8, flags=re.I | re.M) m3u8 = re.sub(r'URI="/', r'URI="{}'.format(base_url), m3u8, flags=re.I | re.M) ## Convert to proxy paths m3u8 = re.sub(r'(https?)://', r'{}\1://'.format(PROXY_PATH), m3u8, flags=re.I) m3u8 = m3u8.encode('utf8') if ADDON_DEV: m3u8 = b"\n".join( [ll.rstrip() for ll in m3u8.splitlines() if ll.strip()]) log.debug('Time taken: {}'.format(time.time() - start)) with open( xbmc.translatePath('special://temp/' + file_name + '-out.m3u8'), 'wb') as f: f.write(m3u8) response.stream.content = m3u8
def _middleware(self, url, response): if url not in self._session.get('middleware', {}): return middleware = self._session['middleware'][url].copy() _type = middleware.pop('type') if _type not in middlewares: return log.debug('MIDDLEWARE: {}'.format(_type)) return middlewares[_type](response, **middleware)
def stop(self): if not self.started: return self._server.shutdown() self._server.server_close() self._server.socket.close() self._httpd_thread.join() self.started = False log.debug("API: Stopped") userdata.set('_playlist_url', '') userdata.set('_epg_url', '')
def setup_buttons(): log.debug('Setting up buttons') try: database.connect() Button.update(status=Button.Status.INACTIVE, error=None).where(Button.enabled == True).execute() Button.update(status=Button.Status.DISABLED, error=None).where(Button.enabled == False).execute() btns = list(Button.select().where(Button.enabled == True)) buttons = [] for btn in btns: if not btn.has_callbacks(): continue try: button = gpiozero.Button(btn.pin, pull_up=btn.pull_up, bounce_time=btn.bounce_time or None, hold_time=btn.hold_time, hold_repeat=btn.hold_repeat) if btn.when_pressed: button.when_pressed = lambda function=btn.when_pressed: callback( function) if btn.when_released: button.when_released = lambda function=btn.when_released: callback( function) if btn.when_held: button.when_held = lambda function=btn.when_held: callback( function) except Exception as e: log.exception(e) btn.status = Button.Status.ERROR btn.error = e else: btn.status = Button.Status.ACTIVE buttons.append(button) btn.save() return buttons except Exception as e: log.debug(e) return [] finally: database.close()
def _refresh_token(self, force=False): if not force and userdata.get('expires', 0) > time() or not self.logged_in: return log.debug('Refreshing token') payload = { 'platformId': 'android', 'regsource': '7plus', 'refreshToken': userdata.get('refresh_token'), } self._oauth_token(payload)
def login(self, username, password, kickdevice=None): self.logout() raw_id = self._format_id(settings.get('device_id')).lower() device_id = hashlib.sha1(raw_id.encode('utf8')).hexdigest() log.debug('Raw device id: {}'.format(raw_id)) log.debug('Hashed device id: {}'.format(device_id)) hex_password = self._hex_password(password, device_id) params = { 'appID': APP_ID, 'format': 'json', } payload = { 'username': username, 'password': hex_password, 'deviceId': device_id, 'accountType': 'foxtel', } if kickdevice: payload['deviceToKick'] = kickdevice log.debug('Kicking device: {}'.format(kickdevice)) data = self._session.post( '/auth.class.api.php/logon/{site_id}'.format(site_id=VOD_SITEID), data=payload, params=params).json() response = data['LogonResponse'] devices = response.get('CurrentDevices', []) error = response.get('Error') success = response.get('Success') if error: if not devices or kickdevice: raise APIError(_(_.LOGIN_ERROR, msg=error.get('Message'))) options = [d['Nickname'] for d in devices] index = gui.select(_.DEREGISTER_CHOOSE, options) if index < 0: raise APIError(_(_.LOGIN_ERROR, msg=error.get('Message'))) kickdevice = devices[index]['DeviceID'] return self.login(username, password, kickdevice=kickdevice) userdata.set('token', success['LoginToken']) userdata.set('deviceid', success['DeviceId']) userdata.set('entitlements', success.get('Entitlements', '')) if settings.getBool('save_password', False): userdata.set('pswd', password) log.debug('Password Saved') self.logged_in = True
def _parse_m3u8_sub(self, m3u8, master_url): lines = [] for line in m3u8.splitlines(): if not line.startswith('#') and '/beacon?' in line.lower(): parse = urlparse(line) params = dict(parse_qsl(parse.query)) for key in params: if key.lower() == 'redirect_path': line = params[key] log.debug('M3U8 Fix: Beacon removed') lines.append(line) return '\n'.join(lines)
def _refresh_token(self, force=False): if not force and userdata.get('expires', 0) > time() or not self.logged_in: return log.debug('Refreshing token') payload = { 'client_id': CLIENT_ID, 'refresh_token': userdata.get('refresh_token'), 'grant_type': 'refresh_token', 'scope': 'openid profile email offline_access', } self._oauth_token(payload)