async def screenshot(_, message: Message): await asyncio.gather( message.delete(), UserBot.send( functions.messages.SendScreenshotNotification( peer=await UserBot.resolve_peer(message.chat.id), reply_to_msg_id=0, random_id=UserBot.rnd_id(), ) ) )
async def restart(bot: UserBot, message: Message): await message.edit(f"Restarting {UserBot.__class__.__name__}.") await bot.send_message( "me", f"#userbot_restart, {message.chat.id}, {message.message_id}") if "p" in message.text and "g" in message.text: asyncio.get_event_loop().create_task( UserBot.restart(git_update=True, pip=True)) elif "p" in message.text: asyncio.get_event_loop().create_task(UserBot.restart(pip=True)) elif "g" in message.text: asyncio.get_event_loop().create_task(UserBot.restart(git_update=True)) else: asyncio.get_event_loop().create_task(UserBot.restart())
async def restart(bot: UserBot, message: Message): await message.edit(f"Restarting {UserBot.__name__}.") await bot.send_message( 'me', f'#userbot_restart, {message.chat.id}, {message.message_id}') if 'p' in message.text and 'g' in message.text: asyncio.get_event_loop().create_task( bot.restart(git_update=True, pip=True)) elif 'p' in message.text: asyncio.get_event_loop().create_task(bot.restart(pip=True)) elif 'g' in message.text: asyncio.get_event_loop().create_task(bot.restart(git_update=True)) else: asyncio.get_event_loop().create_task(bot.restart())
def __init__(self, token, group_id, debug=True): Vk.__init__(self, token=token, group_id=group_id, debug=debug) self.messages_to_delete = {} self.userbot = UserBot() self.debug = True base = BetterBotBase("users", "dat") base.addPattern("karma", 0) base.addPattern("programming_languages", []) base.addPattern("github_profile", "") base.addPattern("supporters", []) base.addPattern("opponents", []) base.addPattern("last_collective_vote", 0) self.base = base
async def unsplash_pictures(bot: UserBot, message: Message): cmd = message.command if len(cmd) > 1 and isinstance(cmd[1], str): keyword = cmd[1] if len(cmd) > 2 and int(cmd[2]) < 10: await message.edit("```Getting Pictures```") count = int(cmd[2]) images = [] while len(images) is not count: img = await AioHttp().get_url( f"https://source.unsplash.com/1600x900/?{keyword}") if img not in images: images.append(img) for img in images: await bot.send_photo(message.chat.id, str(img)) await message.delete() return else: await message.edit("```Getting Picture```") img = await AioHttp().get_url( f"https://source.unsplash.com/1600x900/?{keyword}") await asyncio.gather(message.delete(), bot.send_photo(message.chat.id, str(img)))
async def quotly(_, message: Message): if not message.reply_to_message: await message.edit("Reply to any users text message") return await message.edit("```Making a Quote```") await message.reply_to_message.forward("@QuotLyBot") is_sticker = False progress = 0 while not is_sticker: try: msg = await UserBot.get_history("@QuotLyBot", 1) check = msg[0]["sticker"]["file_id"] is_sticker = True except: await sleep(0.5) progress += random.randint(0, 10) try: await message.edit( "```Making a Quote```\nProcessing {}%".format(progress)) except: await message.edit("ERROR SUUUU") if msg_id := msg[0]['message_id']: await asyncio.gather( message.delete(), UserBot.forward_messages(message.chat.id, "@QuotLyBot", msg_id))
async def paste(_, message: Message): text = message.reply_to_message.text try: async with aiohttp.ClientSession() as session: async with session.post( 'https://nekobin.com/api/documents', json={"content": text}, timeout=3 ) as response: key = (await response.json())["result"]["key"] except Exception: await message.edit_text("`Pasting failed`") await asyncio.sleep(2) await message.delete() return else: url = f'https://nekobin.com/{key}' reply_text = f'Nekofied to **Nekobin** : {url}' delete = True if len(message.command) > 1 \ and message.command[1] in ['d', 'del'] \ and message.reply_to_message.from_user.is_self else False if delete: await asyncio.gather( UserBot.send_message(message.chat.id, reply_text, disable_web_page_preview=True), message.reply_to_message.delete(), message.delete() ) else: await message.edit_text( reply_text, disable_web_page_preview=True, )
async def mark_chat_unread(_, message: Message): await asyncio.gather( message.delete(), UserBot.send( functions.messages.MarkDialogUnread(peer=await UserBot.resolve_peer( message.chat.id), unread=True)))
async def generate_qr(bot: UserBot, message: Message): if qr_text := await UserBot.extract_command_text(message): img = qrcode.make(qr_text) with open('downloads/qr.png', 'wb') as f: img.save(f) await asyncio.gather( bot.send_photo(message.chat.id, 'downloads/qr.png'), message.delete() )
async def give_pats(_, message: Message): URL = "https://some-random-api.ml/animu/pat" async with aiohttp.ClientSession() as session: async with session.get(URL) as request: if request.status == 404: return await message.edit("`no Pats for u :c") result = await request.json() url = result.get("link", None) await asyncio.gather( message.delete(), UserBot.send_video(GetChatID(message), url, reply_to_message_id=ReplyCheck(message)) )
def __init__( self, token: str, group_id: int, debug: bool = True ): """Auth as VK group and register commands. """ Vk.__init__(self, token=token, group_id=group_id, debug=debug) self.messages_to_delete = {} self.userbot = UserBot() self.data = BetterBotBaseDataService() self.commands = Commands(self, self.data) self.commands.register_cmds( (patterns.HELP, self.commands.help_message), (patterns.INFO, self.commands.info_message), (patterns.UPDATE, self.commands.update_command), (patterns.ADD_PROGRAMMING_LANGUAGE, lambda: self.commands.change_programming_language(True)), (patterns.REMOVE_PROGRAMMING_LANGUAGE, lambda: self.commands.change_programming_language(False)), (patterns.ADD_GITHUB_PROFILE, lambda: self.commands.change_github_profile(True)), (patterns.REMOVE_GITHUB_PROFILE, lambda: self.commands.change_github_profile(False)), (patterns.KARMA, self.commands.karma_message), (patterns.TOP, self.commands.top), (patterns.PEOPLE, self.commands.top), (patterns.BOTTOM, lambda: self.commands.top(True)), (patterns.TOP_LANGUAGES, self.commands.top_langs), (patterns.PEOPLE_LANGUAGES, self.commands.top_langs), (patterns.BOTTOM_LANGUAGES, lambda: self.commands.top_langs(True)), (patterns.APPLY_KARMA, self.commands.apply_karma), )
def __new__(cls, configuration): if type(configuration) is not Configuration: raise TypeError("'configuration' must be instance of 'configuration.Configuration'") self = super().__new__(cls) self.__configuration = configuration self.__loop = asyncio.get_event_loop() # todo on new event loop doesn't works userbot configuration self.__userbot = UserBot(configuration, self.__loop) self.__nativebot = NativeBot(configuration, self.__loop) self.__userbot.nativebot = self.__nativebot.client self.__nativebot.userbot = self.__userbot.client self.__both_connected_locker = asyncio.locks.Lock(loop=self.__loop) return self
async def spamhammer(bot: UserBot, message: Message): await message.edit("```Initializing the database```") url = 'https://feed.spamwat.ch/' content = requests.get( url, headers={ "User-Agent": "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:15.0) Gecko/20100101 Firefox/15.0.1" }) spam_ids = [] for x in content.iter_lines(): line: dict = json.loads(x) the_id = line.get('id') if the_id not in spam_ids: spam_ids.append(the_id) await message.edit("Starting to kick spam accounts.") count = 0 async for member in bot.iter_chat_members(message.chat.id): member: ChatMember = member if member.user.id in spam_ids: try: await bot.kick_chat_member(message.chat.id, member.user.id, until_date=0) await message.edit( f"```Kicked {count} spam accounts from here.```") count += 1 except: ban_message = ( f"{member.user.id} could not be banned from Baivaru Requests for some reason." ) await bot.send_message(LOG_GROUP, ban_message) ban_message = ( f"{member.user.id} just got banned from Baivaru Requests.") await bot.send_message(LOG_GROUP, ban_message) print(f"```Kicked {count} spam accounts from here.```")
async def commit_graph(_, message: Message): if len(message.command) < 2: await message.edit( "Please provide a github profile username to generate the graph!" ) await sleep(2) await message.delete() return else: git_user = message.command[1] url = f"https://ghchart.rshah.org/{git_user}" file_name = f"{randint(1, 999)}{git_user}" resp = await AioHttp.get_raw(url) f = await aiofiles.open(f"{file_name}.svg", mode="wb") await f.write(resp) await f.close() try: drawing = svg2rlg(f"{file_name}.svg") renderPM.drawToFile(drawing, f"{file_name}.png") except UnboundLocalError: await message.edit("Username does not exist!") await sleep(2) await message.delete() return await asyncio.gather( UserBot.send_photo( chat_id=message.chat.id, photo=f"{file_name}.png", caption=git_user, reply_to_message_id=ReplyCheck(message), ), message.delete(), ) for file in iglob(f"{file_name}.*"): os.remove(file)
async def word_count(bot: UserBot, message: Message): await message.delete() words = Custom() progress = await bot.send_message(message.chat.id, "`Processed 0 messages...`") total = 0 async for msg in bot.iter_history(message.chat.id, 1000): total += 1 if total % 100 == 0: await progress.edit_text(f"`Processed {total} messages...`") time.sleep(0.5) if msg.text: for word in msg.text.split(): words[word.lower()] += 1 if msg.caption: for word in msg.caption.split(): words[word.lower()] += 1 freq = sorted(words, key=words.get, reverse=True) out = "Word Counter\n" for i in range(25): out += f"{i + 1}. **{words[freq[i]]}**: {freq[i]}\n" await progress.edit_text(out)
async def quotly(bot: UserBot, message: Message): if not message.reply_to_message: await message.edit("Reply to any users text message") return await message.edit("```Making a Quote```") await message.reply_to_message.forward("@QuotLyBot") is_sticker = False progress = 0 while not is_sticker: try: await sleep(4) msg = await bot.get_history("@QuotLyBot", 1) print(msg) is_sticker = True except: await sleep(1) progress += random.randint(0, 5) if progress > 100: await message.edit('There was a long running error') return try: await message.edit( "```Making a Quote\nProcessing {}%```".format(progress)) except: await message.edit("ERROR") if msg_id := msg[0]['message_id']: await asyncio.gather( message.delete(), bot.forward_messages(message.chat.id, "@QuotLyBot", msg_id))
class V(Vk): def __init__(self, token, group_id, debug=True): Vk.__init__(self, token=token, group_id=group_id, debug=debug) self.messages_to_delete = {} self.userbot = UserBot() self.debug = True base = BetterBotBase("users", "dat") base.addPattern("karma", 0) base.addPattern("programming_languages", []) base.addPattern("github_profile", "") base.addPattern("supporters", []) base.addPattern("opponents", []) base.addPattern("last_collective_vote", 0) self.base = base def message_new(self, event): """ Handling all new messages. """ event = event["object"]["message"] if event['peer_id'] in self.messages_to_delete: peer = CHAT_ID_OFFSET + config.userbot_chats[event['peer_id']] new_messages_to_delete = [] ids = [] for item in self.messages_to_delete[event['peer_id']]: if item['date'] > datetime.now(): new_messages_to_delete.append(item) else: ids.append(item['id']) if new_messages_to_delete: self.messages_to_delete[event['peer_id']] = new_messages_to_delete else: self.messages_to_delete.pop(event['peer_id']) if ids: self.userbot.delete_messages(ids, peer) user = self.base.autoInstall(event["from_id"], self) if event["from_id"] > 0 else None message = event["text"].lstrip("/") messages = self.get_messages(event) selected_message = messages[0] if len(messages) == 1 else None selected_user = self.base.autoInstall(selected_message["from_id"], self) if selected_message else None is_bot_selected = selected_message and (selected_message["from_id"] < 0) karma_enabled = event["peer_id"] in config.chats_karma_whitelist group_chat = event["peer_id"] >= CHAT_ID_OFFSET if group_chat: if karma_enabled: match = regex.match(patterns.KARMA, message) if match: return self.send_karma(event, selected_user if selected_user else user, not selected_user) match = regex.match(patterns.TOP, message) if match: maximum_users = match.group("maximum_users") maximum_users = int(maximum_users) if maximum_users else 0 return self.send_top(event, maximum_users) match = regex.match(patterns.BOTTOM, message) if match: maximum_users = match.group("maximum_users") maximum_users = int(maximum_users) if maximum_users else 0 return self.send_bottom(event, maximum_users) match = regex.match(patterns.APPLY_KARMA, message) if match: # Only regular users can be selected if is_bot_selected: return if not selected_user: selected_user_id = match.group("selectedUserId") if selected_user_id: selected_user = self.base.autoInstall(int(selected_user_id), self) if selected_user and (user.uid != selected_user.uid): operator = match.group("operator")[0] amount = match.group("amount") amount = int(amount) if amount else 0 utcnow = datetime.utcnow() # Downvotes disabled for users with negative karma if (operator == "-") and (user.karma < 0): self.delete_message(event) self.send_not_enough_karma_error(event, user) return # Collective votes limit if amount == 0: utclast = datetime.fromtimestamp(float(user.last_collective_vote)); difference = utcnow - utclast hours_difference = difference.total_seconds() / 3600; hours_limit = self.get_karma_hours_limit(user.karma); if hours_difference < hours_limit: self.delete_message(event) self.send_not_enough_hours_error(event, user, hours_limit, difference.total_seconds() / 60) return user_karma_change, selected_user_karma_change, collective_vote_applied, voters = self.apply_karma_change(event, user, selected_user, operator, amount) if collective_vote_applied: user.last_collective_vote = int(utcnow.timestamp()) self.base.save(user) self.base.save(selected_user) if user_karma_change: self.base.save(user) self.send_karma_change(event, user_karma_change, selected_user_karma_change, voters) self.delete_message(event) return match = regex.match(patterns.TOP_LANGUAGES, message) if match: languages = match.group("languages") return self.send_top_languages(event, languages) else: match = regex.match(patterns.PEOPLE, message) if match: maximum_users = match.group("maximum_users") maximum_users = int(maximum_users) if maximum_users else 0 return self.send_people(event, maximum_users) match = regex.match(patterns.PEOPLE_LANGUAGES, message) if match: languages = match.group("languages") return self.send_people_languages(event, languages) match = regex.match(patterns.HELP, message) if match: return self.send_help(event, group_chat, karma_enabled) match = regex.match(patterns.INFO, message) if match: return self.send_info(event, karma_enabled, selected_user if selected_user else user, not selected_user) match = regex.match(patterns.ADD_PROGRAMMING_LANGUAGE, message) if match: language = match.group('language') language = self.get_default_programming_language(language) if not language: return if language not in user.programming_languages: user.programming_languages.append(language) self.base.save(user) return self.send_programming_languages_list(event, user) match = regex.match(patterns.REMOVE_PROGRAMMING_LANGUAGE, message) if match: language = match.group('language') language = self.get_default_programming_language(language) if not language: return if language in user.programming_languages: user.programming_languages.remove(language) self.base.save(user) return self.send_programming_languages_list(event, user) match = regex.match(patterns.ADD_GITHUB_PROFILE, message) if match: profile = match.group('profile') if not profile: return if profile != user.github_profile: if requests.get(f'https://github.com/{profile}').status_code == 200: user.github_profile = profile self.base.save(user) return self.send_github_profile(event, user) match = regex.match(patterns.REMOVE_GITHUB_PROFILE, message) if match: profile = match.group('profile') if not profile: return if profile == user.github_profile: user.github_profile = "" self.base.save(user) return self.send_github_profile(event, user) def delete_message(self, event, delay=2): peer_id = event['peer_id'] if peer_id in config.userbot_chats and peer_id in config.chats_deleting: if peer_id not in self.messages_to_delete: self.messages_to_delete.update({peer_id: []}) message_id = event['conversation_message_id'] data = {'date': datetime.now() + timedelta(seconds=delay), 'id': message_id} self.messages_to_delete[peer_id].append(data) def get_karma_hours_limit(self, karma): for limit_item in config.karma_limit_hours: if (not limit_item["min_karma"]) or (karma >= limit_item["min_karma"]): if (not limit_item["max_karma"]) or (karma < limit_item["max_karma"]): return limit_item["limit"] return 168 # hours (a week) def apply_karma_change(self, event, user, selected_user, operator, amount): selected_user_karma_change = None user_karma_change = None collective_vote_applied = None voters = None # Personal karma transfer if amount > 0: if user.karma < amount: self.send_not_enough_karma_error(event, user) return user_karma_change, selected_user_karma_change, collective_vote_applied, voters else: user_karma_change = self.apply_user_karma(user, -amount) amount = -amount if operator == "-" else amount selected_user_karma_change = self.apply_user_karma(selected_user, amount) # Collective vote elif amount == 0: if operator == "+": selected_user_karma_change, voters, collective_vote_applied = self.apply_collective_vote(user, selected_user, "supporters", config.positive_votes_per_karma, +1) else: selected_user_karma_change, voters, collective_vote_applied = self.apply_collective_vote(user, selected_user, "opponents", config.negative_votes_per_karma, -1) return user_karma_change, selected_user_karma_change, collective_vote_applied, voters def apply_collective_vote(self, user, selected_user, current_voters, number_of_voters, amount): vote_applied = None if user.uid not in selected_user[current_voters]: selected_user[current_voters].append(user.uid) vote_applied = True if len(selected_user[current_voters]) >= number_of_voters: voters = selected_user[current_voters] selected_user[current_voters] = [] return self.apply_user_karma(selected_user, amount), voters, vote_applied return None, None, vote_applied def apply_user_karma(self, user, amount): user.karma += amount return (user.uid, user.name, user.karma - amount, user.karma) def get_messages(self, event): reply_message = event.get("reply_message", {}) return [reply_message] if reply_message else event.get("fwd_messages", []) def get_programming_languages_string_with_parentheses_or_empty(self, user): programming_languages_string = self.get_programming_languages_string(user) if programming_languages_string == "": return programming_languages_string else: return "(" + programming_languages_string + ")" def get_github_profile(self, user): if isinstance(user, dict): return user["github_profile"] if "github_profile" in user else "" else: return user.github_profile def get_github_profile_top_string(self, user): profile = self.get_github_profile(user) if profile: profile = f" — github.com/{profile}" return profile def get_programming_languages_string(self, user): if isinstance(user, dict): languages = user["programming_languages"] if "programming_languages" in user else [] else: languages = user.programming_languages if len(languages) > 0: languages.sort() return ", ".join(languages) else: return "" def get_default_programming_language(self, language): for default_programming_language in config.default_programming_languages: default_programming_language = default_programming_language.replace('\\', '') if default_programming_language.lower() == language.lower(): return default_programming_language return None def contains_string(self, strings, matchedString, ignoreCase): if ignoreCase: for string in strings: if string.lower() == matchedString.lower(): return True else: for string in strings: if string == matchedString: return True return False def contains_all_strings(self, strings, matchedStrings, ignoreCase): matched_strings_count = len(matchedStrings) for string in strings: if self.contains_string(matchedStrings, string, ignoreCase): matched_strings_count -= 1 if matched_strings_count == 0: return True return False def send_karma_change(self, event, user_karma_change, selected_user_karma_change, voters): if selected_user_karma_change and user_karma_change: self.send_message(event, "Карма изменена: [id%s|%s] [%s]->[%s], [id%s|%s] [%s]->[%s]." % (user_karma_change + selected_user_karma_change)) elif selected_user_karma_change: self.send_message(event, "Карма изменена: [id%s|%s] [%s]->[%s]. Голосовали: (%s)" % (selected_user_karma_change + (", ".join([f"@id{voter}" for voter in voters]),))) def send_karma(self, event, user, is_self=True): if is_self: response = "[id%s|%s], Ваша карма — %s." else: response = "Карма [id%s|%s] — %s." self.send_message(event, response % (user.uid, user.name, self.get_karma_string(user))) def send_info(self, event, karma_enabled, user, is_self=True): programming_languages_string = self.get_programming_languages_string(user) if not programming_languages_string: programming_languages_string = "отсутствуют" profile = self.get_github_profile(user) if not profile: profile = "отсутствует" else: profile = f"github.com/{profile}" if karma_enabled: if is_self: response = "[id%s|%s], Ваша карма — %s.\nВаши языки программирования: %s\nВаша страничка на GitHub — %s" else: response = "Карма [id%s|%s] — %s.\nЯзыки программирования: %s\nCтраничка на GitHub — %s" return self.send_message(event, response % (user.uid, user.name, self.get_karma_string(user), programming_languages_string, profile)) else: if is_self: response = "[id%s|%s], \nВаши языки программирования: %s\nВаша страничка на GitHub — %s" else: response = "[id%s|%s]. \nЯзыки программирования: %s\nCтраничка на GitHub — %s" return self.send_message(event, response % (user.uid, user.name, programming_languages_string, profile)) def get_karma_string(self, user): plus_string = "" minus_string = "" if isinstance(user, dict): karma = user["karma"] plus_votes = len(user["supporters"]) minus_votes = len(user["opponents"]) else: karma = user.karma plus_votes = len(user.supporters) minus_votes = len(user.opponents) if plus_votes > 0: plus_string = "+%.1f" % (plus_votes / config.positive_votes_per_karma) if minus_votes > 0: minus_string = "-%.1f" % (minus_votes / config.negative_votes_per_karma) if plus_votes > 0 or minus_votes > 0: return f"[{karma}][{plus_string}{minus_string}]" else: return f"[{karma}]" def send_top_users(self, event, users): if not users: return user_strings = ["%s [id%s|%s]%s %s" % (self.get_karma_string(user), user["uid"], user["name"], self.get_github_profile_top_string(user), self.get_programming_languages_string_with_parentheses_or_empty(user)) for user in users] total_symbols = 0 i = 0 for user_string in user_strings: user_string_length = len(user_string) if (total_symbols + user_string_length + 2) >= 4096: # Maximum message size for VK API (messages.send) user_strings = user_strings[:i] else: total_symbols += user_string_length + 2 i += 1 response = "\n".join(user_strings) self.send_message(event, response) def get_users_sorted_by_karma(self, peer_id): members = self.get_members_ids(peer_id); users = self.base.getSortedByKeys("karma", otherKeys=["programming_languages", "supporters", "opponents", "github_profile", "uid"]) if members: users = [u for u in users if u["uid"] in members] return users def get_users_sorted_by_name(self, peer_id): members = self.get_members_ids(peer_id); users = self.base.getSortedByKeys("name", otherKeys=["programming_languages", "github_profile", "uid"]) if members: users = [u for u in users if u["uid"] in members] users.reverse() return users def send_bottom(self, event, maximum_users): peer_id = event["peer_id"] users = self.get_users_sorted_by_karma(peer_id) users = [i for i in users if (i["karma"] != 0) or ("programming_languages" in i and len(i["programming_languages"]) > 0)] if (maximum_users > 0) and (len(users) >= maximum_users): users.reverse() self.send_top_users(event, users[:maximum_users]) else: self.send_top_users(event, reversed(users)) def send_people_users(self, event, users): if not users: return user_strings = ["[id%s|%s]%s %s" % (user["uid"], user["name"], self.get_github_profile_top_string(user), self.get_programming_languages_string_with_parentheses_or_empty(user)) for user in users] total_symbols = 0 i = 0 for user_string in user_strings: user_string_length = len(user_string) if (total_symbols + user_string_length + 2) >= 4096: # Maximum message size for VK API (messages.send) user_strings = user_strings[:i] else: total_symbols += user_string_length + 2 i += 1 response = "\n".join(user_strings) self.send_message(event, response) def send_people(self, event, maximum_users): peer_id = event["peer_id"] users = self.get_users_sorted_by_name(peer_id) users = [i for i in users if i["github_profile"] or ("programming_languages" in i and len(i["programming_languages"]) > 0)] if (maximum_users > 0) and (len(users) >= maximum_users): self.send_people_users(event, users[:maximum_users]) else: self.send_people_users(event, users) def send_top(self, event, maximum_users): peer_id = event["peer_id"] users = self.get_users_sorted_by_karma(peer_id) users = [i for i in users if (i["karma"] != 0) or ("programming_languages" in i and len(i["programming_languages"]) > 0)] if (maximum_users > 0) and (len(users) >= maximum_users): self.send_top_users(event, users[:maximum_users]) else: self.send_top_users(event, users) def send_people_languages(self, event, languages): languages = regex.split(r"\s+", languages) peer_id = event["peer_id"] users = self.get_users_sorted_by_name(peer_id) users = [i for i in users if ("programming_languages" in i and len(i["programming_languages"]) > 0) and self.contains_all_strings(i["programming_languages"], languages, True)] self.send_people_users(event, users) def send_top_languages(self, event, languages): languages = regex.split(r"\s+", languages) peer_id = event["peer_id"] users = self.get_users_sorted_by_karma(peer_id) users = [i for i in users if ("programming_languages" in i and len(i["programming_languages"]) > 0) and self.contains_all_strings(i["programming_languages"], languages, True)] self.send_top_users(event, users) def send_github_profile(self, event, user): profile = self.get_github_profile(user) if not profile: self.send_message(event, f"[id{user.uid}|{user.name}], у Вас не указана страничка на GitHub.") else: self.send_message(event, f"[id{user.uid}|{user.name}], Ваша страничка на GitHub — github.com/{profile}.") def send_programming_languages_list(self, event, user): programming_languages_string = self.get_programming_languages_string(user) if not programming_languages_string: self.send_message(event, f"[id{user.uid}|{user.name}], у Вас не указано языков программирования.") else: self.send_message(event, f"[id{user.uid}|{user.name}], Ваши языки программирования: {programming_languages_string}.") def send_help(self, event, group_chat, karma_enabled): if group_chat: if karma_enabled: self.send_message(event, config.help_string_with_karma) else: self.send_message(event, config.help_string) else: self.send_message(event, config.help_string_private_chat) def send_not_in_whitelist(self, event, user): peer_id = event["peer_id"] message = f"Извините, [id{user.uid}|{user.name}], но Ваша беседа [{peer_id}] отсутствует в белом списке для начисления кармы." self.send_message(event, message) def send_not_enough_karma_error(self, event, user): message = f"Извините, [id{user.uid}|{user.name}], но Вашей кармы [{user.karma}] недостаточно :(" self.send_message(event, message) def send_not_enough_hours_error(self, event, user, hours_limit, difference_minutes): message = f"Извините, [id{user.uid}|{user.name}], но с момента вашего последнего голоса ещё не прошло {hours_limit} ч. :( До следующего голоса осталось {int(hours_limit * 60 - difference_minutes)} м." self.send_message(event, message) def get_members(self, peer_id): return self.messages.getConversationMembers(peer_id=peer_id) def get_members_ids(self, peer_id): members = self.get_members(peer_id) if "error" in members: return None else: return [m["member_id"] for m in members["response"]["items"] if m["member_id"] > 0] def send_message(self, event, message): self.messages.send(message=message, peer_id=event["peer_id"], disable_mentions=1, random_id=0)
class Bot(Vk): """Provides working with VK API as group. """ def __init__( self, token: str, group_id: int, debug: bool = True ): """Auth as VK group and register commands. """ Vk.__init__(self, token=token, group_id=group_id, debug=debug) self.messages_to_delete = {} self.userbot = UserBot() self.data = BetterBotBaseDataService() self.commands = Commands(self, self.data) self.commands.register_cmds( (patterns.HELP, self.commands.help_message), (patterns.INFO, self.commands.info_message), (patterns.UPDATE, self.commands.update_command), (patterns.ADD_PROGRAMMING_LANGUAGE, lambda: self.commands.change_programming_language(True)), (patterns.REMOVE_PROGRAMMING_LANGUAGE, lambda: self.commands.change_programming_language(False)), (patterns.ADD_GITHUB_PROFILE, lambda: self.commands.change_github_profile(True)), (patterns.REMOVE_GITHUB_PROFILE, lambda: self.commands.change_github_profile(False)), (patterns.KARMA, self.commands.karma_message), (patterns.TOP, self.commands.top), (patterns.PEOPLE, self.commands.top), (patterns.BOTTOM, lambda: self.commands.top(True)), (patterns.TOP_LANGUAGES, self.commands.top_langs), (patterns.PEOPLE_LANGUAGES, self.commands.top_langs), (patterns.BOTTOM_LANGUAGES, lambda: self.commands.top_langs(True)), (patterns.APPLY_KARMA, self.commands.apply_karma), ) def message_new( self, event: Dict[str, Any] ) -> NoReturn: """Handling all new messages. """ event = event["object"]["message"] msg = event["text"].lstrip("/") peer_id = event["peer_id"] from_id = event["from_id"] msg_id = event["conversation_message_id"] if peer_id in self.messages_to_delete: peer = CHAT_ID_OFFSET + config.USERBOT_CHATS[peer_id] new_messages_to_delete = [] ids = [] for item in self.messages_to_delete[peer_id]: if item['date'] > datetime.now(): new_messages_to_delete.append(item) else: ids.append(item['id']) if new_messages_to_delete: self.messages_to_delete[peer_id] = new_messages_to_delete else: self.messages_to_delete.pop(peer_id) if ids: self.userbot.delete_messages(ids, peer) user = self.data.get_user(from_id, self) if from_id > 0 else None messages = self.get_messages(event) selected_message = messages[0] if len(messages) == 1 else None selected_user = ( self.data.get_user(selected_message["from_id"], self) if selected_message else None) self.commands.process( msg, peer_id, from_id, messages, msg_id, user, selected_user) def delete_message( self, peer_id: int, msg_id: int, delay: int = 2 ) -> NoReturn: """Assigns messages to deleting. """ if peer_id in config.USERBOT_CHATS and peer_id in config.CHATS_DELETING: if peer_id not in self.messages_to_delete: self.messages_to_delete.update({peer_id: []}) data = { 'date': datetime.now() + timedelta(seconds=delay), 'id': msg_id } self.messages_to_delete[peer_id].append(data) def get_members( self, peer_id: int ) -> Dict[str, Any]: """Returns all conversation members. """ return self.messages.getConversationMembers(peer_id=peer_id) def get_members_ids( self, peer_id: int ) -> List[int]: """Returns all conversation member's IDs """ members = self.get_members(peer_id) if "error" in members: return None return [m["member_id"] for m in members["response"]["items"] if m["member_id"] > 0] def send_msg( self, msg: str, peer_id: int ) -> NoReturn: """Sends message to chat with {peer_id}. :param msg: message text :param peer_id: chat ID """ self.messages.send( message=msg, peer_id=peer_id, disable_mentions=1, random_id=0 ) def get_user_name( self, uid: int, name_case: str = "nom" ) -> str: """Returns user firstname. :param uid: user ID :param name_case: The declension case for the user's first and last name. Possible values: • Nominative – nom, • Genitive – gen, • dative – dat, • accusative – acc, • instrumental – ins, • prepositional – abl. """ return self.users.get(user_ids=uid, name_case=name_case)['response'][0]["first_name"] @staticmethod def get_messages( event: Dict[str, Any] ) -> List[Dict[str, Any]]: """Returns forward messages or reply message if available. """ reply_message = event.get("reply_message", {}) return [reply_message] if reply_message else event.get("fwd_messages", [])
class V(Vk): def __init__(self): Vk.__init__(self, token=BotToken, group_id=bot_group_id, debug=True) self.messages_to_delete = {} self.userbot = UserBot() self.debug = True def message_new(self, event): """ Handling all new messages. """ event = event["object"]["message"] if event['peer_id'] in self.messages_to_delete: peer = 2000000000 + userbot_chats[event['peer_id']] new_messages_to_delete = [] ids = [] for item in self.messages_to_delete[event['peer_id']]: if item['date'] > datetime.now(): new_messages_to_delete.append(item) else: ids.append(item['id']) if new_messages_to_delete: self.messages_to_delete[ event['peer_id']] = new_messages_to_delete else: self.messages_to_delete.pop(event['peer_id']) if ids: self.userbot.delete_messages(ids, peer) user = base.autoInstall(event["from_id"], self) if event["from_id"] > 0 else None message = event["text"].lstrip("/") messages = self.get_messages(event) selected_message = messages[0] if len(messages) == 1 else None selected_user = base.autoInstall(selected_message["from_id"], self) if selected_message else None is_bot_selected = selected_message and (selected_message["from_id"] < 0) if regex.findall(patterns.HELP, message): self.send_help(event) elif regex.findall(patterns.KARMA, message): self.send_karma(event, selected_user if selected_user else user, not selected_user) elif regex.findall(patterns.TOP, message): self.send_top(event) elif regex.findall(patterns.BOTTOM, message): self.send_bottom(event) elif regex.findall(patterns.INFO, message): self.send_info(event, selected_user if selected_user else user, not selected_user) elif regex.findall(patterns.APPLY_KARMA, message): # Only for chat rooms if event["peer_id"] < 2000000000: return # Only for whitelisted chat rooms if event["peer_id"] not in chats_whitelist: self.send_not_in_whitelist(event, user) return # Only regular users can be selected if is_bot_selected: return if selected_user and (user.uid != selected_user.uid): match = regex.match(patterns.APPLY_KARMA, message) operator = match.group("operator")[0] amount = match.group("amount") # Downvotes disabled for users with negative rating if (operator == "-") and (user.rating < 0): self.send_not_enough_karma_error(event, user) return user_karma_change, selected_user_karma_change, voters = self.apply_karma_change( event, user, selected_user, operator, amount) base.save(selected_user) if user_karma_change: base.save(user) self.send_karma_change(event, user_karma_change, selected_user_karma_change, voters) self.delete_message(event) elif regex.findall(patterns.ADD_PROGRAMMING_LANGUAGE, message): language = regex.match(patterns.ADD_PROGRAMMING_LANGUAGE, message).group('language') language = self.get_default_programming_language(language) if not language: return if "programming_languages" not in user.obj: user.programming_languages = [] base.save(user) if language not in user.programming_languages: user.programming_languages.append(language) base.save(user) self.send_programming_languages_list(event, user) elif regex.findall(patterns.REMOVE_PROGRAMMING_LANGUAGE, message): language = regex.match(patterns.REMOVE_PROGRAMMING_LANGUAGE, message).group('language') language = self.get_default_programming_language(language) if not language: return if "programming_languages" not in user.obj: user.programming_languages = [] base.save(user) if language in user.programming_languages: user.programming_languages.remove(language) base.save(user) self.send_programming_languages_list(event, user) elif regex.findall(patterns.TOP_LANGUAGES, message): match = regex.match(patterns.TOP_LANGUAGES, message) languages = match.group("languages") self.send_top_languages(event, languages) def delete_message(self, event, delay=2): peer_id = event['peer_id'] if peer_id in userbot_chats and peer_id in chats_deleting: if peer_id not in self.messages_to_delete: self.messages_to_delete.update({peer_id: []}) message_id = event['conversation_message_id'] data = { 'date': datetime.now() + timedelta(seconds=delay), 'id': message_id } self.messages_to_delete[peer_id].append(data) def apply_karma_change(self, event, user, selected_user, operator, amount): selected_user_karma_change = None user_karma_change = None voters = None amount = int(amount) if amount else 0 # Personal karma transfer if amount > 0: if user.rating < amount: self.send_not_enough_karma_error(event, user) return user_karma_change, selected_user_karma_change, voters else: user_karma_change = self.apply_user_karma(user, -amount) amount = -amount if operator == "-" else amount selected_user_karma_change = self.apply_user_karma( selected_user, amount) # Collective vote elif amount == 0: if operator == "+": selected_user_karma_change, voters = self.apply_collective_vote( user, selected_user, "current", 2, +1) else: selected_user_karma_change, voters = self.apply_collective_vote( user, selected_user, "current_sub", 3, -1) return user_karma_change, selected_user_karma_change, voters def apply_collective_vote(self, user, selected_user, current_voters, number_of_voters, amount): if user.uid not in selected_user[current_voters]: selected_user[current_voters].append(user.uid) if len(selected_user[current_voters]) >= number_of_voters: voters = selected_user[current_voters] selected_user[current_voters] = [] return self.apply_user_karma(selected_user, amount), voters return None, None def apply_user_karma(self, user, amount): user.rating += amount return (user.uid, user.name, user.rating - amount, user.rating) def get_messages(self, event): reply_message = event.get("reply_message", {}) return [reply_message] if reply_message else event.get( "fwd_messages", []) def get_programming_languages_string_with_parentheses_or_empty(self, user): programming_languages_string = self.get_programming_languages_string( user) if programming_languages_string == "": return programming_languages_string else: return "(" + programming_languages_string + ")" def get_programming_languages_string(self, user): if isinstance(user, dict): languages = user["programming_languages"] if "programming_languages" in user else [] else: languages = user.programming_languages if len(languages) > 0: languages.sort() return ", ".join(languages) else: return "" def get_default_programming_language(self, language): for default_programming_language in default_programming_languages: default_programming_language = default_programming_language.replace( '\\', '') if default_programming_language.lower() == language.lower(): return default_programming_language return None def contains_string(self, strings, matchedString, ignoreCase): if ignoreCase: for string in strings: if string.lower() == matchedString.lower(): return True else: for string in strings: if string == matchedString: return True return False def contains_all_strings(self, strings, matchedStrings, ignoreCase): matchedStringsCount = len(matchedStrings) for string in strings: if self.contains_string(matchedStrings, string, ignoreCase): matchedStringsCount -= 1 if matchedStringsCount == 0: return True return False def send_karma_change(self, event, user_karma_change, selected_user_karma_change, voters): if selected_user_karma_change and user_karma_change: self.send_message( event, "Карма изменена: [id%s|%s] [%s]->[%s], [id%s|%s] [%s]->[%s]." % (user_karma_change + selected_user_karma_change)) elif selected_user_karma_change: self.send_message( event, "Карма изменена: [id%s|%s] [%s]->[%s]. Голосовали: (%s)" % (selected_user_karma_change + (", ".join(["@id%s" % (voter) for voter in voters]), ))) def send_karma(self, event, user, is_self=True): if is_self: response = "[id%s|%s], Ваша карма - [%s]." else: response = "Карма [id%s|%s] - [%s]." self.send_message(event, response % (user.uid, user.name, user.rating)) def send_info(self, event, user, is_self=True): programming_languages_string = self.get_programming_languages_string( user) if is_self: response = "[id%s|%s], Ваша карма - [%s].\nВаши языки программирования - %s" else: response = "Карма [id%s|%s] - [%s].\nЯзыки программирования - %s" if not programming_languages_string: programming_languages_string = "отсутствуют" self.send_message( event, response % (user.uid, user.name, user.rating, programming_languages_string)) def send_top_users(self, event, users): if not users: return user_strings = [ "[%s] [id%s|%s] %s" % (user["rating"], user["uid"], user["name"], self.get_programming_languages_string_with_parentheses_or_empty( user)) for user in users ] total_symbols = 0 i = 0 for user_string in user_strings: user_string_length = len(user_string) if (total_symbols + user_string_length + 2 ) >= 4096: # Maximum message size for VK API (messages.send) user_strings = user_strings[:i] else: total_symbols += user_string_length + 2 i += 1 response = "\n".join(user_strings) self.send_message(event, response) def send_bottom(self, event): users = base.getSortedByKeys("rating", otherKeys=["programming_languages"]) users = [ i for i in users if (i["rating"] != 0) or ("programming_languages" in i and len(i["programming_languages"]) > 0) ] self.send_top_users(event, reversed(users)) def send_top(self, event): users = base.getSortedByKeys("rating", otherKeys=["programming_languages"]) users = [ i for i in users if (i["rating"] != 0) or ("programming_languages" in i and len(i["programming_languages"]) > 0) ] self.send_top_users(event, users) def send_top_languages(self, event, languages): languages = regex.split(r"\s+", languages) users = base.getSortedByKeys("rating", otherKeys=["programming_languages"]) users = [ i for i in users if ("programming_languages" in i and len(i["programming_languages"]) > 0) and self. contains_all_strings(i["programming_languages"], languages, True) ] self.send_top_users(event, users) def send_programming_languages_list(self, event, user): programming_languages_string = self.get_programming_languages_string( user) if not programming_languages_string: self.send_message( event, "[id%s|%s], у Вас не указано языков программирования." % (user.uid, user.name)) else: self.send_message( event, "[id%s|%s], Ваши языки программирования: %s." % (user.uid, user.name, programming_languages_string)) def send_help(self, event): self.send_message(event, help_string) def send_not_in_whitelist(self, event, user): self.send_message( event, "Извините, [id%s|%s], но Ваша беседа [%s] отсутствует в белом списке для начисления кармы." % (user.uid, user.name, event["peer_id"])) def send_not_enough_karma_error(self, event, user): self.send_message( event, "Извините, [id%s|%s], но Вашей кармы [%s] недостаточно :(" % (user.uid, user.name, user.rating)) def send_message(self, event, message): self.messages.send(message=message, peer_id=event["peer_id"], disable_mentions=1, random_id=0)
import userbot from userbot import UserBot from userbot import scheduler if __name__ == "__main__": userbot.client = UserBot scheduler.start() UserBot.run()
def __init__(self): Vk.__init__(self, token=BotToken, group_id=bot_group_id, debug=True) self.messages_to_delete = {} self.userbot = UserBot() self.debug = True