def set_widget(): service = VkApi(token=bot.get_settings("service_token"), api_version=bot.vk.api_version) widget = { "title": "Список лучших игроков клана", "title_url": "https://vk.com/kronos_bs", "more": "Перейти к полному списку", "more_url": "https://vk.com/topic-187742365_41459579", "head": [{ "text": "Игрок", "align": "left" }, { "text": "Трофеи", "align": "right" }], "body": [] } members = brawl.get_club_members("#R020J99L", limit=11).response["items"] for k in range(0, len(members)): widget["body"].append([{ "text": "{}. {}".format(k+1, members[k]["name"]) }, { "text": bot.get_messages("widget_member", t=members[k]["trophies"]) }]) widget["title_counter"] = len(members) try: service.method("appWidgets.update", { "type": "table", "code": "return " + dumps(widget, ensure_ascii=False, separators=(",", ":")) + ";" }) except: bot.log_exception()
class Bot: """Бот""" def __init__(self, token, id, db): super().__init__() self.token = token self.id = id self.db = db self.session = VkApi(token=token, api_version="5.124") self.vk = self.session.get_api() #self.longpoll = VkBotLongPoll(self.session, group_id=id) self.keyboards = None def setKeyboards(self, keyboards): self.keyboards = keyboards def newUser(self, event): self.sendKeyboard(event.object.user_id, "main_keyboard", "Добро пожаловать!") def userExit(self, event): #print(f"Пользователь {event.object.user_id} запретил сообщения.") pass def writeMsg(self, user_id, message): """Отправить пользователю сообщение""" self.session.method('messages.send', {'user_id': user_id, 'message': message, "random_id":get_random_id()}) def attachmentMsg(self, user_id, attachment_type, attachment_id): """Отправить пользователю изображение""" ownid = f"-{self.id}" self.session.method('messages.send', {'user_id': user_id, "random_id":get_random_id(), "attachment":f"{attachment_type}{ownid}_{attachment_id}"}) def repostPost(self, user_id, id): """Отправить пользователю запись""" self.attachmentMsg(user_id, "wall", id) def setCurrentKeyboard(self, id, keyboard): """Установить клавиатуру в бд""" self.db.update("Students", "current_keyboard", f"'{keyboard}'", f"WHERE user_id='{id}'") self.db.connection.commit() def sendKeyboard(self, from_id, keyboard, text="", set_as_current=False, static=False): """Отправить пользователю клавиатуру""" if keyboard in self.keyboards: if text == "": text = "Выполнено" if set_as_current: self.setCurrentKeyboard(from_id, keyboard) if static: keyboard=self.keyboards[keyboard].build(from_id) keyboard = keyboard.get_keyboard() else: keyboard = self.keyboards[keyboard].keyboard.get_keyboard() self.vk.messages.send( user_id=from_id, random_id=get_random_id(), peer_id=from_id, keyboard=keyboard, message=text )
class VkAPI: def __init__(self, token): self._api = VkApi(token=token) self._longpoll = VkLongPoll(self._api) def write_msg(self, user_id, s): self._api.method('messages.send', {'user_id': user_id, 'message': s}) def get_incoming_events(self): return (e for e in self._longpoll.listen() if e.to_me)
def _send_startup_event(group_id, group_secret): account = random.choice(tech_accounts) sess = VkApi(token=account['access_token']) payload = {'group_id': abs(group_id)} resp = sess.method('messages.allowMessagesFromGroup', payload) data_json = { "type": "message_new", "object": { "date": int(time.time()), "from_id": account['id'], "id": 777, "out": 0, "peer_id": account['id'], "text": "/startup", "conversation_message_id": 777, "fwd_messages": [], "important": False, "random_id": 0, "attachments": [], "is_hidden": False }, "group_id": abs(group_id), "secret": group_secret } data = json.dumps(data_json) req = requests.post(DJANGO_URL, data=data) return 1
class BaseVkBot: token = '' api_v = '' vk = None longPoll = None def __init__(self): self.loadEnv() self.token = environ['token'] self.api_v = environ['api_v'] self.vk = VkApi(token=self.token) self.longPoll = longpoll.VkLongPoll(self.vk) def run(self): for event in self.longPoll.listen(): if event.type == longpoll.VkEventType.MESSAGE_NEW and event.to_me: self.newMessage({ 'user_id': event.user_id, 'message': event.text }) def loadEnv(self): try: file = open('.env', 'r') for line in file: line = line.rstrip() temp = line.split('=') environ[temp[0]] = temp[1] except FileNotFoundError as e: print('File .env not exists') exit() def sendMessage(self, user_id, message): random_id = randint(1, 10000000) self.vk.method('messages.send', { 'user_id': user_id, 'message': message, 'random_id': random_id }) def newMessage(self, event): pass
class VK: def __init__(self, token=None): self.vk = VkApi(token=token) self.log = getLogger('VK') try: self.who_am_i() except ApiError: self.log.fatal('Invalid VK token passed') exit(-1) def get_conversations(self): result = [] offset = 0 while True: data = self.vk.method('messages.getConversations', {'offset': offset, 'count': 200, 'extended': 0}) if not data['items']: break data['items'] = [x for x in data['items'] if x['conversation']['peer']['type'] == 'user' and x['conversation']['peer']['id'] != 100] sleep(0.4) offset += 200 result.append(data) return result def get_messages(self, conversation, offset=0): while True: data = self.vk.method('messages.getHistory', { 'offset': offset, 'count': 200, 'user_id': conversation['conversation']['peer']['id'], 'extended': 0 }) offset += 200 if not data['items']: break yield data, offset def who_am_i(self): return self.vk.method('users.get')[0] def get_sns(self, ids: list) -> tuple: ids = [str(x) for x in ids] return tuple([(x.get('first_name', None), x.get('last_name', None)) if x.get('first_name') and x.get('last_name') else ('Удаленный', 'пользователь') for x in self.vk.method('users.get', {'user_ids': ','.join(ids)})])
def set_topic(): user = VkApi(token=bot.get_settings("admin_token"), api_version=bot.vk.api_version) members = brawl.get_club_members("#R020J99L").response["items"] msg = "Список участников [{}/100]\n".format(len(members)) for k in range(0, len(members)): msg += bot.get_messages("member", role=get_role(members[k]["role"]), t=members[k]["trophies"], name=members[k]["name"], tag=members[k]["tag"], n=k+1 ) msg += "\n" try: user.method("board.editComment", { "group_id": bot.lp.group_id, "comment_id": 2, "topic_id": 41459579, "message": msg }) except: bot.log_exception()
def load_avatars(): login, password = json.load(open('secret.json')) vk = VkApi(login, password) vk.auth() target = 'annndruha' members = [] try: id = int(target.replace('id', '')) except: id = vk.method('users.get', {'user_ids': target})[0]['id'] members = vk.method('friends.get', {'user_id': id})["items"] print(len(members)) #print(members) members_str = ','.join(map(str, members)) members_data = vk.method('users.get', { 'user_ids': members_str, 'fields': 'photo_400_orig' }) for data in members_data: try: url = data['photo_400_orig'] id = data['id'] filename = f'avatars/{id}.jpg' response = requests.get(url) if response.status_code == 200: with open(filename, 'wb') as imgfile: imgfile.write(response.content) except: pass
def initializeTracksCount(self): session = VkApi(self.authScreen.loginInput.text, self.authScreen.passInput.text, auth_handler=self.authHandler, captcha_handler=self.captchaHandler) try: session.auth(reauth=True) except Exception as ex: self.screenManagement.transition.direction = "left" self.screenManagement.current = "auth" print(ex) return audio = vkapi.audio(session) self.tracksCount = audio.get_len_user_audio() if self.tracksCount != 0: self.startScreen.tracksCount.label = "Аудиозаписей: " + str( self.tracksCount) else: self.startScreen.tracksCount.label = "Нет аудиозаписей" user = session.method("users.get", { "user_ids": audio.user_id, "fields": "photo_200" }) self.startScreen.username.text = user[0]["first_name"] + ' ' + user[0][ "last_name"] self.startScreen.avatar.source = user[0]["photo_200"] self.screenManagement.transition.direction = "left" self.screenManagement.current = "start"
class GetAudioListThread(QThread): signal = pyqtSignal("PyQt_PyObject") str_signal = pyqtSignal(str) image_signal = pyqtSignal("QImage") def __init__(self, cookie, window): QThread.__init__(self) self.login = "" self.password = "" self.user_link = "" self.statusBar = None self.save_password = False self.authorized = False self.cookie = cookie self.window = window def __del__(self): self.wait() def _user_auth(self): if self.login: self.session = VkApi( login=self.login, password=self.password, auth_handler=self.auth_handler, captcha_handler=self.captcha_handler, config_filename=self.cookie, ) self.statusBar.showMessage("Авторизация.") self.session.auth() else: self.statusBar.showMessage( "Логин не указан, использование пароля в качестве токена") self.session = VkApi(token=self.password, captcha_handler=self.captcha_handler) self.vk_audio = VkAudio(self.session) self.authorized = True def _get_audio(self): tracks = [] albums = [] string = str() # Try to get post audio list post = self.get_group_and_post_id(self.user_link) album = self.get_album_id(self.user_link) if isinstance(post, tuple): owner_id, post_id = post self.statusBar.showMessage("Получение списка аудиозаписей поста.") string = "Аудиозаписи поста" tracks = self.vk_audio.get_post_audio(owner_id, post_id) audios = ",".join(["{owner_id}_{id}".format(**i) for i in tracks]) tracks = self.session.method(method="audio.getById", values={"audios": audios}) elif isinstance(album, tuple): owner_id, album_id, *_ = album self.statusBar.showMessage( "Получение списка аудиозаписей альбома.") string = "Аудиозаписи альбома" tracks = self._get_tracks(owner_id, album_id) else: user_id = self.get_user_id(self.user_link) # Try to get user or group audio list # noinspection PyBroadException try: owner_id = self.session.method("users.get", dict(user_ids=user_id))[0] self.statusBar.showMessage( "Получение списка аудиозаписей пользователя: {first_name} {last_name}" .format(**owner_id)) string = "Музыка пользователя: {first_name} {last_name}".format( **owner_id) except Exception: group_id = self.session.method("groups.getById", dict(group_id=user_id))[0] self.statusBar.showMessage( "Получение списка аудиозаписей сообщества: {name}".format( **group_id)) string = "Музыка сообщества: {}".format(group_id["name"]) albums = self._get_albums(-group_id["id"]) tracks = self._get_tracks(-group_id["id"]) else: albums = self._get_albums(owner_id["id"]) tracks = self._get_tracks(owner_id["id"]) for album in albums: try: album["tracks"] = self.vk_audio.get( owner_id=album["owner_id"], album_id=album["id"], access_hash=album["access_hash"], ) except: album["tracks"] = self._get_tracks(owner_id["id"], album["id"]) return tracks, string, albums def _get_tracks(self, owner_id, album_id=None, access_hash=None): try: tracks = self.vk_audio.get(owner_id, album_id, access_hash) except: values = {"owner_id": owner_id} if album_id: values.update({"album_id": album_id}) res = self.session.method( method="audio.get", values=values, ) count = res["count"] offset = 0 tracks = [] while count != 0: audios = ",".join( ["{owner_id}_{id}".format(**i) for i in res["items"]]) tracks.extend( self.session.method(method="audio.getById", values={"audios": audios})) offset += 200 if count >= 200 else count % 200 count -= 200 if count >= 200 else count % 200 values.update({"offset": offset}) res = self.session.method( method="audio.get", values=values, ) return tracks def _get_albums(self, owner_id): try: albums = self.vk_audio.get_albums(owner_id["id"]) except: res = self.session.method( method="audio.getPlaylists", values={"owner_id": owner_id}, ) count = res["count"] offset = 0 albums = [] while count != 0: albums.extend(res["items"]) offset += 10 if count >= 10 else count % 10 count -= 10 if count >= 10 else count % 10 res = self.session.method( method="audio.getPlaylists", values={ "owner_id": owner_id, "offset": offset }, ) return albums def auth_handler(self): """ При двухфакторной аутентификации вызывается эта функция. :return: key, remember_device """ self.str_signal.emit("Введите код авторизации:") while not self.window.key: pass return self.window.key, self.save_password def captcha_handler(self, captcha): url = captcha.get_url() file = TemporaryFile() res = self.session.http.get(url, stream=True) res.raw.decode_content = True shutil.copyfileobj(res.raw, file) file.seek(0) image = QImage() image.loadFromData(file.read()) self.image_signal.emit(image) while not self.window.key: pass return captcha.try_again(self.window.key) def run(self): try: if not self.authorized: self._user_auth() result = self._get_audio() self.signal.emit(result) except exceptions.BadPassword: self.signal.emit("Неверный логин или пароль.") except exceptions.LoginRequired: self.signal.emit("Требуется логин.") except exceptions.PasswordRequired: self.signal.emit("Требуется пароль.") except (IndexError, AttributeError): self.signal.emit( "Невозможно получить список аудиозаписей. Проверьте, открыты ли они у пользователя." ) except exceptions.ApiError as e: if "113" in str(e): self.signal.emit( "Неверная ссылка на профиль пользователя (неверный ID пользователя)." ) elif "100" in str(e): self.signal.emit( "Неверная ссылка на профиль пользователя (сообщества).") else: self.signal.emit(str(e)) except Exception as e: self.signal.emit(str(type(e)) + str(e)) @staticmethod def get_user_id(link): result = findall(r"(https?://m?\.?vk\.com/)?(.*)$", link)[0][1] return result if result else None @staticmethod def get_group_and_post_id(link): result = findall(r"wall(.*?)_(.*?)$", link) return result[0] if result else None @staticmethod def get_album_id(link): link = link.replace("%2F", "/") result = findall(r"playlist/(.*)_(.*)_(.*)\?", link) if not result: result = findall(r"playlist/(.*)_(.*)_(.*)", link) if not result: result = findall(r"audio_playlist(.*)_(.*)&access_hash=(.*)", link) if not result: result = findall(r"audio_playlist(.*)_(.*)/(.*)", link) if not result: result = findall(r"audio_playlist(.*)_(.*)", link) return result[0] if result else None
def group_add(access_token, CurrentUse=None): # todo get latest chat id need_perms = ['photos', 'docs', 'messages', 'manage', 'wall'] sess = VkApi(token=access_token) try: perms = sess.method('groups.getTokenPermissions') except: return 0, 'Неверный токен' have_perms = set() for perm in perms['permissions']: have_perms.add(perm['name']) for perm in need_perms: if perm not in have_perms: return 0, 'Необходимые права токена: ' + ', '.join(need_perms) group = sess.method('groups.getById', {'fields': 'description'})[0] group_id = group['id'] try: group_obj = ConnectedGroup.objects.get(id=-group_id) return 0, 'Эта группа уже есть в базе данных' except ObjectDoesNotExist: pass payload = { 'group_id': group_id, 'enabled': 1, 'api_version': 5.87, 'message_new': 1, 'group_change_settings': 1, } # todo all to 0? try: result = sess.method('groups.setLongPollSettings', payload) except: result = 0 if not result: return 0, 'Не удалось изменить настройки Long Poll сервера' payload = { 'group_id': group_id, 'messages': 1, 'bots_add_to_chat': 1, 'bots_capabilities': 1, 'bots_start_button': 1, 'v': 5.101 } try: result = sess.method('groups.setSettings', payload) except: result = 0 if not result: return 0, 'Не удалось включить функции бота' secret = randomString(16) owner = CurrentUse.user group_obj = ConnectedGroup(id=-group_id, access_token=access_token, secret=secret, owner=owner) group_obj.save() time.sleep(1) r = _send_startup_event(group_id, secret) notify('Добавлена новая группа\nhttps://vk.com/club{}'.format( abs(group_id))) return 1, '1'
class Vk: session = None long_pool = None def __init__(self, token): self.session = VkApi(token=token) self.long_pool = VkLongPoll(self.session) def send(self, id, text, buttons=None, forward_messages=None, attachments=None): if type(text) is list: text = text[random.randint(0, len(text) - 1)] message = { 'user_id': id, 'message': text, 'forward_messages': forward_messages, 'attachment': attachments, 'random_id': random.randint(0, sys.maxsize * sys.maxsize * 2) } if buttons or buttons == []: message.update({ 'keyboard': str(json.dumps({ 'one_time': False, 'buttons': buttons })) }) self.session.method('messages.send', message) def send_sticker(self, id, num): self.session.method( 'messages.send', { 'user_id': id, 'sticker_id': num, 'random_id': random.randint(0, sys.maxsize * sys.maxsize * 2) }) def send_message_sticker(self, id, text, sticker_num): self.send(id, text) self.send_sticker(id, sticker_num) def get_unread_conversations(self, offset=0, count=200): conversations = self.session.method('messages.getConversations', { 'filter': 'unread', 'offset': offset, 'count': count, 'extended': 0 }) return [ conversation for conversation in conversations['items'] if conversation['conversation']['peer']['type'] != 'chat' ], conversations['count'] def get_message_attachments(self, message_id): attachments = self.session.method('messages.getById', {'message_ids': message_id}) return attachments['items'][0][ 'attachments'] if attachments['count'] != 0 else None def get_users_names(self, user_ids): try: users = self.session.method('users.get', {'user_ids': user_ids}) return [ f'{user["first_name"]} {user["last_name"]}' for user in users ] except: return None @staticmethod def is_photo(event): return event.attachments and event.attachments.get( 'attach1_type') == MediaTypes.photo @staticmethod def is_audio_msg(event): return event.attachments and event.attachments.get( 'attach1_kind') == MediaTypes.audiomsg @staticmethod def is_audio(event): return event.attachments and event.attachments.get( 'attach1_type') == MediaTypes.audio @staticmethod def is_video(event): return event.attachments and event.attachments.get( 'attach1_type') == MediaTypes.video
def splitJson(array): js = {} for i in range(0, len(array) - 1): js.update({array[i]: array[i + 1]}) return js f = open('config.conf') data = f.read().replace(' ', '').split('\n') f.close() confLog = splitJson(data[0].split(':')) configPass = splitJson(data[1].split(':')) confLog.update(configPass) selector = input("Selector: ") ids = input("id: ") file = input("File: ") from vk_api import VkApi vk = VkApi(login=confLog['login'], password=confLog['password']) vk.auth() token = vk.token['access_token'] dray = lib.UploadVoiceMsg(token, "voices/" + file) dray.upload() vk.method("messages.send", { selector: ids, 'attachment': dray.returnAttachment() }) print("all is okay")
'payload': payload, 'callback': None } response.append(cur_action) if agr_level in agr_handlers and agr_handlers[agr_level]: response = agr_handlers[agr_level](response) return response try: sess = VkApi(token=VK_MY_TOKEN) exec_stack = ExecuteStack(sess) payload = {'user_ids': uid, 'fields': 'online'} is_online = sess.method('users.get', payload)[0]['online'] if is_online and (time.time() - storage['latest_send']) > SEND_TIMEOUT: storage['latest_send'] = time.time() actions = gen_actions() for action in actions: exec_stack.add(action['method'], action['payload'], additional=action['callback']) resps = exec_stack.finish() for resp, callback in resps: if callback: callback(resp) storage['current_notifies'] += 1 if storage['current_notifies'] == 1: storage['current_first'] = time.time()
class GetInfo: def __init__(self, login, password, target, type = 'group_members', normed = False): self.vk = VkApi(login, password) self.vk.auth() self.target = target self.type = type self.normed = normed self.members = [] self.bdate_mans = [] self.bdate_womans = [] self.count_of_members = 0 self.mens = 0 self.womans =0 self.no_sex = 0 self.deleted = 0 self.banned = 0 self.active = 0 self.open_accounts=0 self.closed_accounts=0 self.avg_mens = 0 self.avg_womans = 0 def get_members_ids(self): offset = 0 if not os.path.exists(str(self.target)): os.makedirs(str(self.target)) try: if self.type == 'group_members': self.count_of_members = self.vk.method('groups.getMembers', {'group_id':self.target, 'count':1})['count'] start_time = time.time() while len(self.members)<self.count_of_members: _persent = int(100*len(self.members)/self.count_of_members) _mem = f'{len(self.members)}/{self.count_of_members}' _time = "%.1f" % (time.time()-start_time) _time_left = "%.1f" % (self.count_of_members*(time.time()-start_time)/(len(self.members)+1)-(time.time()-start_time)) print(f'Geting ids... {_persent}% ({_mem})\t time: {_time} \t left: {_time_left}') self.members += self.vk.method('execute', {'code': '''var members = []; var offset = %i; var i = 0; var members_count = %i; while ((i<25) &&(offset<members_count)) { members = members + API.groups.getMembers({"group_id":"%s", "offset":offset })["items"]; i = i + 1; offset = offset + 1000; }; return members;''' % (offset, self.count_of_members, self.target) }) offset +=25000 elif self.type == 'user_friends': print(f'Get friens ids...') try: id = int(self.target.replace('id','')) except: id = self.vk.method('users.get', {'user_ids':self.target})[0]['id'] else: self.vk.method('friends.get', {'user_id':id}) self.members +=self.vk.method('friends.get', {'user_id':id})["items"] self.count_of_members = len(self.members) print(f'Users: {self.count_of_members}') print('Get ids done. Saving...') except Exception as err: print(f'Exception: {str(err)}') with open(f'{self.target}/{self.target}_ids.json', 'w') as outfile: json.dump(self.members, outfile) print('Ids saved.') return None def get_users_data(self): print('Ids loading...') members_ids = json.load(open(f'{self.target}/{self.target}_ids.json')) print('Ids loaded. Start getting data...') try: offset = 0 members_data = [] start_time = time.time() while offset < len(members_ids): members = members_ids[offset:offset+1000] members_str = ','.join(map(str, members)) members_data += self.vk.method('users.get', {'user_ids':members_str, 'fields':'bdate, sex'}) offset += 1000 _persent = int(100*len(members_data)/len(members_ids)) _mem = f'{len(members_data)}/{len(members_ids)}' _time = "%.1f" % (time.time()-start_time) _time_left = "%.1f" % (len(members_ids)*(time.time()-start_time)/(len(members_data))-(time.time()-start_time)) print(f'Geting data... {_persent}% ({_mem})\t time: {_time} \t left: {_time_left}') print('Get users data done. Saving...') except Exception as err: print(f'Exception: {str(err)}') with open(f'{self.target}/{self.target}_data.json', 'w') as outfile: json.dump(members_data, outfile) print('Users data saved.') return None def calculate(self): print('Users data loading...') members_data = json.load(open(f'{self.target}/{self.target}_data.json')) self.count_of_members = len(members_data) print('Users data loaded.') print('Calculate...') for data in members_data: if 'deactivated' in data: if data['deactivated']=='deleted':self.deleted+=1 else: self.banned+=1 continue self.active += 1 if data['is_closed']: self.closed_accounts +=1 else: self.open_accounts +=1 if data['sex']==1: self.womans += 1 elif data['sex']==2: self.mens += 1 else: self.no_sex +=1 if (('bdate' in data) and (len(data['bdate'].split('.'))==3)): # Если дата указана и содержит год рожения year = int((data['bdate'].split('.'))[2]) if year>1960: # Хвост графика из фейковых дат рождения нас не интересует if data['sex']==1: self.bdate_womans.append(year) elif data['sex']==2: self.bdate_mans.append(year) print('Calculate done.') return None def make_plot(self): print('Plotting...') bdate_mans = np.array(self.bdate_mans) bdate_womans = np.array(self.bdate_womans) self.avg_mens = np.average(bdate_mans) self.avg_womans = np.average(bdate_womans) bins = np.arange(min(min(bdate_womans),min(bdate_mans)), max(max(bdate_womans),max(bdate_mans))+1, 1) fig, ax1 = plt.subplots() fig.set_size_inches((16, 9), forward=False) if self.normed: # Нормируется соотношение полов, основываясь на общем соотношении, независимо от числа открытых женских аккаунтов norm_koeff = (self.mens/self.womans)/(len(bdate_mans)/len(bdate_womans)) bincount_m = np.bincount(bdate_mans)[1961:]*norm_koeff bincount_w = np.bincount(bdate_womans)[1961:] else: bincount_m = np.bincount(bdate_mans)[1961:] bincount_w = np.bincount(bdate_womans)[1961:] if len(bincount_m)<len(bincount_w): n = len(bincount_w)-len(bincount_m) bincount_m = np.pad(bincount_m, [(0,n)], mode='constant') else: n = len(bincount_m)-len(bincount_w) bincount_w = np.pad(bincount_w, [(0,n)], mode='constant') try: width = 0.4 ax1.bar(bins- width/2, bincount_w, width, label = 'W', color = ['violet']) ax1.bar(bins+ width/2, bincount_m, width, label = 'M', color = ['slateblue']) except: bdates = np.array([bdate_womans, bdate_mans]) ax1.hist(bdates, bins, histtype='bar', align='left', color = ['violet','slateblue']) labels = [str(i) for i in bins] ax1.set_xticks(bins) ax1.set_xticklabels(labels, rotation=90) ax1.set_xlabel("Год рождения") ax1.set_ylabel("Количество человек") labels_top = [str(2020-i) for i in bins] ax2 = ax1.twiny() ax2.set_xlim(ax1.get_xlim()) ax2.set_xticks(bins) ax2.set_xticklabels(labels_top, rotation=90) ax2.set_xlabel("Возраст") try: if self.type == 'group_members': group_info = self.vk.method('groups.getById', {'group_ids':self.target}) plt.title(f'''"{group_info[0]["name"]}" - Возрастно-половая диаграмма''') else: user_info = self.vk.method('users.get', {'user_ids':self.target})[0] first_name, last_name = user_info['first_name'], user_info['last_name'] plt.title(f'Возрастно-половая диаграмма друзей: {first_name} {last_name}') except: plt.title(f'Возрастно-половая диаграмма: {self.target}') a = mpatches.Patch(color='slateblue', label=f'Мужчин: {self.mens} ({int(100*(self.mens/(self.mens+self.womans)))}%)') b = mpatches.Patch(color='violet', label=f'Женщин: {self.womans} ({int(100*(self.womans/(self.mens+self.womans)))}%)') c = mpatches.Patch(color='white', label ='') d = mpatches.Patch(color='gray', label=f'Активных: {self.active} ({int(100*(self.active/(self.banned+self.active+self.deleted)))}%)') e = mpatches.Patch(color='gray', label=f'Активных закрытых: {self.closed_accounts} ({int(100*(self.closed_accounts/(self.open_accounts+self.closed_accounts)))}%)') f = mpatches.Patch(color='gray', label=f'Активных открытых: {self.open_accounts} ({int(100*(self.open_accounts/(self.open_accounts+self.closed_accounts)))}%)') g = mpatches.Patch(color='gray', label=f'Удалённых: {self.deleted} ({int(100*(self.deleted/(self.banned+self.active+self.deleted)))}%)') h = mpatches.Patch(color='gray', label=f'Заблокированных: {self.banned} ({int(100*(self.banned/(self.banned+self.active+self.deleted)))}%)') i = mpatches.Patch(color='gray', label=f'Всего: {self.count_of_members}') j = mpatches.Patch(color='white', label ='') k = mpatches.Patch(color='gray', label=f'Указан год и пол: {len(bdate_womans)+len(bdate_mans)} ({int(100*((len(bdate_womans)+len(bdate_mans))/self.count_of_members))}%)') l = mpatches.Patch(color='gray', label=f'из них: М: {len(bdate_mans)} ({int(100*(len(bdate_mans)/(len(bdate_womans)+len(bdate_mans))))}%) Ж: {len(bdate_womans)} ({int(100*(len(bdate_womans)/(len(bdate_womans)+len(bdate_mans))))}%)') m = mpatches.Patch(color='gray', label =f'Нормировка графика по полу: {self.normed}') n = mpatches.Patch(color='gray', label =f'Ср. возраст мужчин: {2020-int(self.avg_mens)}') o = mpatches.Patch(color='gray', label =f'Ср. возраст женщин: {2020-int(self.avg_womans)}') plt.legend(handles=[a,b,c,d,e,f,g,h,i,j,k,l,m,n,o], loc='upper left') plt.savefig(f'{self.target}/{self.target}.png', dpi=320, bbox_inches='tight') print(f'Plot save in {self.target}/{self.target}.png') return None
class VkBot(IBot): def __init__(self, token: str, group_id: int): super().__init__() self._api = VkApi(token=token) self._longpoll = VkBotLongPoll(self._api, group_id=group_id) self._longpoll.wait = 0 self._current_user: Union[int, None] = None def change_user(self, user_id: int): self._current_user = user_id self.on_new_user.notify(user_id) def send_message(self, message: Message): if self._current_user is None: return self._api.method('messages.send', values={ 'peer_id': self._current_user, 'message': message.text, 'random_id': int(getrandbits(32)) }) def set_keyboard(self, keyboard: Keyboard, message: str = 'keyboard'): vk_keyboard = VkKeyboard(True) current_line = 1 for pos, button in keyboard.all(): row, column = pos if row + 1 < current_line: current_line += 1 vk_keyboard.add_line() vk_keyboard.add_button(button.text, VK_BUTTON_COLOR[button.color]) self._api.method('messages.send', values={ 'peer_id': self._current_user, 'random_id': int(getrandbits(32)), 'keyboard': vk_keyboard.get_keyboard(), 'message': message }) def get_current_user(self): return self._current_user def handle_server_event(self): last_notification_id = int(cfg.get('SETTINGS', 'LAST_ID')) data = requests.get( cfg.get('API', 'API_ADDRESS') + f'/notifications/{last_notification_id}').json() last_notification_id = data['meta']['last_id'] cfg.set('SETTINGS', 'LAST_ID', str(last_notification_id)) cfg.write(open('settings.cfg', 'w')) for student, notifications in data['students'].items(): self.change_user(int(student)) for student_data in notifications: current_contest = None for contest, contest_data in data['contests'].items(): if contest == str(student_data['contest']): current_contest = contest_data current_contest['id'] = contest break current_stage = None for stage, stage_data in data['stages'].items(): if stage == str(student_data['stage']): current_stage = stage_data current_stage['id'] = stage break self.on_event.notify({ 'contest': current_contest, 'stage': current_stage, 'student': student }) def run(self) -> NoReturn: print('Бот начал работу!') schedule.every(5).seconds.do(self.handle_server_event) while True: try: for event in self._longpoll.check(): if event.type == VkBotEventType.MESSAGE_NEW and event.from_user: self.change_user(event.message.from_id) self.on_new_message.notify( Message(event.message.get('text', ''))) schedule.run_pending() except requests.ConnectionError: print(f'{datetime.now()}: Не удается подключиться к серверу!')
else: send('Неверно. Попытка удаления акаунта была заблокирована.') database_query(f'UPDATE users SET state=1 WHERE user_id={user_id}') elif state == 4: # состояние блокировки send('❌ Ваш акаунт был заблокирован.') elif state == 5: # состояние отправки сообщения send('✅ Отправлено;') recipient = database.execute(f'SELECT viewed_user FROM users WHERE user_id={user_id}').fetchone() recipient = database.execute( f'SELECT name, surname, user_id FROM users WHERE user_id={recipient[0]}').fetchone() sender = database.execute(f'SELECT name, surname FROM users WHERE user_id={user_id}').fetchone() user = bot.method(f'users.get', {'user_ids': [user_id], 'fields': 'screen_name'})[0] try: send(f'@{user["screen_name"]} ({sender[0]} {sender[1]}) оставил тебе сообщение:\n' f'{text}', None, recipient[2]) except: send('Пользователь заблокировал бота.') database_query(f'UPDATE users SET state=1 WHERE user_id={user_id}') view() elif state == 7: # состояние отправки реф. кода code = database.execute(f'SELECT user_id, name, surname FROM users WHERE referral_code="{text}"').fetchone() if code: if code[0] != user_id: send(f'Реферальный код пользователя {code[1]} {code[2]} принят ✅\n')
class Server: def __init__(self, api_token, server_name: str = "Empty"): self.server_name = server_name self.vk = VkApi(token=api_token) self.long_poll = VkLongPoll(self.vk) self.vk_api = self.vk.get_api() self.event = None self.current_user_id = None # словарь подобранных людей self.users_info_dict = {} # счетчик просмотра подобранных людей self.count = 0 # текущее состояние пользователя self.states = {} self.session = Session() def write_msg(self, message): self.vk.method('messages.send', {'user_id': self.event.user_id, 'message': message, 'random_id': randrange(10 ** 7)}) def write_msg_keyboard(self, message, keyboard): self.vk.method('messages.send', {'user_id': self.event.user_id, 'message': message, 'random_id': randrange(10 ** 7), 'keyboard': json.dumps(keyboards[keyboard], ensure_ascii=False)}) def write_msg_attachment(self, message, attachment, keyboard): self.vk.method('messages.send', {'user_id': self.event.user_id, 'message': message, 'random_id': randrange(10 ** 7), 'keyboard': json.dumps(keyboards[keyboard], ensure_ascii=False), 'attachment': attachment}) def hello_state(self, objects): if self.event.text == "выход" or self.event.text == "выйти": return False objects[0].state = "Initial" self.session.commit() self.write_msg_keyboard('Выберите действие:', 'greeting') def initial_state(self, objects): if self.event.text == "начать поиск": objects[0].state = "City" self.session.commit() self.write_msg('Введите город') elif self.event.text == "показать/удалить людей": orm.get_dating_list(self.event.user_id) orm.get_ignore_list(self.event.user_id) self.write_msg_keyboard('Привет! Выбери действие', 'like_ignore') elif self.event.text == "лайк": orm.dating_count = 0 objects[0].state = "Like" self.session.commit() self.write_msg_keyboard(f'У вас найдено - {len(orm.dating_list)} человек. Приступим?', 'filter_msg') elif self.event.text == "игнор": orm.ignore_count = 0 objects[0].state = "Ignore" self.session.commit() self.write_msg_keyboard(f'У вас найдено - {len(orm.ignore_list)} человек. Приступим?', 'filter_msg') elif self.event.text == "выйти": self.write_msg_keyboard('Выбери действие', 'greeting') else: self.write_msg_keyboard('Выбери действие', 'greeting') def like_state(self, objects): if self.event.text == "следующий": orm.dating_count += 1 if orm.show_dating_user(): dat_name, dat_age, dat_id, dat_attach = orm.show_dating_user() self.write_msg_attachment(f'{dat_name}\nВозраст - {dat_age}\nhttps://vk.com/id{dat_id}', f'photo{dat_id}_{dat_attach}', 'show_users') else: objects[0].state = "Initial" self.session.commit() self.write_msg_keyboard('Список закончился. Выберите действие', 'greeting') elif self.event.text == "удалить": orm.dating_list[orm.dating_count].remove_dating_user() orm.dating_count += 1 if orm.show_dating_user(): dat_name, dat_age, dat_id, dat_attach = orm.show_dating_user() self.write_msg_attachment(f'{dat_name}\nВозраст - {dat_age}\nhttps://vk.com/id{dat_id}', f'photo{dat_id}_{dat_attach}', 'show_users') else: objects[0].state = "Initial" self.session.commit() self.write_msg_keyboard('Список закончился. Выберите действие', 'greeting') elif self.event.text == "выйти": objects[0].state = "Initial" self.session.commit() self.write_msg_keyboard('Выбери действие', 'greeting') else: if orm.show_dating_user(): dat_name, dat_age, dat_id, dat_attach = orm.show_dating_user() self.write_msg_attachment(f'{dat_name}\nВозраст - {dat_age}\nhttps://vk.com/id{dat_id}', f'photo{dat_id}_{dat_attach}', 'show_users') else: objects[0].state = "Initial" self.session.commit() self.write_msg_keyboard('Лайк список пуст. Выберите действие', 'greeting') def ignore_state(self, objects): if self.event.text == "следующий": orm.ignore_count += 1 if orm.show_ignore_user(): self.write_msg_keyboard(f'https://vk.com/id{orm.show_ignore_user()}', 'show_users') else: objects[0].state = "Initial" self.session.commit() self.write_msg_keyboard('Список закончился. Выберите действие', 'greeting') elif self.event.text == "удалить": orm.ignore_list[orm.ignore_count].remove_ignore_user() orm.ignore_count += 1 if orm.show_ignore_user(): self.write_msg_keyboard(f'https://vk.com/id{orm.show_ignore_user()}', 'show_users') else: objects[0].state = "Initial" self.session.commit() self.write_msg_keyboard('Список закончился. Выберите действие', 'greeting') elif self.event.text == "выйти": self.write_msg_keyboard('Выбери действие', 'greeting') objects[0].state = "Initial" self.session.commit() else: if orm.show_ignore_user(): self.write_msg_keyboard(f'https://vk.com/id{orm.show_ignore_user()}', 'show_users') else: objects[0].state = "Initial" self.session.commit() self.write_msg_keyboard('Игнор список пуст. Выберите действие', 'greeting') def city_state(self, objects): if re.findall(r'[а-яА-яёЁ0-9]+', self.event.text): try: city_name = VkUser().get_city_name(VkUser().get_city_id(self.event.text))[0]['title'] objects[0].state = "Sex" objects[1].search_city = city_name self.session.commit() self.write_msg('Введите пол:\n1 - женщина\n2 - мужчина') except IndexError: self.write_msg('Вы ввели неверную информацию\nВведите город повторно') else: self.write_msg('Вы ввели неверную информацию\nВведите город повторно') def sex_state(self, objects): if self.event.text == '1' or self.event.text == '2': try: sex_value = int(self.event.text) objects[0].state = "Relation" objects[1].search_sex = sex_value self.session.commit() self.write_msg('Введите семейное положение\n1 — не женат/не замужем\n2 — есть друг/есть подруга\n' '3 — помолвлен/помолвлена\n4 — женат/замужем\n5 — всё сложно\n6 — в активном поиске\n' '7 — влюблён/влюблена\n8 — в гражданском браке\n0 — не указано\n') except ValueError: self.write_msg('Вы ввели неверную информацию\nВведите пол повторно\n1 - женщина\n2 - мужчина') else: self.write_msg('Вы ввели неверную информацию\nВведите пол повторно\n1 - женщина\n2 - мужчина') def relation_state(self, objects): msg = f'Вы ввели неверную информацию\nВведите статус повторно\n1 — не женат/не замужем\n' \ f'2 — есть друг/есть подруга\n3 — помолвлен/помолвлена\n4 — женат/замужем\n5 — всё сложно\n' \ f'6 — в активном поиске\n7 — влюблён/влюблена\n8 — в гражданском браке\n0 — не указано\n' if re.findall(r'[0-8]', self.event.text): try: status = int(self.event.text) objects[0].state = "Range" objects[1].search_relation = status self.session.commit() self.write_msg('Введите диапозон поиска ОТ и ДО (через пробел или -)') except ValueError: self.write_msg(msg) else: self.write_msg(msg) def range_state(self, objects): try: age_pattern = re.compile(r'(\d\d?)[ -]+(\d\d?)') age_from = int(age_pattern.sub(r"\1", self.event.text)) age_to = int(age_pattern.sub(r"\2", self.event.text)) if age_to - age_from < 0: self.write_msg('Вы ввели неверную информацию\nВведите диапозон поиска ОТ и ДО (через пробел или -)') return objects[0].state = "Decision" objects[1].search_from = age_from objects[1].search_to = age_to self.session.commit() sex = objects[1].search_sex city_name = objects[1].search_city status = objects[1].search_relation vk_server.search_dating_user(age_from, age_to, sex, city_name, status) user_founded_id, first_name, last_name, age, attachment_list = self.get_founded_user_info() while user_founded_id is None: user_founded_id, first_name, last_name, age, attachment_list = self.get_founded_user_info() if len(attachment_list) >= 1: self.write_msg_attachment(f'{first_name} {last_name}', attachment_list, 'decision') else: self.write_msg(f'{first_name} {last_name} - {attachment_list}\n') self.write_msg_keyboard('Выберите действие', 'decision') except ValueError: self.write_msg('Вы ввели неверную информацию\nВведите диапозон поиска ОТ и ДО (через пробел или -)') def get_founded_user_info(self): person = vk_server.users_info_dict['items'][self.count] user_dating_id = person['id'] # проверка наличия найденного Id в таблицах if orm.is_viewed(user_dating_id, self.event.user_id): self.count += 1 return None, None, None, None, None first_name = person['first_name'] last_name = person['last_name'] attachment_list = [] try: age = person['bdate'] age = get_age(age) except KeyError: age = 'нет данных' link_dict = VkUser().get_users_best_photos(user_dating_id) try: for photo_links in link_dict.values(): attachment = photo_links[0] attachment_list.append(f'photo{user_dating_id}_{attachment}') attachment_string = ",".join(attachment_list) return user_dating_id, first_name, last_name, age, attachment_string except AttributeError: link_dict = 'нет фотографий' return user_dating_id, first_name, last_name, age, link_dict def decision_state(self, objects): user_founded_id, first_name, last_name, age, attachment_list = self.get_founded_user_info() if self.event.text == "выход": objects[0].state = "Initial" self.session.commit() self.write_msg_keyboard('Выберите действие:', 'greeting') return elif self.event.text == "лайк": DatingUser().add_dating_user(user_founded_id, first_name, last_name, age, self.event.user_id) UserPhoto().add_user_photo(VkUser().get_users_best_photos(user_founded_id), user_founded_id, self.event.user_id) self.count += 1 user_founded_id, first_name, last_name, age, attachment_list = self.get_founded_user_info() if len(attachment_list) >= 1: self.write_msg_attachment(f'{first_name} {last_name}', attachment_list, 'decision') else: self.write_msg(f'{first_name} {last_name} - {attachment_list}\n') self.write_msg_keyboard('Выберите действие', 'decision') elif self.event.text == "крестик": IgnoreUser().add_ignore_user(user_founded_id, self.event.user_id) self.count += 1 user_founded_id, first_name, last_name, age, attachment_list = self.get_founded_user_info() if len(attachment_list) >= 1: self.write_msg_attachment(f'{first_name} {last_name}', attachment_list, 'decision') else: self.write_msg(f'{first_name} {last_name} - {attachment_list}\n') self.write_msg_keyboard('Выберите действие', 'decision') elif self.event.text == "пропуск": SkippedUser().add_skipped_user(user_founded_id, self.event.user_id) self.count += 1 user_founded_id, first_name, last_name, age, attachment_list = self.get_founded_user_info() if len(attachment_list) >= 1: self.write_msg_attachment(f'{first_name} {last_name}', attachment_list, 'decision') else: self.write_msg(f'{first_name} {last_name} - {attachment_list}\n') self.write_msg_keyboard('Выберите действие', 'decision') else: return def use_state(self, state_name): self.states = { "Hello": self.hello_state, "Initial": self.initial_state, "City": self.city_state, "Sex": self.sex_state, "Relation": self.relation_state, "Range": self.range_state, "Decision": self.decision_state, "Like": self.like_state, "Ignore": self.ignore_state } return self.states[state_name] def start(self, ): for event in self.long_poll.listen(): self.event = event if self.event.type != VkEventType.MESSAGE_NEW: continue if not self.event.to_me: continue if self.event.user_id != self.current_user_id: self.current_user_id = self.event.user_id else: pass if orm.looking_for_user_vk(self.event.user_id) is None: objects = orm.add_objects(self.event.user_id, VkUser().get_user_data(self.event.user_id)) else: objects = orm.looking_for_user_vk(self.event.user_id) if self.event.text == '/start': objects[0].state = "Initial" self.session.commit() self.write_msg_keyboard('Выберите действие:', 'greeting') elif self.event.text == '/test': pass else: ans = self.use_state(objects[0].state)(objects) # при нажатии Выход ans возвращает False и выходим из программы if ans or ans is None: continue else: break
class VK: __slots__ = ('vk', 'logger', 'event_queue', 'msg_queue', 'user_cache', 'group_id') def __init__(self, token: str, logger) -> None: self.vk = VkApi(token=token, api_version=API_VERSION) self.logger = logger self.event_queue = collections.deque() self.msg_queue = [] self.user_cache = {} self.group_id = self.method('groups.getById')[0]['id'] self.init_group_settings() def method(self, method: str, args: dict = None) -> dict: return self.vk.method(method, args) def send(self, peer_id: int, message: str, keyboard=None, attach=None, sticker=None, disable_mentions=True) -> None: if 4000 < len(message) < 100000 and (not attach) and (not sticker): for message_part in [ message[j:j + 4000] for j in range(0, len(message), 4000) ]: self.msg_queue.append({ 'peer_id': peer_id, 'message': message_part, 'random_id': get_random_id(), 'disable_mentions': disable_mentions, 'keyboard': keyboard }) else: self.msg_queue.append({ 'peer_id': peer_id, 'message': message, 'random_id': get_random_id(), 'disable_mentions': disable_mentions, 'keyboard': keyboard, 'attachment': attach, 'sticker_id': sticker }) def send_multiple(self, peer_ids: List[int], message: str, keyboard=None, disable_mentions=True) -> None: self.msg_queue.append({ 'peer_ids': peer_ids, 'message': message, 'random_id': get_random_id(), 'disable_mentions': disable_mentions, 'keyboard': keyboard }) def get_user_link(self, target_id: int, name_case: str = 'nom') -> str: if target_id not in self.user_cache and target_id != 0: if target_id < 0: self.user_cache[target_id] = self.method( 'groups.getById', {'group_id': -target_id})[0] else: self.user_cache[target_id] = self.method( 'users.get', { 'user_ids': target_id, 'name_case': name_case })[0] if target_id < 0: return ''.join([ '[id', str(target_id), '|', self.user_cache[target_id]['first_name'], ']' ]) elif target_id == 0: return '@id0' else: self.user_cache[target_id] = self.method('users.get', { 'user_ids': target_id, 'name_case': name_case })[0] return f"[id{target_id}|{self.user_cache[target_id]['first_name']}]" def get_user_links(self, target_ids: List[int]) -> dict: cached = True for i in target_ids: if i not in self.user_cache: cached = False break if not cached: for i in self.method( 'users.get', {'user_ids': ','.join(list(map(str, target_ids)))}): self.user_cache[i['id']] = i return { i: f"[id{i}|{self.user_cache[i]['first_name']}]" for i in target_ids } def get_target_id(self, s: str) -> Optional[int]: r = s.replace('https://', '').replace('vk.com/', '').replace( '@id', '').replace('@', '').replace('[', '').replace(']', '') if '|' in r: r = r.split('|')[0] if not r.isdecimal(): r = self.method('utils.resolveScreenName', {'screen_name': r.replace('-', 'club')}) if not r: return if r['type'] == 'user': r = r['object_id'] elif r['type'] == 'group': r = -r['object_id'] return int(r) def is_chat_member(self, peer_id: int, user_id: int) -> bool: members = self.method('messages.getConversationMembers', {'peer_id': peer_id})['items'] for i in members: if i['member_id'] == user_id: return True def is_chat_admin(self, peer_id: int, user_id: int, check_if_owner: bool = False) -> bool: members = self.method('messages.getConversationMembers', {'peer_id': peer_id})['items'] for i in members: if i['member_id'] == user_id and 'is_admin' in i and i[ 'is_admin'] and ((not check_if_owner) or ('is_owner' in i and i['is_owner'])): return True def get_chat_owner(self, peer_id: int) -> Optional[int]: members = self.method('messages.getConversationMembers', {'peer_id': peer_id})['items'] for i in members: if 'is_owner' in i and i['is_owner']: return i['member_id'] def get_upload(self) -> VkUpload: return VkUpload(self.vk) def init_group_settings(self) -> None: self.method( 'groups.setSettings', { 'group_id': self.group_id, 'messages': 1, 'bots_capabilities': 1, 'bots_start_button': 1, 'bots_add_to_chat': 1, }) self.method( 'groups.setLongPollSettings', { 'group_id': self.group_id, 'enabled': 1, 'api_version': API_VERSION, 'message_new': 1, }) async def messages_sender(self) -> None: while True: queue = self.msg_queue[:25] if queue: self.msg_queue = self.msg_queue[25:] try: vk_execute( self.vk, ''.join(('API.messages.send(' + json.dumps( i, ensure_ascii=False, separators=(',', ':')) + ');') for i in queue)) except Exception as ex: self.logger.warning( 'Произошла ошибка при отправке сообщений', exc_info=ex) await asyncio.sleep(0.05) @threaded def event_handler(self) -> None: convs = self.method('messages.getConversations', { 'count': 200, 'filter': 'unanswered' })['items'] for i in convs: self.event_queue.append(VKMessage(i['last_message'], self)) lp = VkBotLongPoll(self.vk, self.group_id) while True: try: for event in lp.check(): if event.type == VkBotEventType.MESSAGE_NEW: self.event_queue.append( VKMessage(event.raw['object']['message'], self)) else: self.event_queue.append(event) except Exception as ex: self.logger.warning('Произошла ошибка в LongPoll', exc_info=ex) time.sleep(3)
class VkBot: """ Main class :param config: Configuration file path :type config: str :param logger: Logging config file path :type logger: str """ MESSAGES = {} RUNNING = True admins = [] prefix = None events = {} config = None logger = None lang = "rus" time = 0 vk = None lp = None def __init__(self, config, logger): self.__load_configs(config, logger) self.logger = logging.getLogger(self.get_settings("logger", "vkbot")) self.vk = VkApi(token=self.get_settings("access_token"), api_version=self.get_settings("version", 5.120)) self.admins = self.get_settings("admins", "").split(",") self.prefix = self.get_settings("prefix", None) self.lp = VkBotLongPoll(self.vk, self.get_settings("group_id"), int(self.get_settings("lp_wait", 5))) self.register(VkBotEventType.MESSAGE_NEW, self.cmd_event) self.cmd = CommandManager(self) self.tasks = TaskManager(self) th = threading.Thread(target=self.__exit) th.daemon = True th.start() self.logger.info( self.get_messages("start", id=self.get_settings("group_id"))) self.time = utime() def task(self, time, repeating=0): """ Add task with decorator :param time: complete time :param repeating: repeating count """ def tsk(func): tsk = Task(time, repeating) tsk.target = func tsk.name = func.__name__ self.tasks.add_task(tsk) return func return tsk def command(self, name, **kwargs): """ Register command with decorator :param kwargs: Command constructor args """ def cmd(func): cmd = Command(name=name, **kwargs) cmd.target = func self.cmd.register(cmd) return func return cmd def event(self, event): """ Register event with decorator :param event: Event type :type event: str """ def register(func): self.register(event, func) return func return register def cmd_event(self, obj): user = self.get_object(obj.from_id) chat = self.get_chat(obj.peer_id) if self.prefix: if obj.text[:1] == self.prefix[:1]: self.cmd.exec(user, chat, obj, obj.text[1:]) else: self.cmd.exec(user, chat, obj, obj.text) def get_id(self, id): """ :param id: Id|domain|link :returns: available id """ if not isinstance(id, str): return id try: for r in ("@", "*", "[", "]", "id", "club", "https://vk.com/"): id = id.replace(r, "") id = id.split("|") id = id[0] if not id.isnumeric(): type = self.method("messages.getConversationsById", peer_ids=id)["items"][0]["peer"]["type"] if type == "group": id = -self.method("groups.getById", group_ids=id)[0]["id"] elif type == "user": id = self.method("users.get", user_ids=id)[0]["id"] except: pass return id def get_object(self, id): """ :param id: id|domain|link :returns: User|Sender|Chat|Group """ id = self.get_id(id) type = self.method("messages.getConversationsById", peer_ids=id) type = type["items"][0]["peer"]["type"] if type == "chat": return self.get_chat(id) elif type == "user": return self.get_user(id) elif type == "group": return self.get_group(id) return Sender(self, id) def get_group(self, id): return Group(self, self.get_id(id)) def get_chat(self, id): return Chat(self, id) def get_user(self, id): return User(self, self.get_id(id)) def method(self, method, **kwargs): """ Call the api method :param method: str :param kwargs: method params """ try: response = self.vk.method(method, kwargs) except ApiError as e: self.logger.error( self.get_messages("method_error", method=method, message=e)) seld.log_exception() response = [] return response def register(self, event, consumer): """ Register event :param event: str :param consumer: func """ if event not in self.events: self.events[event] = [] self.events[event].append(consumer) def __handle(self, event, obj): if event not in self.events: return for e in self.events[event]: if callable(e): try: e(obj) except: self.logger.error( self.get_messages("event_error", event=event)) self.log_exception() def start(self): while self.RUNNING: try: for event in self.lp.check(): thread = threading.Thread(target=self.__handle, args=(event.type, event.obj)) thread.daemon = True thread.start() except: self.log_exception() else: self.logger.info(self.get_messages("stop_listen")) self.logger.info(self.get_messages("stop", ut=self.uptime())) def log_exception(self): self.logger.debug(format_exc()) def get_messages(self, key, **args): """ :param key: Messages key :type key: str :param args: kwargs :returns: str """ if not self.config: return key else: try: msg = self.config.get("messages", key) except: msg = self.MESSAGES[self.lang].get(key) if msg: return msg.format(**args) else: return key def get_settings(self, key, default=None): """ :param key: Settings key :type key: str :param default: if the key is not found in the config, it will return the default value :type default: mixed :returns: mixed """ if not self.config: return default else: try: res = self.config.get("settings", key) return res except: return default def uptime(self): time = utime() - self.time fmt = self.get_messages("time_format").split(",") months = round(time / 2592000 % 999) weeks = round(time / 604800 % 4) days = round(time / 86400 % 7) hours = round(time / 3600 % 24) minutes = round(round(time / 60) % 60) if months > 0: return "{}{} {}{}".format(months, fmt[0], weeks, fmt[1]) format = "" if days > 0: format += "{}{} ".format(days, fmt[2]) if hours > 0: format += "{}{} ".format(hours, fmt[3]) if minutes > 0: format += "{}{} ".format(minutes, fmt[4]) format += "{}{}".format(round(time % 60), fmt[5]) return format def __exit(self): input() self.stop() def stop(self): self.RUNNING = False def __load_configs(self, config, logger): logging.config.fileConfig(logger) self.config = ConfigParser() self.config.sections() self.config.read(config) self.MESSAGES["rus"] = { "start": "Бот запущен. ID:{id}", "stop": "Бот остановлен. Время работы: {ut}", "time_format": "мес.,нед.,дн.,чс.,мн.,сек.", "stop_listen": "Остановка прослушивания..", "event_error": "Не удалось обработать событие '{event}'", "method_error": "ApiError: не удалось вызвать метод '{method}' - {message}", "task_error": "Не удалось выполнить задачу '{task}'", "no_permission": "У вас недостаточно прав!", "command_not_found": "Комада {cmd} не найдена", "command_error": "При выполнении команды {cmd} произошла ошибка.", "group_not_use": "Эту команду могут использовать только пользователи!" } self.MESSAGES["eng"] = { "start": "Bot started. ID:{id}", "stop": "Bot stopped. Uptime: {ut}", "time_format": "mh.,w.,d.,h.,m.,s.", "stop_listen": "Stop listening..", "event_error": "Failed to execute method '{event}'", "method_error": "ApiError: Failed to call method '{method}' - {message}", "task_error": "failed to complete the task '{task}'", "no_permission": "You do not have sufficient permissions!", "command_not_found": "Command {cmd} not found", "command_error": "An error occurred while executing the {cmd} command.", "group_not_use": "This command can only be used by users!" } if not self.get_settings("access_token"): raise Exception("specify the access token in the config file!") if not self.get_settings("group_id"): raise Exception("specify the group id in the config file!")
def main(): init() global config try: with open('config.json') as f: config = json.load(f) except FileNotFoundError: config = { 'limit': 1000, 'types': { 'chats': True, 'groups': True, 'users': True } } with open('config.json', 'w') as f: json.dump(config, f, indent=2) if config['limit'] <= 0: config['limit'] = 1e10 s = input('Введите "логин:пароль" или токен: ') if len(s) == 85: vk = VkApi(token=s, captcha_handler=captcha_handler) vk.http.headers.update({'User-agent': USER_AGENT}) elif ':' in s: sp = s.split(':') vk = VkApi(sp[0], sp[1], app_id=2685278, captcha_handler=captcha_handler) vk.http.headers.update({'User-agent': USER_AGENT}) try: vk.auth(token_only=True) except AuthError: con(Colors.ERROR + 'Неверный логин или пароль') return else: con(Colors.WARNING + 'Введите данные для входа в виде "логин:пароль" или "токен"') return try: user = vk.method('users.get')[0] except VkApiError as ex: if ex.__dict__['error']['error_code'] == 5: error_text = 'неверный токен' else: error_text = str(ex) con(Colors.ERROR + 'Ошибка входа: ' + error_text) return con(Colors.OK + 'Вход выполнен') infos = [] count = vk.method('messages.getConversations', {'count': 0})['count'] for offset in range((count - 1) // 200 + 1): peers = vk.method('messages.getConversations', { 'count': 200, 'extended': 1, 'offset': offset * 200 }) for peer in peers['items']: peer_id = peer['conversation']['peer']['id'] peer_type = peer['conversation']['peer']['type'] if peer_type == 'group' and config['types']['groups']: info = [i for i in peers['groups'] if i['id'] == -peer_id][0] name = info[ 'screen_name'] if 'screen_name' in info else 'club' + str( info['id']) infos.append((peer_id, name, info['name'])) elif peer_type == 'user' and config['types']['users']: info = [i for i in peers['profiles'] if i['id'] == peer_id][0] name = info[ 'screen_name'] if 'screen_name' in info else 'id' + str( info['id']) infos.append((peer_id, name, info['first_name'] + ' ' + info['last_name'])) elif peer_type == 'chat' and config['types']['chats']: infos.append((peer_id, '', peer['conversation']['chat_settings']['title'])) base_dir = 'messages_' + str(user['id']) + '/' if not os.path.exists(base_dir): os.makedirs(base_dir) copy('files/favicon.ico', base_dir) copy('files/style.css', base_dir) name = user['first_name'] + ' ' + user['last_name'] with open('files/index_pre.html', encoding='utf-8') as f: index_file = f.read().replace('\n', '').format(user['id'], name) for i in infos: if i[1]: index_file += '<div class="item"><div class="item__main"><a href="messages/{0}.html">{1}</a></div><div class="item__tertiary">@{2}</div></div>'.format( i[0], i[2], i[1]) else: index_file += '<div class="item"><a href="messages/{0}.html">{1}</a></div>'.format( i[0], i[2]) with open('files/index_post.html', encoding='utf-8') as f: index_file += f.read().replace('\n', '') with open(base_dir + 'index.html', 'w', encoding='utf-8') as f: f.write(index_file) messages_dir = base_dir + 'messages/' if not os.path.exists(messages_dir): os.makedirs(messages_dir) total = ' \\ ' + str(len(infos)) for num in range(len(infos)): info = infos[num] msgs = [] msg_count = vk.method('messages.getHistory', { 'peer_id': info[0], 'count': 0 })['count'] con(Colors.INFO + 'Сохранение диалога ' + str(num + 1) + total) for offset in range( min(((msg_count - 1) // 200 + 1), config['limit'] // 200)): try: chunk = vk.method( 'messages.getHistory', { 'peer_id': info[0], 'count': 200, 'extended': 1, 'offset': offset * 200 }) for msg in chunk['items']: if msg['from_id'] < 0: item = [ i for i in chunk['groups'] if i['id'] == -msg['from_id'] ][0] sender = 'club' + str(-msg['from_id']) sender_name = item['name'] else: item = [ i for i in chunk['profiles'] if i['id'] == msg['from_id'] ][0] sender = 'id' + str(msg['from_id']) sender_name = item['first_name'] + ' ' + item[ 'last_name'] text = 'Служебное сообщение ' + msg['action'][ 'type'] if 'action' in msg else msg['text'] a = [] for i in msg['attachments']: link = '' if i['type'] == 'photo': photo = '' current = 0 sizes = i['photo']['sizes'] for size in sizes: if size['type'] == 'w': photo = size['url'] break elif size['type'] == 's' and current < 1: current = 1 photo = size['url'] elif size['type'] == 'm' and current < 2: current = 2 photo = size['url'] elif size['type'] == 'x' and current < 3: current = 3 photo = size['url'] elif size['type'] == 'y' and current < 4: current = 4 photo = size['url'] elif size['type'] == 'z' and current < 5: current = 5 photo = size['url'] desc = 'Фотография' link = photo elif i['type'] == 'video': desc = 'Видеозапись' link = 'https://vk.com/video' + str( i['video']['owner_id']) + '_' + str( i['video']['id']) elif i['type'] == 'audio': desc = 'Аудиозапись ' + i['audio']['title'] elif i['type'] == 'doc': desc = 'Документ' link = i['doc']['url'] elif i['type'] == 'link': desc = 'Ссылка' link = i['link']['url'] elif i['type'] == 'market': desc = 'Товар' link = 'https://vk.com/market' + str( i['market']['owner_id']) + '_' + str( i['market']['id']) elif i['type'] == 'wall': desc = 'Запись на стене' link = 'https://vk.com/wall' + str( i['wall']['to_id']) + '_' + str( i['wall']['id']) elif i['type'] == 'wall_reply': if 'deleted' in i['wall_reply']: desc = 'Комментарий на стене (удалён)' else: desc = 'Комментарий на стене' link = 'https://vk.com/wall' + str( i['wall_reply']['owner_id']) + '_' + str( i['wall_reply']['post_id'] ) + '?reply=' + str(i['wall_reply']['id']) elif i['type'] == 'sticker': desc = 'Стикер ID ' + str( i['sticker']['sticker_id']) elif i['type'] == 'gift': desc = 'Подарок ID ' + str(i['gift']['id']) elif i['type'] == 'audio_message': desc = 'Аудиосообщение' link = i['audio_message']['link_mp3'] elif i['type'] == 'poll': desc = 'Опрос' link = 'https://vk.com/poll' + str( i['poll']['owner_id']) + '_' + str( i['poll']['id']) else: desc = '' attach = '<div class="attachment__description">' + desc + '</div>' if link: attach += '<a class="attachment__link" href="' + link + '" target="_blank">' + link + '</a>' a.append(attach) msgs.append((sender, msg['date'], sender_name, text, a)) except KeyError: con(Colors.WARNING + 'Ошибка при сохранении диалога ' + str(info[0])) with open('files/messages_pre.html', encoding='utf-8') as f: file = f.read().replace('\n', '').format(user['id'], name, info[2]) for msg in msgs: link = '<a href="https://vk.com/' + str( msg[0]) + '" target="_blank">' + msg[2] + '</a>, ' tm = time.strftime('%d.%m.%Y %H:%M:%S', time.gmtime(msg[1] + TZ)) attach = '<div class="kludges">' + '\n'.join( msg[4]) + '</div>' if msg[4] else '' file += '<div class="item"><div class="item__main"><div class="message"><div class="message__header">{0}{2}</div><div>{1}</div></div></div></div>'.format( link + tm, msg[3], attach) with open('files/index_post.html', encoding='utf-8') as f: file += f.read().replace('\n', '') with open(messages_dir + str(info[0]) + '.html', 'w', encoding='utf-8') as f: f.write(file) con(Colors.OK + 'Готово!')
class SearchHandler(BaseHandler): def __init__(self, user_id, vk_group_client, db_session): self.questions = [] self.search_params = {} self.vk_user_client = None self.db_session = db_session super().__init__(user_id, vk_group_client) def reset(self): self.search_params = {} self.questions = [ AgeFromQuestion(self.user_id, self.vk_group_client), AgeToQuestion(self.user_id, self.vk_group_client), HometownQuestion(self.user_id, self.vk_group_client), SexQuestion(self.user_id, self.vk_group_client), StatusQuestion(self.user_id, self.vk_group_client), TokenQuestion(self.user_id, self.vk_group_client, self.db_session), ] def keywords(self): return ['Старт', 'Start'] def is_active(self): for question in self.questions: if question.should_handle_answer(): return True return False def handle_impl(self, message): if self.should_handle(message): self.reset() question = self.questions[0] if question.should_handle_answer(): if not question.handle_answer(message, self.search_params): question.ask() else: self.questions.pop(0) while len(self.questions) > 0 and not self.is_active(): question = self.questions[0] if question.should_ask(): question.ask() else: self.questions.pop(0) if len(self.questions) == 0: self.find_match() def find_match(self): user = self.db_session.query(User).filter(User.id == self.user_id).first() self.vk_user_client = VkApi(token=user.token) candidates = self.search() if len(candidates) == 0: self.write_msg('Никого не найдено') return for candidate in candidates: top_photos = self.get_popular_profile_photos(candidate['id']) candidate['top_photos'] = top_photos result = f"{candidate['first_name']} {candidate['last_name']}\n" result += f"https://vk.com/{candidate['screen_name']}\n" candidate_exists = self.db_session.query(Candidate).filter(Candidate.id == candidate['id']).first() if not candidate_exists: c = Candidate( id=candidate['id'], first_name=candidate['first_name'], last_name=candidate['last_name'], screen_name=candidate['screen_name'], ) self.db_session.add(c) user.candidates.append(c) else: user.candidates.append(candidate_exists) self.write_msg(result) attachments = [] for photo in top_photos: owner_photo_id = f"photo{photo['owner_id']}_{photo['id']}" attachments.append(owner_photo_id) photo_exists = self.db_session.query(Photo).filter(Photo.id == owner_photo_id).first() if not photo_exists: self.db_session.add( Photo( id=owner_photo_id, photo_id=photo['id'], candidate_id=photo['owner_id'], likes_count=photo['likes']['count'], comments_count=photo['comments']['count'], ) ) self.send_attachment(','.join(attachments)) self.db_session.commit() def send_attachment(self, attachment): self.vk_group_client.method('messages.send', {'user_id': self.user_id, 'attachment': attachment, 'random_id': randrange(10 ** 7)}) def get_popular_profile_photos(self, owner_id): response = self.vk_user_client.method('photos.get', {'owner_id': owner_id, 'album_id': 'profile', 'extended': 1, 'count': 1000}) items = response['items'] def sum_likes_and_comments_count(item): return item['likes']['count'] + item['comments']['count'] items.sort(key=sum_likes_and_comments_count) most_liked_photos = items[-3:] return most_liked_photos def search(self): params = {'has_photo': 1, 'count': 10, 'fields': 'screen_name'} response = self.vk_user_client.method('users.search', {**self.search_params, **params}) def already_matched(user_id, candidate_id): user = self.db_session.query(User).filter(User.id == user_id, User.candidates.any(id=candidate_id)).first() return user is not None items = [item for item in response['items'] if not item['is_closed'] and not already_matched(self.user_id, item['id'])] return items