def __init__(self, util, listeners, rows, columns, voice_assistant, d=None, turn_page=None, page_in_title=True, show_loading=False): """ Initializer :param util: utility object :param listeners: file browser listeners :param rows: menu rows :param d: dictionary with menu button flags :param turn_page: turn page callback :param util: utility object """ self.util = util self.config = util.config self.factory = Factory(util) self.bounding_box = util.screen_rect self.player = None self.turn_page = turn_page self.page_in_title = page_in_title self.show_loading = show_loading self.cache = Cache(self.util) self.layout = BorderLayout(self.bounding_box) self.layout.set_percent_constraints(PERCENT_TOP_HEIGHT, PERCENT_BOTTOM_HEIGHT, 0, 0) Screen.__init__(self, util, "", PERCENT_TOP_HEIGHT, voice_assistant, "menu_screen_screen_title", True, self.layout.TOP) color_dark_light = self.config[COLORS][COLOR_DARK_LIGHT] self.menu_layout = self.layout.CENTER if d: self.menu_button_layout = self.get_menu_button_layout(d) self.img_rect = self.menu_button_layout.image_rectangle listeners[GO_LEFT_PAGE] = self.previous_page listeners[GO_RIGHT_PAGE] = self.next_page try: self.navigator = BookNavigator(util, self.layout.BOTTOM, listeners, color_dark_light, d[4]) Container.add_component(self, None) Container.add_component(self, self.navigator) except: Container.add_component(self, None) self.total_pages = 0 self.current_page = 1 self.menu = None
def get(self, user_id, page_id): ratelimit_key = self.ratelimit_key_template % self.request.remote_ip remote_ip_rate = Cache.incr(ratelimit_key) if remote_ip_rate is None: Cache.set(ratelimit_key, 1, time=60) elif remote_ip_rate > 60: self.set_status(503) self.set_header('Retry-After', '60') self.write( 'Rate limit exceeded. Please do not make more than 60 requests per minute.' ) # Don't log every single time we rate limit a host (that would get spammy fast), # but do log significant breakpoints on exactly how spammy a host is being. if remote_ip_rate in (61, 100, 1000, 10000): logging.info('Rate limited IP %s - %s requests/min' % (self.request.remote_ip, remote_ip_rate)) return self.finish() self.gplus_user_id = user_id self.gplus_page_id = page_id if len(user_id) != 21: self.write( "Google+ profile IDs are exactly 21 digits long. Please specify a proper profile ID." ) return self.finish() if page_id and len(page_id) != 21: self.write( "Google+ page IDs are exactly 21 digits long. Please specify a proper page ID." ) self.cache_key = self.cache_key_template % user_id if page_id: self.cache_key += str(page_id) cached_result = Cache.get(self.cache_key) flush_requested = self.request.arguments.get('flush', [None])[0] if cached_result: if not Config.getboolean('cache', 'allow-flush') or not flush_requested: return self._respond(**cached_result) if page_id: OAuth2Handler.authed_fetch( user_id, self.json_url % (page_id, self.request.remote_ip), self._on_api_response) else: OAuth2Handler.authed_fetch( user_id, self.json_url % ('me', self.request.remote_ip), self._on_api_response)
def wrap_callback(response): if response.code == 401: Cache.delete(cls.auth_cache_key_template % user_id) # Retry once to see if we can use a refresh token to get a new key. if _authed_fetch_retry: cls.authed_fetch(user_id, url, callback, _authed_fetch_retry=False, *args, **kwargs) else: logging.warning("Abandoning request for %s after retry.", url) else: return callback(response)
def on_profile_request_complete(self, person): """Callback for the initial OAuth flow's call to fetch_person_by_token.""" # We compute the time= param here to take into account potential time # spent during the API call. Cache.set(self.auth_cache_key_template % person['id'], self.gplus_access_token, time=int((self.gplus_expires_at - datetime.datetime.today()).total_seconds()), ) # store refresh token and gplus user id in database if self.gplus_refresh_token is not None: TokenIdMapping.update_refresh_token(person['id'], self.gplus_refresh_token) self.set_cookie('gplus_id', str(person['id'])) self.redirect('/')
def main(): """ 更新 """ parser = argparse.ArgumentParser() parser.add_argument('-c', default="config.json") get_config(path=parser.parse_args().c) if get_config('dns', 'dnspod').startswith('ali'): dns = alidns elif get_config('dns', 'dnspod').startswith('dnscom'): dns = dnscom else: dns = dnspod dns.ID, dns.TOKEN = get_config('id'), get_config('token') dns.PROXY = get_config('proxy') ip.DEBUG = get_config('debug') cache = get_config('cache', True) and Cache(CACHE_FILE) if cache is False: print("Cache is disabled!") elif len(cache) < 1 or get_config.time >= cache.time: cache.clear() print("=" * 25, time.ctime(), "=" * 25, sep=' ') update_ip('4', cache, dns) update_ip('6', cache, dns)
def main(): """ 更新 """ parser = ArgumentParser(description=__description__, epilog=__doc__, formatter_class=RawTextHelpFormatter) parser.add_argument('-v', '--version', action='version', version=__version__) parser.add_argument('-c', '--config', default="config.json", help="run with config file [配置文件路径]") get_config(path=parser.parse_args().config) # Dynamicly import the dns module as configuration dns_provider = str(get_config('dns', 'dnspod').lower()) dns = getattr(__import__('dns', fromlist=[dns_provider]), dns_provider) dns.ID, dns.TOKEN = get_config('id'), get_config('token') if get_config('debug'): ip.DEBUG = get_config('debug') basicConfig( level=DEBUG, format='%(asctime)s <%(module)s.%(funcName)s> %(lineno)d@%(pathname)s \n[%(levelname)s] %(message)s') info("DDNS[%s] run: %s,%s", __version__, os_name, sys.platform) proxy = get_config('proxy') or 'DIRECT' proxy_list = proxy.strip('; ') .split(';') cache = get_config('cache', True) and Cache(CACHE_FILE) if cache is False: warning("Cache is disabled!") elif len(cache) < 1 or get_config.time >= cache.time: cache.clear() print("=" * 25, ctime(), "=" * 25, sep=' ') update_ip('4', cache, dns, proxy_list) update_ip('6', cache, dns, proxy_list)
def main(): """ 更新 """ parser = argparse.ArgumentParser() parser.add_argument('-c', default="config.json") get_config(path=parser.parse_args().c) # Dynamicly import the dns module as configuration dns_provider = str(get_config('dns', 'dnspod').lower()) dns = getattr(__import__('dns', fromlist=[dns_provider]), dns_provider) dns.ID, dns.TOKEN = get_config('id'), get_config('token') if get_config('debug'): ip.DEBUG = get_config('debug') logging.basicConfig( level=logging.DEBUG, format= '%(asctime)s <%(module)s.%(funcName)s> %(lineno)d@%(pathname)s \n[%(levelname)s] %(message)s' ) logging.info("DDNS[%s] run: %s,%s", __version__, os.name, sys.platform) proxy = get_config('proxy') or 'DIRECT' proxy_list = proxy.strip('; ').split(';') cache = get_config('cache', True) and Cache(CACHE_FILE) if cache is False: print("Cache is disabled!") elif len(cache) < 1 or get_config.time >= cache.time: cache.clear() print("=" * 25, time.ctime(), "=" * 25, sep=' ') update_ip('4', cache, dns, proxy_list) update_ip('6', cache, dns, proxy_list)
def access_token_for_id(cls, id, callback): """Returns the access token for an id, acquiring a new one if necessary.""" token = Cache.get(cls.auth_cache_key_template % id) if token: return IOLoop.instance().add_callback(lambda: callback(token)) # If we don't have an access token cached, see if we have a refresh token token = TokenIdMapping.lookup_refresh_token(id) if token: post_body = urllib.urlencode({ 'client_id': Config.get('oauth', 'client-id'), 'client_secret': Config.get('oauth', 'client-secret'), 'refresh_token': token, 'grant_type': 'refresh_token', }) http_client = AsyncHTTPClient() return http_client.fetch( 'https://accounts.google.com/o/oauth2/token', lambda response: cls.on_refresh_complete(response, id, callback), method='POST', body=post_body, request_timeout=20.0, connect_timeout=15.0, ) else: logging.error("Unable to update access token for %s, no refresh token stored.", id) return IOLoop.instance().add_callback(lambda: callback(None))
def _on_api_response(self, response): if response is None: logging.error("API request for %s failed." % self.gplus_user_id) self.write("Unable to fetch content for this Google+ ID; it may not be authenticated. See http://%s for more information." % self.request.host) self.set_status(401) return self.finish() if response.error: if response.code == 403: logging.error("API Request 403: %r" % (json.loads(response.body))) self.set_status(503) self.write("Unable to fulfill request at this time - Google+ API rate limit exceeded.") return self.finish() else: logging.error("AsyncHTTPRequest error: %r, %r" % (response.error, response)) return self.send_error(500) else: data = json.loads(response.body) headers = {'Content-Type': 'application/atom+xml'} params = { 'userid': self.gplus_page_id or self.gplus_user_id, 'baseurl': 'http://%s' % self.request.host, 'requesturi': 'http://%s%s' % (self.request.host, self.request.uri.split('?', 1)[0]), } if 'items' not in data or not data['items']: params['lastupdate'] = dateutils.to_atom_format(datetime.datetime.today()) return self._respond(headers, empty_feed_template.format(**params)) posts = data['items'] lastupdate = max(dateutils.from_iso_format(p['updated']) for p in posts) params['author'] = xhtml_escape(posts[0]['actor']['displayName']) params['lastupdate'] = dateutils.to_atom_format(lastupdate) headers['Last-Modified'] = dateutils.to_http_format(lastupdate) params['entrycontent'] = u''.join(entry_template.format(**get_post_params(p)) for p in posts) body = feed_template.format(**params) Cache.set(self.cache_key, {'headers': headers, 'body': body}, time=Config.getint('cache', 'stream-expire')) return self._respond(headers, body)
def get(self, user_id, page_id): ratelimit_key = self.ratelimit_key_template % self.request.remote_ip remote_ip_rate = Cache.incr(ratelimit_key) if remote_ip_rate is None: Cache.set(ratelimit_key, 1, time=60) elif remote_ip_rate > 60: self.set_status(503) self.set_header('Retry-After', '60') self.write('Rate limit exceeded. Please do not make more than 60 requests per minute.') # Don't log every single time we rate limit a host (that would get spammy fast), # but do log significant breakpoints on exactly how spammy a host is being. if remote_ip_rate in (61, 100, 1000, 10000): logging.info('Rate limited IP %s - %s requests/min' % (self.request.remote_ip, remote_ip_rate)) return self.finish() self.gplus_user_id = user_id self.gplus_page_id = page_id if len(user_id) != 21: self.write("Google+ profile IDs are exactly 21 digits long. Please specify a proper profile ID.") return self.finish() if page_id and len(page_id) != 21: self.write("Google+ page IDs are exactly 21 digits long. Please specify a proper page ID.") self.cache_key = self.cache_key_template % user_id if page_id: self.cache_key += str(page_id) cached_result = Cache.get(self.cache_key) flush_requested = self.request.arguments.get('flush', [None])[0] if cached_result: if not Config.getboolean('cache', 'allow-flush') or not flush_requested: return self._respond(**cached_result) if page_id: OAuth2Handler.authed_fetch(user_id, self.json_url % (page_id, self.request.remote_ip), self._on_api_response) else: OAuth2Handler.authed_fetch(user_id, self.json_url % ('me', self.request.remote_ip), self._on_api_response)
def __init__(self, listeners, util, site_parser, voice_assistant): """ Initializer :param listeners: screen listeners :param util: utility object :param site_parser: site parser """ FilePlayerScreen.__init__(self, listeners, util, self.get_playlist, voice_assistant) self.config = util.config self.current_playlist = None self.parser = site_parser self.cache = Cache(self.util) self.current_book_state = None self.current_track_index = 0 self.playlist = self.get_playlist() self.audio_files = self.get_audio_files_from_playlist() self.loading_listeners = [] self.reset_loading_listeners = [] self.LOADING = util.config[LABELS][KEY_LOADING]
def on_refresh_complete(cls, response, id, callback): """Callback for request to get a new access token based on refresh token.""" if response.code in (400, 401): if 'invalid_grant' in response.body: # Our refresh token is invalid, which means that we don't have # permission to access this user's content anymore. Forget them. Cache.delete(cls.auth_cache_key_template % id) Cache.delete(cls.profile_cache_key_template % id) TokenIdMapping.remove_id(id) logging.error("Access was revoked for %s; cached data deleted.", id) logging.error("HTTP %s while trying to refresh access token for %s.", response.code, id) return IOLoop.instance().add_callback(lambda: callback(None)) elif response.code != 200: logging.error("Non-200 response to refresh token request (%s, id=%s): %r" % (response.code, id, response.body)) return IOLoop.instance().add_callback(lambda: callback(None)) results = json.loads(response.body) # sanity check if results['token_type'] != "Bearer": logging.error('Unknown token type received: %s' % results['token_type']) return IOLoop.instance().add_callback(lambda: callback(None)) token = results['access_token'] Cache.set(cls.auth_cache_key_template % id, token, time=results['expires_in']) IOLoop.instance().add_callback(lambda: callback(token))
def fetch_person_by_id(cls, id, callback): """Returns a dict representing a Person, given their G+ id.""" # If we have them cached already, just return that. person = Cache.get(cls.profile_cache_key_template % id) if person: return person # If we don't have the person cached, but we do have an # access token, use that to fetch the person. cls.access_token_for_id(id, lambda token: cls.fetch_person_by_token(token, callback), )
def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.config = config self.bot_config = self.config['bot'] self.session = aiohttp.ClientSession() self.logger = logger self.cache = Cache() self.database = Database(self.config['database']) self.pool = None self.debug = debug self.title = self.bot_config['title'] self.base_extensions = self.bot_config['extensions']['base'] self.debug_extensions = self.bot_config['extensions']['debug'] if self.debug: self.bot_extensions = self.base_extensions + self.debug_extensions self.token = self.bot_config['debug_token'] self.prefix = self.bot_config['debug_prefix'] else: self.bot_extensions = self.base_extensions self.token = self.bot_config['production_token'] self.prefix = self.bot_config['production_prefix']
def main(): """ 更新 """ parser = argparse.ArgumentParser() parser.add_argument('-c', default="config.json") get_config(path=parser.parse_args().c) # Dynamicly import the dns module as configuration dns_provider = str(get_config('dns', 'dnspod').lower()) dns = getattr(__import__('dns', fromlist=[dns_provider]), dns_provider) dns.ID, dns.TOKEN = get_config('id'), get_config('token') dns.DOMAIN = get_config('domain') ip.DEBUG = get_config('debug') proxy = get_config('proxy') or 'DIRECT' proxy_list = proxy.strip('; ') .split(';') print ("=" * 26, "=" * len(time.ctime()), "=" * 26, "\n", sep='') print(" " * 30, "%s" % (dns.DOMAIN.encode("utf8")).rjust( len(time.ctime())/2 - 2),"\n",sep="") print ("=" * 25, time.ctime(), "=" * 25, "\n", sep=' ') cache = get_config('cache', True) and Cache(CACHE_FILE) print("[OGetting] [Address]") # address = get_ip("4") print("[Now]".rjust(10) + " [" + get_ip("4") + "]") cache = False; if cache is False: # print("Cache is disabled!") print ("[Cache]".rjust(10),"[Disabled]",sep=" ") elif len(cache) < 1 or get_config.time >= cache.time: cache.clear() # print ("=" * 25, time.ctime(), "=" * 25, sep=' ') print ("[Cache]".rjust(10),"[Cleared]",sep=" ") update_ip('4', cache, dns, proxy_list) # update_ip('6', cache, dns, proxy_list) print('[Session]'.rjust(10)+" [End]", end=" ") print("\n") print ("_" * 25, time.ctime(), "_" * 25, sep=' ') print ("_" * 26, "_" * len(time.ctime()), "_" * 26, "\n", sep='') print("\n")
def main(): """ 更新 """ init_config(__description__, __doc__, __version__) # Dynamicly import the dns module as configuration dns_provider = str(get_config('dns', 'dnspod').lower()) dns = getattr(__import__('dns', fromlist=[dns_provider]), dns_provider) dns.Config.ID = get_config('id') dns.Config.TOKEN = get_config('token') dns.Config.TTL = get_config('ttl') if get_config('debug'): ip.DEBUG = get_config('debug') basicConfig( level=DEBUG, format= '%(asctime)s <%(module)s.%(funcName)s> %(lineno)d@%(pathname)s \n[%(levelname)s] %(message)s' ) print("DDNS[", __version__, "] run:", os_name, sys.platform) if get_config("config"): print("Configuration was loaded from <==", path.abspath(get_config("config"))) print("=" * 25, ctime(), "=" * 25, sep=' ') proxy = get_config('proxy') or 'DIRECT' proxy_list = proxy if isinstance( proxy, list) else proxy.strip('; ').replace(',', ';').split(';') cache = get_config('cache', True) and Cache(CACHE_FILE) if cache is False: info("Cache is disabled!") elif get_config("config_modified_time") is None or get_config( "config_modified_time") >= cache.time: warning("Cache file is out of dated.") cache.clear() elif not cache: debug("Cache is empty.") update_ip('4', cache, dns, proxy_list) update_ip('6', cache, dns, proxy_list)
def __init__(self): handlers = [ (r'/', IndexHandler), # 首页 # (r'/wx', WxHandler), # 微信授权页面 (r'/pay/wx', PayHandler), # 支付 # (r'/pay_test', PayWeixinTestHandler), # 微信支付测试页 (r'/api/address', address.AddressHandler), (r'/api/recom_item', recom_item.DetailHandler), (r'/api/home', home.HomeHandler), (r'/api/itemlist', home.ItemHandler), (r'/api/auth/login', auth.LoginHandler), (r'/api/order', order.OrderHandler), (r'/api/util/smscode', util.SmscodeHandler), (r'/api/util/region', util.RegionHandler), # (r'/download/yc', YcDownloadHandler), # 有菜下载 (r'/coupon', CouponHandler), # 有菜优惠券 (r'/api/coupon', coupon.CouponHandler), # 有菜获取优惠券接口 (r'/api/update_mobile', coupon.UpdateMobileHandler), # 更改红包领取手机号 (r'/coupon/info', CouponInfoHandler), # 有菜优惠券说明 ] settings = dict( debug=options.debug, xsrf_cookies=True, login_url='/login', cookie_secret='alA9P3tIUGFe3boFVM2A2tmusiRsrTGdgm8Vrk=', static_path=os.path.join(ROOT_PATH, 'static') if options.debug else os.path.join(os.path.dirname(ROOT_PATH), 'static'), template_path=os.path.join(ROOT_PATH, 'templates'), db={ 'hamlet': motor.MotorClient(MONGO_HAMLET['master']).hamlet, 'store': motor.MotorClient(MONGO_STORE['master']).store, 'youcai': motor.MotorClient(MONGO_YOUCAI['master']).youcai }, cache=Cache(CACHE_SERVER), session_manager=SessionManager(SESSION_SECRET, SESSION_SERVER, SESSION_TIMEOUT, not options.debug)) super(YoucaiWeb, self).__init__(handlers, **settings)
def main(): """ 更新 """ parser = argparse.ArgumentParser() parser.add_argument('-c', default="config.json") get_config(path=parser.parse_args().c) # Dynamicly import the dns module as configuration dns_provider = str(get_config('dns', 'dnspod').lower()) dns = getattr(__import__('dns', fromlist=[dns_provider]), dns_provider) dns.ID, dns.TOKEN = get_config('id'), get_config('token') dns.PROXY = get_config('proxy') ip.DEBUG = get_config('debug') cache = get_config('cache', True) and Cache(CACHE_FILE) if cache is False: print("Cache is disabled!") elif len(cache) < 1 or get_config.time >= cache.time: cache.clear() print ("=" * 25, time.ctime(), "=" * 25, sep=' ') update_ip('4', cache, dns) update_ip('6', cache, dns)
def on_fetch_person_complete(cls, response, callback): """Callback for the people/me API call in fetch_person_by_token.""" person = json.loads(response.body) Cache.set(cls.profile_cache_key_template % person['id'], person, time=Config.getint('cache', 'profile-expire')) return IOLoop.instance().add_callback(lambda: callback(person))
import openpyxl from const import ( HttpStatus, ) from config import ( QIANBIDAO_USER, QIANBIDAO_PASSWORD, RECEIPTS, ) from util.http import HttpClient from util.mail import mail_multipart from util.cache import Cache from util.decorators import singleton, retry cache = Cache(default_values={'qianbidao': {'last_id': '55c433b917a672bd'}}) class QianBiDaoCrawler(object): QianBiDaoAppHeaders = { 'User-Agent': 'PencilNews/1.3.0 (iPhone; iOS 11.2.5; Scale/2.00)', 'Accept-Encoding': 'br, gzip, deflate', 'Accept-Language': 'zh-Hans-CN;q=1, en-CN;q=0.9', 'Authority': 'api.pencilnews.cn', } login_url = 'https://api.pencilnews.cn/user/login' def __init__(self, username, password): self.httpclient = HttpClient(default_headers=self.QianBiDaoAppHeaders) self.username = username
class MenuScreen(Screen): """ Site Menu Screen. Base class for all book menu screens """ def __init__(self, util, listeners, rows, columns, voice_assistant, d=None, turn_page=None, page_in_title=True): """ Initializer :param util: utility object :param listeners: file browser listeners :param rows: menu rows :param d: dictionary with menu button flags :param turn_page: turn page callback :param util: utility object """ self.util = util self.config = util.config self.factory = Factory(util) self.bounding_box = self.config[SCREEN_RECT] self.player = None self.turn_page = turn_page self.page_in_title = page_in_title self.cache = Cache(self.util) self.layout = BorderLayout(self.bounding_box) self.layout.set_percent_constraints(PERCENT_TOP_HEIGHT, PERCENT_BOTTOM_HEIGHT, 0, 0) Screen.__init__(self, util, "", PERCENT_TOP_HEIGHT, voice_assistant, "menu_screen_screen_title", True, self.layout.TOP) color_dark_light = self.config[COLORS][COLOR_DARK_LIGHT] self.menu_layout = self.layout.CENTER self.menu_button_layout = self.get_menu_button_layout(d) self.img_rect = self.menu_button_layout.image_rectangle listeners[GO_LEFT_PAGE] = self.previous_page listeners[GO_RIGHT_PAGE] = self.next_page try: self.navigator = BookNavigator(util, self.layout.BOTTOM, listeners, color_dark_light, d[4]) Container.add_component(self, None) Container.add_component(self, self.navigator) except: Container.add_component(self, None) self.total_pages = 0 self.current_page = 1 self.menu = None self.loading_listeners = [] self.LOADING = util.config[LABELS][KEY_LOADING] def get_menu_button_layout(self, d): """ Return menu button layout :param d: dictionary with menu button flags :return: menu button layout """ s = State() s.show_img = True s.show_label = True button_w = int(self.menu_layout.w / d[1]) button_h = int(self.menu_layout.h / d[0]) label_padding = 2 image_padding = 4 try: self.show_author = d[2] except: self.show_author = False try: self.show_genre = d[3] except: self.show_genre = False s.bounding_box = Rect(0, 0, button_w, button_h) return MultiLineButtonLayout(s, label_padding, image_padding) def previous_page(self, state): """ Handle click on left button :param state: button state object """ if self.current_page == 1: return self.current_page -= 1 if getattr(state, "select_last", False): self.components[1].selected_index = 0 self.menu.current_page = self.current_page self.menu.selected_index = 0 self.turn_page() def next_page(self, state): """ Handle click on right button :param state: button state object """ if self.total_pages <= 1 or self.total_pages == self.current_page: return self.current_page += 1 if self.current_page > self.total_pages: self.current_page = self.total_pages self.menu.current_page = self.current_page self.menu.selected_index = 0 self.turn_page() def set_menu(self, menu): """ Set menu :param menu: menu object """ self.menu = self.components[1] = menu def set_title(self, page_num): """ Set screen title :param page_num: menu page number """ if self.total_pages == 1 or not self.page_in_title: self.screen_title.set_text(self.title) return if len(str(page_num)) <= len(str(self.total_pages)): self.screen_title.set_text(self.title + " (" + str(page_num) + ")") def reset_title(self): """ Reset screen title """ self.screen_title.set_text(self.title + " (" + str(self.current_page) + ")") def go_to_page(self, page_num): """ Handle go to page event :param page_num: menu page number """ n = int(page_num) if n > self.total_pages: n = self.total_pages if n == 0: n = 1 self.current_page = n self.menu.current_page = self.current_page self.turn_page() def get_image_from_cache(self, url): """ Return image from cache :param url: image url :return: image """ return self.cache.get_image(url) def put_image_to_cache(self, url, img): """ Put image into cache :param url: image url :param img: image """ self.cache.cache_image(img, url) def set_button_image(self, b, icon, img_y=None): """ Set button image :param b: button :param icon: image :param img_y: image Y coordinate """ bb = b.bounding_box comps = b.components im = comps[1] im.content = icon w = im.content.get_size()[0] h = im.content.get_size()[1] im.content_x = bb.x + (bb.width - w) / 2 if img_y == None: img_area_height = bb.height - ((bb.height / LINES) * 2) img_y = bb.y + (img_area_height - h) / 2 im.content_y = img_y self.components[1].clean_draw_update() def set_loading(self, name): """ Show Loading... sign :name: screen title """ b = self.config[COLORS][COLOR_DARK] f = self.config[COLORS][COLOR_BRIGHT] fs = int(self.bounding_box.h * 0.07) bb = self.menu_layout t = self.factory.create_output_text(self.LOADING, bb, b, f, fs) t.set_text(self.LOADING) self.screen_title.set_text(name) self.set_visible(True) self.add_component(t) self.clean_draw_update() self.notify_loading_listeners() def reset_loading(self): """ Remove Loading... sign """ del self.components[-1] self.notify_loading_listeners() def add_loading_listener(self, listener): """ Add loading listener :param listener: event listener """ if listener not in self.loading_listeners: self.loading_listeners.append(listener) def notify_loading_listeners(self): """ Notify all loading listeners """ for listener in self.loading_listeners: listener(None)
def _on_api_response(self, response): if response is None: logging.error("API request for %s failed." % self.gplus_user_id) self.write( "Unable to fetch content for this Google+ ID; it may not be authenticated. See http://%s for more information." % self.request.host) self.set_status(401) return self.finish() if response.error: if response.code == 403: logging.error("API Request 403: %r" % (json.loads(response.body))) self.set_status(503) self.write( "Unable to fulfill request at this time - Google+ API rate limit exceeded." ) return self.finish() else: logging.error("AsyncHTTPRequest error: %r, %r" % (response.error, response)) return self.send_error(500) else: data = json.loads(response.body) headers = {'Content-Type': 'application/atom+xml'} params = { 'userid': self.gplus_page_id or self.gplus_user_id, 'baseurl': 'http://%s' % self.request.host, 'requesturi': 'http://%s%s' % (self.request.host, self.request.uri.split('?', 1)[0]), } if 'items' not in data or not data['items']: params['lastupdate'] = dateutils.to_atom_format( datetime.datetime.today()) return self._respond(headers, empty_feed_template.format(**params)) posts = data['items'] lastupdate = max( dateutils.from_iso_format(p['updated']) for p in posts) params['author'] = xhtml_escape(posts[0]['actor']['displayName']) params['lastupdate'] = dateutils.to_atom_format(lastupdate) headers['Last-Modified'] = dateutils.to_http_format(lastupdate) params['entrycontent'] = u''.join( entry_template.format(**get_post_params(p)) for p in posts) body = feed_template.format(**params) Cache.set(self.cache_key, { 'headers': headers, 'body': body }, time=Config.getint('cache', 'stream-expire')) return self._respond(headers, body)
class MenuScreen(Screen): """ Site Menu Screen. Base class for all book menu screens """ def __init__(self, util, listeners, rows, columns, voice_assistant, d=None, turn_page=None, page_in_title=True, show_loading=False): """ Initializer :param util: utility object :param listeners: file browser listeners :param rows: menu rows :param d: dictionary with menu button flags :param turn_page: turn page callback :param util: utility object """ self.util = util self.config = util.config self.factory = Factory(util) self.bounding_box = util.screen_rect self.player = None self.turn_page = turn_page self.page_in_title = page_in_title self.show_loading = show_loading self.cache = Cache(self.util) self.layout = BorderLayout(self.bounding_box) self.layout.set_percent_constraints(PERCENT_TOP_HEIGHT, PERCENT_BOTTOM_HEIGHT, 0, 0) Screen.__init__(self, util, "", PERCENT_TOP_HEIGHT, voice_assistant, "menu_screen_screen_title", True, self.layout.TOP) self.menu_layout = self.layout.CENTER if d: self.menu_button_layout = self.get_menu_button_layout(d) self.img_rect = self.menu_button_layout.image_rectangle listeners[GO_LEFT_PAGE] = self.previous_page listeners[GO_RIGHT_PAGE] = self.next_page self.total_pages = 0 self.current_page = 1 self.menu = None def get_menu_button_layout(self, d): """ Return menu button layout :param d: dictionary with menu button flags :return: menu button layout """ s = State() s.show_img = True s.show_label = True button_w = int(self.menu_layout.w / d[1]) button_h = int(self.menu_layout.h / d[0]) label_padding = 2 image_padding = 4 try: self.show_author = d[2] except: self.show_author = False try: self.show_genre = d[3] except: self.show_genre = False s.bounding_box = Rect(0, 0, button_w, button_h) return MultiLineButtonLayout(s, label_padding, image_padding) def previous_page(self, state): """ Handle click on left button :param state: button state object """ if self.current_page == 1: return self.current_page -= 1 if getattr(state, "select_last", False): self.components[1].selected_index = 0 self.menu.current_page = self.current_page self.menu.selected_index = 0 if self.show_loading: self.set_loading(self.screen_title.text) self.turn_page() if self.show_loading: self.reset_loading() def next_page(self, state): """ Handle click on right button :param state: button state object """ if self.total_pages <= 1 or self.total_pages == self.current_page: return self.current_page += 1 if self.current_page > self.total_pages: self.current_page = self.total_pages self.menu.current_page = self.current_page self.menu.selected_index = 0 if self.show_loading: self.set_loading(self.screen_title.text) self.turn_page() if self.show_loading: self.reset_loading() def set_menu(self, menu): """ Set menu :param menu: menu object """ self.menu = menu self.add_component(self.menu) def set_title(self, page_num): """ Set screen title :param page_num: menu page number """ if self.total_pages == 1 or not self.page_in_title: self.screen_title.set_text(self.title) return if len(str(page_num)) <= len(str(self.total_pages)): self.screen_title.set_text(self.title + " (" + str(page_num) + ")") def reset_title(self): """ Reset screen title """ self.screen_title.set_text(self.title + " (" + str(self.current_page) + ")") def go_to_page(self, page_num): """ Handle go to page event :param page_num: menu page number """ n = int(page_num) if n > self.total_pages: n = self.total_pages if n == 0: n = 1 self.current_page = n self.menu.current_page = self.current_page self.turn_page() def get_image_from_cache(self, url): """ Return image from cache :param url: image url :return: image """ return self.cache.get_image(url) def put_image_to_cache(self, url, img): """ Put image into cache :param url: image url :param img: image """ self.cache.cache_image(img, url) def set_button_image(self, b, icon, img_y=None): """ Set button image :param b: button :param icon: image :param img_y: image Y coordinate """ bb = b.bounding_box comps = b.components im = comps[1] im.content = icon w = im.content.get_size()[0] h = im.content.get_size()[1] im.content_x = bb.x + (bb.width - w) / 2 if img_y == None: img_area_height = bb.height - ((bb.height / LINES) * 2) img_y = bb.y + (img_area_height - h) / 2 im.content_y = img_y self.components[1].clean_draw_update() def set_loading(self, name, text=None): """ Show Loading... sign :param name: screen title :param text: screen text """ Screen.set_loading(self, name, self.menu_layout, text)
class BookPlayer(FilePlayerScreen): """ Book Player Screen """ def __init__(self, listeners, util, site_parser, voice_assistant): """ Initializer :param listeners: screen listeners :param util: utility object :param site_parser: site parser """ FilePlayerScreen.__init__(self, listeners, util, self.get_playlist, voice_assistant) self.config = util.config self.image_util = util.image_util self.current_playlist = None self.parser = site_parser self.cache = Cache(self.util) self.current_book_state = None self.current_track_index = 0 self.playlist = self.get_playlist() self.audio_files = self.get_audio_files_from_playlist() self.loading_listeners = [] self.reset_loading_listeners = [] self.LOADING = util.config[LABELS][KEY_LOADING] def get_playlist(self): """ Return current playlist :return: playlist """ return self.current_playlist def set_book(self, new_track, state=None): """ Set book :param new_track: flag defining if track is new :param state: button state object """ self.set_loading() self.current_book_state = state img_url = None if hasattr(state, "event_origin"): img_url = state.event_origin.state.icon_base[0] elif hasattr(state, "img_url"): img_url = state.img_url self.current_playlist = self.parser.get_book_audio_files_by_url( state.book_url, img_url) state.url = self.parser.book_parser.img_url img = self.cache.get_image(state.url) if img == None: i = self.image_util.load_image_from_url(state.url) if i: self.cache.cache_image(i[1], state.url) img = i[1] bb = self.file_button.bounding_box w = bb.w h = bb.h self.cover_image = self.image_util.scale_image_with_padding(w, h, img, padding=1) self.screen_title.set_text(state.name) if self.current_playlist == None: return self.playlist = self.current_playlist if new_track and self.playlist: self.config[AUDIOBOOKS][BROWSER_BOOK_TITLE] = state.name self.config[AUDIOBOOKS][BROWSER_BOOK_URL] = state.book_url self.config[AUDIOBOOKS][BROWSER_IMAGE_URL] = img_url self.config[AUDIOBOOKS][BROWSER_TRACK_FILENAME] = self.playlist[0][ "title"] state.track_time = self.config[AUDIOBOOKS][BROWSER_BOOK_TIME] = "0" elif not new_track: state.track_time = self.config[AUDIOBOOKS][BROWSER_BOOK_TIME] self.audio_files = self.playlist def set_current(self, new_track=False, state=None): """ Set current file :param new_track: True - new audio file :param state: button state object """ if state.source == BOOK_MENU or state.source == INIT: if self.current_book_state and self.current_book_state.book_url == state.book_url and self.time_control.timer_started: return self.current_track_index = 0 if state.source == INIT: new_track = False else: new_track = True self.set_book(new_track, state) elif state.source == TRACK_MENU: if getattr(state, "index", None) and state.index == self.current_track_index: return new_track = True st = {"file_name": state.file_name} self.set_current_track_index(st) elif state.source == ARROW_BUTTON: new_track = True st = {"file_name": state.file_name} self.set_current_track_index(st) elif state.source == RESUME: new_track = False st = {"file_name": state.file_name} self.set_current_track_index(st) elif state.source == HOME_NAVIGATOR or state.source == BOOK_NAVIGATOR_BACK or state.source == BOOK_NAVIGATOR or state.source == GO_PLAYER: return if getattr(state, "url", None): self.file_button.components[ 1].image_filename = self.img_filename = state.url else: if hasattr(self, "img_filename"): self.file_button.components[ 1].image_filename = self.img_filename else: self.file_button.components[ 1].image_filename = self.img_filename = None img = self.cover_image if img: self.file_button.components[1].content = img self.file_button.state.icon_base = img self.file_button.state.show_bgr = True self.file_button.state.bgr = self.config[COLORS][COLOR_MEDIUM] self.file_button.add_background(self.file_button.state) self.file_button.components[ 1].content_x = self.layout.CENTER.x + int( (self.layout.CENTER.w - img.get_size()[0]) / 2) if self.layout.CENTER.h > img.get_size()[1]: self.file_button.components[ 1].content_y = self.layout.CENTER.y + int( (self.layout.CENTER.h - img.get_size()[1]) / 2) else: self.file_button.components[1].content_y = self.layout.CENTER.y if self.current_playlist == None: return self.set_audio_file(new_track, state) def set_audio_file(self, new_track, s=None): """ Set new audio file :param new_track: True - new audio file :param s: button state object """ state = State() state.playback_mode = FILE_AUDIO state.playlist_track_number = 0 name = url = None if s == None: if self.config[AUDIOBOOKS][BROWSER_TRACK_FILENAME]: name = self.config[AUDIOBOOKS][BROWSER_TRACK_FILENAME] for t in self.playlist: if t["title"].endswith(name): url = t["mp3"] else: i = 0 if s != None: i = s.index t = self.playlist[i] url = t["mp3"] name = t["title"] else: if getattr(s, "track_filename", None): i = self.get_current_track_index( {"file_name": s.track_filename}) elif getattr(s, "playlist_track_number", None): i = s.playlist_track_number else: i = self.current_track_index t = self.playlist[i] url = t["mp3"] name = t["title"] self.config[PLAYER_SETTINGS][PAUSE] = False state.file_name = name self.config[AUDIOBOOKS][BROWSER_TRACK_FILENAME] = t["file_name"] state.mute = self.config[PLAYER_SETTINGS][MUTE] state.pause = self.config[PLAYER_SETTINGS][PAUSE] self.play_button.draw_default_state(None) if self.config[VOLUME_CONTROL][ VOLUME_CONTROL_TYPE] == VOLUME_CONTROL_TYPE_PLAYER: state.volume = self.config[PLAYER_SETTINGS][VOLUME] else: state.volume = None state.file_type = FILE_AUDIO state.dont_notify = True state.source = FILE_AUDIO state.url = url state.mode = AUDIOBOOKS state.playback_mode = FILE_AUDIO state.music_folder = self.config[AUDIO][MUSIC_FOLDER] self.audio_files = self.get_audio_files_from_playlist() if self.config[AUDIOBOOKS][BROWSER_BOOK_TIME]: if new_track: state.track_time = "0" else: state.track_time = self.config[AUDIOBOOKS][BROWSER_BOOK_TIME] self.reset_loading() logging.debug(state.url) self.notify_play_listeners(state) def get_audio_files(self): """ Return audio files from playlist :return: files """ return self.get_audio_files_from_playlist() def get_audio_files_from_playlist(self): """ Call player for files in the playlist :return: list of files from playlist """ files = [] if getattr(self, "playlist", None): for n in range(len(self.playlist)): st = State() st.index = st.comparator_item = n t = self.playlist[n] st.file_type = FILE_AUDIO st.file_name = t["file_name"] files.append(st) return files def set_loading(self): """ Show Loading... sign """ b = self.config[COLORS][COLOR_DARK] f = self.config[COLORS][COLOR_BRIGHT] fs = 20 bx = self.file_button.bounding_box x = bx.x - 1 y = bx.y w = bx.w + 2 h = bx.h bb = pygame.Rect(x, y, w, h) t = self.factory.create_output_text(self.LOADING, bb, b, f, fs) t.set_text(self.LOADING) t.layer_name = self.LOADING self.left_button.change_label("") self.right_button.change_label("") self.add_component(t) self.clean_draw_update() self.notify_loading_listeners() def reset_loading(self): """ Remove Loading... sign """ n = getattr(self.components[-1], "layer_name", None) if n and n == self.LOADING: del self.components[-1] pygame.event.clear() self.notify_reset_loading_listeners() def add_loading_listener(self, listener): """ Add loading listener :param listener: event listener """ if listener not in self.loading_listeners: self.loading_listeners.append(listener) def notify_loading_listeners(self): """ Notify all loading listeners """ for listener in self.loading_listeners: listener(None) def add_reset_loading_listener(self, listener): """ Add reset loading listener :param listener: event listener """ if listener not in self.reset_loading_listeners: self.reset_loading_listeners.append(listener) def notify_reset_loading_listeners(self): """ Notify all reset loading listeners """ for listener in self.reset_loading_listeners: listener(None) def add_screen_observers(self, update_observer, redraw_observer, start_time_control, stop_time_control, title_to_json): """ Add screen observers :param update_observer: observer for updating the screen :param redraw_observer: observer to redraw the whole screen :param start_time_control: :param stop_time_control: :param title_to_json: """ FilePlayerScreen.add_screen_observers(self, update_observer, redraw_observer, start_time_control, stop_time_control, title_to_json) self.add_loading_listener(redraw_observer) self.add_reset_loading_listener(redraw_observer)
class FFF(commands.AutoShardedBot): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.config = config self.bot_config = self.config['bot'] self.session = aiohttp.ClientSession() self.logger = logger self.cache = Cache() self.database = Database(self.config['database']) self.pool = None self.debug = debug self.title = self.bot_config['title'] self.base_extensions = self.bot_config['extensions']['base'] self.debug_extensions = self.bot_config['extensions']['debug'] if self.debug: self.bot_extensions = self.base_extensions + self.debug_extensions self.token = self.bot_config['debug_token'] self.prefix = self.bot_config['debug_prefix'] else: self.bot_extensions = self.base_extensions self.token = self.bot_config['production_token'] self.prefix = self.bot_config['production_prefix'] async def on_ready(self): # self.remove_command("help") self.pool = await self.database.connect() await self.update_cache() await self.load_extensions() await self.update_activity() self.logger.info(f"Logged in as {self.user} ({self.user.id}).") if self.debug: self.logger.critical( "Starting in debug mode, do not use this in production!") async def close(self): self.logger.info("\nShutting down!") await super(FFF, self).close() await self.session.close() await self.pool.close() async def on_message_edit(self, before, after): if after.author.bot: return await self.process_commands(after) async def on_command_error(self, ctx, error): if isinstance(error, commands.CommandNotFound): pass elif isinstance(error, commands.CheckFailure): pass elif isinstance(error, commands.MissingRequiredArgument): await ctx.send("Invalid command arguments!") else: try: raise error except Exception as error: cause = str(error.__cause__) owner = self.get_user(self.owner_ids[0]) length = 1024 - (len(cause) + 3) embed = Embed(title="An error has occurred!", color=ctx.author.color) embed.add_field(name=cause, value=str(traceback.format_exc()[:length]) + "...", inline=False) embed.add_field(name="Command name", value=ctx.command.qualified_name, inline=False) embed.add_field(name="Executed by", value=f"`{ctx.author}` ({ctx.author.id})", inline=False) embed.add_field( name="Executed in", value=f"`{ctx.guild.name}` ({ctx.guild.id})\n" f"<#{ctx.channel.id}> (`{ctx.channel.name}`, {ctx.channel.id})", inline=False) await owner.send(embed=embed) embed = Embed(title="An error has occurred!", color=ctx.author.color) embed.add_field( name=cause, value="The owner has been notified about this error.") await ctx.send(embed=embed) self.logger.error(traceback.format_exc()) async def load_extensions(self): for extension in self.bot_extensions: self.load_extension(f"extensions.{extension}") self.logger.info(f"Loaded {extension}.") self.logger.info("Starting...") async def update_activity(self): activity = discord.Activity( name=self.config['bot']['activity']['name'], type=getattr(discord.ActivityType, self.config['bot']['activity']['type'])) await self.change_presence(activity=activity) async def update_cache(self): self.logger.debug("Updating cache...") async with self.pool.acquire() as conn: guild_data = await self.database.get_guild_data(conn) guild_data_history = await self.database.get_guild_data_history( conn) self.cache.set({ "guild_data": guild_data, "guild_data_history": guild_data_history }) self.logger.debug("Successfully updated the cache!")