def mserver(): host = '127.0.0.1' # Bind to all interfaces port = 51500 # Step1: 创建socket对象 s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) # Step2: 设置socket选项(可选) s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) # Step3: 绑定到某一个端口 s.bind((host, port)) # Step4: 监听该端口上的连接 while 1: try: message, address = s.recvfrom(8192) hues.info("Got data from ", address) hues.success("Data is:",message) s.sendto("Data is received succeefully", address) # 告知客户端,信息已收到 except (KeyboardInterrupt, SystemExit): hues.warn("raise") raise except: hues.warn("traceback") traceback.print_exc()
async def upload_photo(self, encoded_image) -> Attachment: data = aiohttp.FormData() data.add_field('photo', encoded_image, filename='picture.png', content_type='multipart/form-data') upload_url = ( await self.method('photos.getMessagesUploadServer'))['upload_url'] async with aiohttp.ClientSession() as sess: async with sess.post(upload_url, data=data) as resp: result = json.loads(await resp.text()) hues.warn(result) if not result: return None data = dict(photo=result['photo'], hash=result['hash'], server=result['server']) result = (await self.method('photos.saveMessagesPhoto', data))[0] link = "" for k in result: if "photo_" in k: link = result[k] return Attachment("photo", result["owner_id"], result["id"], "", link)
def max_long_same(self,inlist): if not inlist or len(inlist)==1: return inlist lstr=[] startpos,endpos=0,0 for k,v in enumerate(inlist[:-1]): if inlist[k+1]==v: endpos+=1 else: lstr.append((v,(startpos,endpos))) startpos,endpos=k+1,k+1 if inlist[-1]==inlist[-2]: lstr.append((inlist[-1],(startpos,endpos))) if inlist[-1]!=inlist[-2]: lstr.append((inlist[-1],(len(inlist)-1,len(inlist)-1))) lres=[] for v,se in lstr: llen=se[1]-se[0]+1 if llen>2: hues.warn(v,se) lres.append((v,llen)) else: hues.warn(v,se) return lres
def checkout(): try: from Config import Config if len(Config.admins) < 1: hues.error('There\'re no admins in Config.py. Specify them.') exit() if len(Config.groups) < 1: hues.error('There\'re no groups in Config.py from which posts will be steal. Specify them.') exit() if Config.vk_user_token == "": hues.error('There\'re no user token in Config.py. Specify it.') exit() if Config.vk_community_token == "": hues.error('There\'re no community token in Config.py. Specify it.') exit() if Config.vk_community_id == "": hues.error('There\'re no community ID in Config.py. Specify it.') exit() if os.path.exists('./source/waterx.png') is False: hues.error('There\'re no waterx.png in "source" folder. Add it.') exit() except ImportError: hues.error('Can\'t find the Config.py. Where?') exit() except Exception as e: hues.warn(str(e)) hues.error('Error while DataCheck.') exit()
def __init__(self, name: str = "Example", usage: str = ''): self.deferred_events = [] # события, на которые подписан плагин self.scheduled_funcs = [] self.name = name self.usage = usage self.first_command = '' hues.warn(self.name)
async def user(self, username, password, app_id, scope): self.username = username self.password = password self.app_id = app_id self.scope = scope self.token = await get_token(username, password, app_id, scope) hues.warn(f"User's token: {self.token}")
def vk_init(self): hues.warn("Авторизация в ВКонтакте...") # Словарь вида ID -> время self.messages_date = {} self.vk = VkPlus(token=self.TOKEN, login=self.VK_LOGIN, password=self.VK_PASSWORD, scope=self.SCOPE, app_id=self.APP_ID) hues.success("Успешная авторизация")
def run(self): ax = self.make_plot() try: plt.savefig(self.output().fn, bbox_inches='tight') except IOError: import hues import uuid fn = "plot.{}.{}".format(str(uuid.uuid4()), self.file_type) hues.warn("filename became to long, saved to `{}`".format(fn)) plt.savefig(fn, bbox_inches='tight')
def vk_init(self): hues.warn("Авторизация в ВКонтакте...") # Словарь вида ID -> время self.messages_date = {} self.vk = VkPlus(users_data=self.USERS, proxies=self.PROXIES, bot=self, scope=self.SCOPE, app_id=self.APP_ID) if self.vk: hues.success("Успешная авторизация")
def __init__(self, name: str = "Example", usage: list = None): self.deferred_events = [] # события, на которые подписан плагин self.scheduled_funcs = [] self.name = name if usage is None: usage = [] if isinstance(usage, str): usage = [usage] self.usage = usage self.first_command = '' hues.warn(self.name)
def tcplink(sock,addr): hues.info("accept new connection from %s:%s..." % addr) sock.send("Welcom!".encode()) while True: #通信循环:发送与接收 data=sock.recv(1024) hues.success("Received [%s] from %s:%s" %(data,addr[0],addr[1])) time.sleep(5) if data=='exit' or not data: break sock.send("hello: ".encode()+data) sock.close() hues.warn("Connection from %s:%s closed." % addr)
def is_available_from_public(key: str) -> bool: """Проверяет, доступен ли метод через паблик апи""" try: topic, method = key.split('.') except ValueError: # Не должно случаться, но мало ли hues.warn('Метод VK API должен состоять из раздела и метода,' ' разделённых точкой') return False methods = ALLOWED_PUBLIC.get(topic, ()) if method in methods: return True
def get_requests(hostname, lines, conn, Proxy): """ build a requests object for a hostname :param hostname: :param lines: content of the file containing user-agents strings :param conn: connection to the database :param Proxy: connection through proxy :return: the answer to the request content or None """ # if the certificate is a wildcard, display it but no testing. # and return. if '*' in hostname: hues.warn('wildcard certificate: no request for ' + hostname) return None url = 'https://' + hostname headers = get_random_UserAgent_header(lines) # set proxy if Proxy: proxy = {"https": Proxy} else: proxy = "" try: r = requests.get(url, headers=headers, proxies=proxy, timeout=5) return r except requests.exceptions.SSLError as errs: # SSL error hues.error(" {} - SSL error".format(url)) return None except requests.exceptions.ConnectionError as errc: # other connection error hues.error(" {} - Connection error".format(url)) return None except requests.exceptions.RequestException as e: # A serious problem happened hues.error(" {} Error: {}".format(url, e)) return None except KeyboardInterrupt: print("get_requests() - Interrupt received, stopping ...") print("start - committing, closing DB") conn.commit conn.close print("ending - committing, closing DB") sys.exit(0) except Exception as ex: hues.error("get_requests() - any other kind of error: {}".format(ex)) return None
def __init__(self, name: str = "Example", usage: list = None): self.name = name self.first_command = '' self.process_pool = None self.deferred_events = [] self.scheduled_funcs = [] self.init_funcs = [] self.init_usage(usage) self.init_data() hues.warn(self.name)
def handle(self, *args, **options): indices = registered_indices() if len(indices): hues.info('Discovered', len(indices), 'Indexes') else: hues.warn('No search indexes found') for i, index in enumerate(indices, 1): hues.info('==> Indexing objects from', index.model, 'in', index) for obj in tqdm(index.queryset): doc = index.init_using_pk(obj.pk) doc.prepare() doc.save() hues.success('--> {0}/{1} indexed.'.format(i, len(indices)))
def save_data(self): hues.warn("Сохраняю данные плагинов...") if not os.path.exists("plugins/temp"): os.makedirs("plugins/temp") for plugin in self.plugin_system.get_plugins(): if plugin.data and any(plugin.data.values()): with open( f'plugins/temp/{plugin.name.lower().replace(" ", "_")}.data', 'wb') as f: pickle.dump(plugin.data, f) hues.warn("Выключение бота...")
def compareCSV(): global ids_new global urls_new global ids_temp global urls_temp global ids_real global urls_real # Compare _temp and _real ids_new = [x for x in ids_temp if x not in ids_real] urls_new = [x for x in urls_temp if x not in urls_real] if ids_new: hues.info('NEW ID COUNT: ' + str(len(ids_new))) elif not ids_new: hues.warn('NO NEW ID')
async def run(self, event_loop): """Главная функция бота - тут происходит ожидание новых событий (сообщений)""" self.event_loop = event_loop # Нужен для шедулинга функций # for func in self.scheduled_funcs: # self.schedule_coroutine(func) await self.init_long_polling() session = aiohttp.ClientSession(loop=event_loop) while True: try: resp = await session.get(self.longpoll_server, params=self.longpoll_values) except aiohttp.errors.ClientOSError: # У меня были такие ошибки на Manjaro 16.10.3 Fringilla # ВК почему-то присылал сервер, к которому нельзя подключиться hues.warn( 'Сервер Long Polling не отвечает, подключаюсь к другому...' ) await self.init_long_polling() continue """ Тут не используется resp.json() по простой причине: aiohttp будет писать warning'и из-за плохого mimetype Неизвестно, почему он у ВК такой - text/javascript; charset=utf-8 """ events_text = await resp.text() try: events = json.loads(events_text) except ValueError: # В JSON ошибка, или это вовсе не JSON continue # Проверяем на код ошибки failed = events.get('failed') if failed: err_num = int(failed) # Код 1 - Нам нужно обновить timestamp if err_num == 1: self.longpoll_values['ts'] = events['ts'] # Коды 2 и 3 - нужно запросить данные нового # Long Polling сервера elif err_num == 2: await self.init_long_polling() elif err_num == 3: await self.init_long_polling() continue # Обновляем время, чтобы не приходили старые события self.longpoll_values['ts'] = events['ts'] for event in events['updates']: await self.check_event(event)
def __init__(self, name: str = "Example", usage: list = None, need_db: bool = False): if need_db and not DATABASE_SETTINGS: return self.name = name self.first_command = '' self.process_pool = None self.deferred_events = [] self.scheduled_funcs = [] self.init_funcs = [] self.init_usage(usage) self.temp_data = {} hues.warn(self.name)
async def method(self, key: str, data=None): """Выполняет метод API VK с дополнительными параметрами""" if data is None: data = {} # Если мы работаем от имени группы if self.token: # Если метод доступен от имени группы - используем API группы if is_available_from_group(key): api_method = self.group_api # Если метод доступен от паблик апи - используем его elif is_available_from_public(key): api_method = self.public_api elif self.user_api: api_method = self.user_api else: hues.warn(f'Метод {key} нельзя вызвать от имени сообщества!') return {} else: api_method = self.user_api try: return await api_method(key, **data) except (asyncio.TimeoutError, json.decoder.JSONDecodeError): # Пытаемся отправить запрос к API ещё раз return await api_method(key, **data) except aiovk.exceptions.VkAuthError: message = 'TOKEN' if self.token else 'LOGIN и PASSWORD' fatal("Произошла ошибка при авторизации API, " f"проверьте значение {message} в settings.py!") except aiovk.exceptions.VkAPIError as ex: # Код 9 - Flood error - слишком много одинаковых сообщений if not ex.error_code == 9: hues.error("Произошла ошибка при вызове метода API " f"{key} с значениями {data}:\n{ex}") return {} if 'message' not in data: return {} data['message'] += f'\n Анти-флуд (API): {self.anti_flood()}' try: # Пытаемся отправить сообщение ещё раз await self.method('messages.send', data) except aiovk.exceptions.VkAPIError: # Не знаю, может ли это случиться, или нет hues.error('Обход анти-флуда API не удался =(') return {}
def handle(self, delete, *args, **options): indices = registered_indices() connection = connections.get_connection() hues.info('Using connection', connection) if len(indices): hues.info('Discovered', len(indices), 'Indexes') else: hues.warn('No search index found') for i, index in enumerate(indices, 1): hues.info('==> Initializing', index.__name__) with index().ensure_closed_and_reopened() as ix: if delete: hues.warn('Deleting existing index.') ix.delete_index() ix.init() hues.success('--> Done {0}/{1}'.format(i, len(indices)))
def is_available_from_group(key: str) -> bool: """Проверяет, можно ли выполнить данный метод VK API от имени группы""" # execute можно выполнять от имени группы if key == 'execute': return True try: topic, method = key.split('.') except ValueError: # Не должно случаться, но мало ли hues.warn('Метод VK API должен состоять из раздела и метода,' ' разделённых точкой') return False # Если раздел - messages, проверяем, нельзя ли выполнить этот метод if topic == 'messages': return method not in DISALLOWED_MESSAGES # Получаем список разрешённых методов для данного раздела methods_allowed = ALLOWED_METHODS.get(topic, ()) if method in methods_allowed: return True
def plugin_init(self): hues.warn("Загрузка плагинов...") # Подгружаем плагины self.plugin_system = PluginSystem(folder=abspath('plugins')) self.plugin_system.register_commands() # Чтобы плагины могли получить список всех плагинов (костыль) self.vk.get_plugins = self.plugin_system.get_plugins # Для парсинга команд с пробелом используется # обратная сортировка, для того, чтобы самые # длинные команды были первыми в списке command_names = list(self.plugin_system.commands.keys()) command_names.sort(key=len, reverse=True) from command import CommandSystem self.cmd_system = CommandSystem(command_names, self.plugin_system, self.NEED_CONVERT) self.scheduled_funcs = self.plugin_system.scheduled_events hues.success("Загрузка плагинов завершена")
async def enter_captcha(url): if not solver: return hues.warn( 'Введите данные для сервиса решения капч в settings.py!') session = aiohttp.ClientSession() with session as ses: async with ses.get(url) as resp: img_data = await resp.read() data = solver.solve_captcha(img_data) return data
def time_controller(self): catched = False if not Config.workout_time: return True while True: if int(StaticMethods.get_time().strftime('%H')) not in range( Config.workout_time[0], Config.workout_time[1] + 1): if not catched: catched = True self.botapi.write_msg( 'Подготовка ко сну. Следующие посты будут доступны с {}' .format(Config.workout_time[0]), JSONWorker.read_json('nonekey.json')) hues.warn('Going to sleep up to {}'.format( Config.workout_time[0])) time.sleep(3600 - int(StaticMethods.get_time().strftime('%M')) * 60) else: break return True
def bye(): try: BA = BotApi(Config.vk_community_token) BA.write_msg('Скрипт был аварийно остановлен.', None) except: pass hues.warn('Shutting down...') try: os.remove('source/tmp/img.jpg') except: pass try: os.remove('./source/tmp/result.png') except: pass try: os.removedirs('./source/tmp/') except: pass
def image_upload(self): try: upload_server = self.vk.method( 'photos.getWallUploadServer', {'group_id': int(Config.vk_community_id)}) temp_photo = requests.post(upload_server['upload_url'], files={ 'photo': open('source/tmp/result.jpg', 'rb') }).json() save_method = \ self.vk.method('photos.saveWallPhoto', {'group_id': int(Config.vk_community_id), 'photo': temp_photo['photo'], 'server': temp_photo['server'], 'hash': temp_photo['hash']})[0] return 'photo{}_{}_{}'.format(save_method['owner_id'], save_method['id'], save_method['access_key']) except exceptions.ApiError as e: print(str(e)) hues.warn('Error while image downloading. Retrying...') return False
async def execute(self, code, **additional_values): if self.retry > 5: hues.warn("Не могу войти в ВК!") return False new = code.replace("\n", "<br>") url = f"https://api.vk.com/method/execute?access_token={self.token}&v=5.64" async with self.session.post(url, data={ "code": new, **additional_values }, **self.req_kwargs) as resp: errors = [] error_codes = [] for data in json_iter_parse(await resp.text()): if 'error' in data: error_data = data['error'] if error_data['error_code'] == CAPTCHA_IS_NEEDED: code = await vkplus.enter_captcha( error_data["captcha_img"]) if not code: return False new_data = {} new_data["captcha_key"] = code new_data["captcha_sid"] = error_data["captcha_sid"] return self.execute(code, **new_data) error_codes.append(error_data['error_code']) errors.append(error_data) if 'response' in data: for error in errors: hues.warn(str(error)) self.retry = 0 return data['response'] if AUTHORIZATION_FAILED in error_codes: hues.warn( "Пользователь не отвечает. Попробую переполучить токен.") await self.user(self.username, self.password, self.app_id, self.scope) self.retry += 1 return await self.execute(code) return False
def logs(aims, conditions, wants, res, yesorno, others=""): """ 0 失败 1 成功 2 警告 """ #################################### 命令行即时输出 if yesorno == 0: yesornostr = u"测试点验证未通过, 请查阅具体记录" + others colorstr = "\033[1;31;40m" #红色 if yesorno == 1: yesornostr = u"测试点验证通过" + others colorstr = "\033[1;32;40m" #绿色 if yesorno == 2: yesornostr = u"警告, 请查阅具体记录" + others colorstr = "\033[1;33;40m" #橙黄色 closecolor = "\033[0m" ##### 非LINUX不支持以上模式的彩色日志输出 if platform.system() != "Linux": colorstr = "" closecolor = "" ###### print("---------------------------------------------------------") print(u"动作名称/目的: " + aims + " " + u"前置条件/判断类型:" + " " + conditions) outputlog = u"预期: " + wants + " " + u"实际结果:" + " " + res + " " + u"\n判定: " + yesornostr #print(colorstr + outputlog + closecolor ) ## 这种模式不兼容 windows , 因此暂时停止使用 ### 暂时使用以下模式 #hues.log hues.info hues.error hues.warn hues.success if yesorno == 0: hues.error(outputlog) if yesorno == 1: hues.success(outputlog) if yesorno == 2: hues.warn(outputlog) ################################################## 报告输出 #### 获得是否报告的标记位 reports = get_reports_tag() ##### 报告标记位正常 if reports != 0: doc = documents.doc doc.insert_text("\n") # 插入表格 doc.insert_text(u"★ 用例及记录 " + str(documents.ids) + u" 判定") ###### 颜色定义 gray = 0xcdc9c9 #灰色 green = 0x228b22 #绿色 if platform.system() == "Linux": red = 0xff4500 #红色 yellow = 0xffd700 #黄色 if platform.system() == "Windows": red = 0x0045ff #红色 yellow = 0x00d7ff #黄色 ###### 结论 表格 在最上方 mytable0 = doc.insert_table(3, 1) doc.table_setattr(mytable0, "A1", "BackColor", gray) doc.insert_tabletext(mytable0, "A1", u"自动化判定结果") # 时间 times = time.strftime('%Y-%m-%d %X', time.localtime()) doc.insert_tabletext(mytable0, "A2", times) if yesorno == 0: ### 错误时的突出显示 doc.table_setattr(mytable0, "A3", "BackColor", red) # 红色 if yesorno == 1: doc.table_setattr(mytable0, "A3", "BackColor", green) # 绿色 if yesorno == 2: doc.table_setattr(mytable0, "A3", "BackColor", yellow) # 黄色 doc.insert_tabletext(mytable0, "A3", yesornostr) ##### 前提 表格 mytable1 = doc.insert_table(2, 2) doc.table_setattr(mytable1, "A1", "BackColor", gray) doc.table_setattr(mytable1, "B1", "BackColor", gray) doc.insert_tabletext(mytable1, "A1", u"动作名称/目的") doc.insert_tabletext(mytable1, "B1", u"前置条件/判断类型") doc.insert_tabletext(mytable1, "A2", aims) doc.insert_tabletext(mytable1, "B2", conditions) ##### 预期和返回 表格 mytable2 = doc.insert_table(2, 2) doc.table_setattr(mytable2, "A1", "BackColor", gray) doc.table_setattr(mytable2, "B1", "BackColor", gray) doc.insert_tabletext(mytable2, "A1", u"自动化用例预期") doc.insert_tabletext(mytable2, "B1", u"自动化获取结果") doc.insert_tabletext(mytable2, "A2", wants) doc.insert_tabletext(mytable2, "B2", res) ### 用例号 documents.ids = documents.ids + 1 ############# 最后: 错误即抛出异常,以便捕获 if yesorno == 0: raise ValueError('测试用例识别到错误')
async def execute(self, code, **additional_values): if self.retry > 10: hues.warn("Не могу войти в ВК!") return False new = code.replace("\n", "<br>").replace("\r", "") url = f"https://api.vk.com/method/execute?access_token={self.token}&v=5.64" async with self.session.post(url, data={ "code": new, **additional_values }, **self.req_kwargs) as resp: errors = [] error_codes = [] for data in json_iter_parse(await resp.text()): if 'error' in data: error_data = data['error'] if error_data['error_code'] == CAPTCHA_IS_NEEDED: captcha_key = await vkplus.enter_captcha( error_data["captcha_img"]) if not captcha_key: return False new_data = { "captcha_key": captcha_key, "captcha_sid": error_data["captcha_sid"] } return await self.execute(code, **additional_values, **new_data) error_codes.append(error_data['error_code']) errors.append(error_data) if 'response' in data: if errors: hues.error( "Ошбка во время запроса(запрос вернул что-то)") for k in errors: hues.error(k.get("error_code", "")) hues.error(k.get("error_msg", "")) hues.error(k.get("request_params", "")) self.retry = 0 if data['response'] is None: error_codes.append(INTERNAL_ERROR) errors.append("unknown") return data['response'] if INTERNAL_ERROR in error_codes: hues.warn("Ошибка у ВК.") await self.user(self.username, self.password, self.app_id, self.scope) self.retry += 1 await asyncio.sleep(1) return await self.execute(code) if AUTHORIZATION_FAILED in error_codes: hues.warn( "Пользователь не отвечает. Попробую переполучить токен.") await self.user(self.username, self.password, self.app_id, self.scope) self.retry += 1 return await self.execute(code) if errors: hues.error("Ошибка при запросе!") for k in errors: hues.error(k.get("error_code", "")) hues.error(k.get("error_msg", "")) hues.error(k.get("request_params", "")) return False
continue # Обновляем время, чтобы не приходили старые события self.longpoll_values['ts'] = events['ts'] for event in events['updates']: schedule_coroutine(self.check_event(event)) if __name__ == '__main__': hues.info("Приступаю к запуску DarkVKBOT") bot = Bot() main_loop = asyncio.get_event_loop() main_loop.run_until_complete(set_up_roles(bot)) hues.success("Приступаю к приему сообщений") try: main_loop.run_until_complete(bot.run(main_loop)) except (KeyboardInterrupt, SystemExit): hues.warn("Выключение бота...") except Exception as ex: import traceback logging.warning("Fatal error:\n") traceback.print_exc() exit(1)
def routine(manual=True) -> None: Methods.console_clear() vk = VkAPI() _settings = None if os.path.exists('./settings.json'): with open('./settings.json') as f: try: _settings = json.loads(f.read()) except Exception: hues.error('Bad settings') os.remove('./settings.json') os._exit(-1) hues.success('Settings loaded.') from source.static.StaticData import StaticData if not Settings.settings_get(): Settings.settings_save(StaticData.defaultSettings) _settings = Settings.settings_get() if manual: if not _settings.get('safe_zone'): hues.warn('No users in safe zone.\nContinue? (y/n)') _choice = input('> ').lower() while _choice != 'y' and _choice != 'n': hues.warn('No users in safe zone.\nContinue? (y/n)') _choice = input('> ').lower() if _choice == 'n': Methods.console_clear() return _ban_list = [] from copy import copy from source.static.StaticMethods import StaticMethods _friends = vk.friends_get() _friends['items'] += vk.get_out_requests()['items'] if _settings.get('safe_zone'): for _friend in _friends['items']: if str(_friend) not in _settings['safe_zone']: _ban_list.append(_friend) _ban_list = list([str(x) for x in _ban_list]) else: _ban_list = list([str(x) for x in _friends['items']]) if _settings['newsfeedBan']: if manual: hues.warn( f'{len(_ban_list)} your friends (and out requests) will be affected.\nContinue? (y/n)' ) _choice = input('> ').lower() while _choice != 'y' and _choice != 'n': _choice = input('> ').lower() if _choice == 'n': Methods.console_clear() return __init_count = len(_ban_list) _temp = copy(_ban_list) while len(_temp) > 0: if manual: hues.log( f'[Newsfeed] Progress: {StaticMethods.get_percentage(abs(__init_count - len(_temp)), __init_count)}' ) vk.add_newsfeed_ban(_temp[:100]) del (_temp[:100]) sleep(0.4) if _settings['messagesBan']: pass if _settings['storiesBan']: _temp = copy(_ban_list) __init_count = len(_temp) while len(_temp) > 0: if manual: hues.log( f'[Stories] Progress: {StaticMethods.get_percentage(abs(__init_count - len(_temp)), __init_count)}' ) vk.stories_ban(_temp[:100]) del (_temp[:100]) sleep(0.4) if manual: Methods.console_clear() hues.success('Work done!')
text_to_days = { "завтра": 1, "послезавтра": 2, "через день": 2, "через 1 день": 2, "через 2 дня": 3, "через 3 дня": 4, "через 4 дня": 5, "через 5 дней": 6, "через 6 дней": 7, "через 7 дней": 8 } if code == "fe198ba65970ed3877578f728f33e0f9": hues.warn( "Вы используете общественный ключ для openweathermap.org! Рекомендуем вам получить личный!" ) @plugin.on_init() async def init(vk): plugin.temp_data["weather"] = {} schedule_coroutine(clear_cache()) @plugin.schedule(10800) # 3 часа async def clear_cache(stopper): plugin.temp_data["weather"] = {}