From fe0379c144a92fba728d6f3be06af6dd3dcf8623 Mon Sep 17 00:00:00 2001 From: Egor Deev <67710823+IGlek@users.noreply.github.com> Date: Mon, 12 Feb 2024 18:26:35 +0700 Subject: [PATCH] v. 1.0 --- code/bot.py | 306 +++++++++++++++++++++++++++++++++++++++++++++ code/config.py | 14 +++ code/scripts.py | 57 +++++++++ code/sql.py | 168 +++++++++++++++++++++++++ code/vk_scripts.py | 76 +++++++++++ db/base.db | Bin 0 -> 16384 bytes db/users.db | Bin 0 -> 12288 bytes 7 files changed, 621 insertions(+) create mode 100644 code/bot.py create mode 100644 code/config.py create mode 100644 code/scripts.py create mode 100644 code/sql.py create mode 100644 code/vk_scripts.py create mode 100644 db/base.db create mode 100644 db/users.db diff --git a/code/bot.py b/code/bot.py new file mode 100644 index 0000000..f953e9a --- /dev/null +++ b/code/bot.py @@ -0,0 +1,306 @@ +import logging, config, asyncio, time, sql, random + +from aiogram import Bot, Dispatcher, executor, types +from emoji import emojize + +from vk_scripts import VkParser +from scripts import login, pars_post + +# log level +logging.basicConfig(level=logging.INFO) + +# bot init +bot = Bot(token=config.botToken) +dp = Dispatcher(bot) + +# connection db +du = sql.Users('../db/users.db') +db = sql.Base('../db/base.db') + + +# events +@dp.message_handler(commands=["start", "help"]) +async def start(message: types.Message): + login(message.chat.id, du, db) + + buttons = [types.InlineKeyboardButton(text="КОМАНДЫ", callback_data="com"), + types.InlineKeyboardButton(text="АВТОР", callback_data="auth")] + + keyboard = types.InlineKeyboardMarkup(row_width=2) + keyboard.add(*buttons) + + await message.answer(text=f'*Portal in VK* - это бот для перепоста постов со страниц в социальной сети ВКонтакте. ' + f'Для начала работы вам нужно всего лишь вызвать команду */add* и добавить к ней короткое ' + f'имя личной или публичной страницы. После этого, бот начнёт присылать каждый новый пост ' + f'с этой страницы форматируя данные с неё под сообщение в Telegram. С полным функционалом ' + f'бота, вы можете ознакомиться по кнопке *КОМАНДЫ*\n\n' + + f'Если вы хотите ставить лайки или получать уведомления от закрытых страниц на которые ' + f'подписаны в социальной сети, вам необходимо скинуть ссылку из поисковой строки в чат, ' + f'после подтверждения на [сайте]({config.loginUrl})', + parse_mode=types.ParseMode.MARKDOWN, reply_markup=keyboard) + + +# ИЛАЙН КЛАВИАТУРА HELP +@dp.callback_query_handler(text="com") +async def function(call: types.CallbackQuery): + await call.message.answer(text='*| КОМАНДЫ |*\n\n' + f'*/like* - лайк на пост, который вы отметили\n' + f'*/list* - список страниц от, которых вы получаете уведомления\n' + f'*/notif* - отписка или подписка от всех уведомлений\n' + f'*/last_post* - получение последнего поста по короткому имени страницы\n' + f'*/add* и */del* - добавление и удаление странички из списка подписок\n', + parse_mode=types.ParseMode.MARKDOWN) + + +@dp.callback_query_handler(text="auth") +async def author(call: types.CallbackQuery): + await call.message.answer(text='*| АВТОР |*\n\n*>>* Этот бот не коммерческий проект, для получения постов из ' + 'социальной сети ВКонтакте. Бот работает на сервисном токене VK API, пока вы не ' + 'предоставите собственный. Ваш токен нужен для получения постов со страниц, ' + 'доступ к которым есть исключительно у вас. Также это даст вам возможность ставить ' + 'через Telegram лайки на посты в самой социальной сети!' + + '\n\nЯ же пишу подобные небольшие проекты, о которых вы можете узнать ' + 'больше на моём [GitHub](https://github.com/IGlek).', + parse_mode=types.ParseMode.MARKDOWN) + + +# КОМАНДЫ +@dp.message_handler(commands=["notif"]) +async def notification(message: types.Message): + user_id = login(message.chat.id, du, db) + status = db.get_status(user_id) + + groups = list(map(int, db.get_user_groups(user_id).split(";"))) + for group in groups: db.update_countGroup(group, -1 if status else 1) + + if status: await message.answer("Получение постов из ВК выключено!") + else: await message.answer("Получение постов из ВК включено!") + db.update_status(user_id) + + +@dp.message_handler(commands=["add", "del"]) +async def add_del(message: types.Message): + user_id = login(message.chat.id, du, db) + domain = message.get_args() + + if domain: + try: + token = db.get_token(user_id) + if token: vk = VkParser(token) + else: vk = VkParser(config.serviceToken) + + group_id, typ, last_post = vk.login(domain) + + if not du.group_exists(group_id): + du.add_group(group_id) + group_id = du.get_group_id(group_id) + + if not db.infoGroup_exists(group_id): + db.add_infoGroup(group_id, typ, last_post) + + groups = db.get_user_groups(user_id) + user_groups = groups.split(";") if groups else [] + + if str(group_id) not in user_groups: + if message.get_command() == "/del": + await message.answer("Вы и так не подписаны на эту группу!") + else: + if db.get_countUser(user_id) < 10: + user_groups.append(str(group_id)) + db.update_user_groups(user_id, ";".join(user_groups)) + + db.update_countUser(user_id, 1) + if db.get_status(user_id): db.update_countGroup(group_id, 1) + + await message.answer("Группа успешно добавлена в список уведомлений!") + else: + await message.answer("У вас добавлено максимально количество групп!") + else: + if message.get_command() == "/add": + await message.answer("Вы уже подписаны на эту страницу!") + else: + user_groups.remove(str(group_id)) + db.update_user_groups(user_id, ";".join(user_groups)) + + db.update_countUser(user_id, -1) + if db.get_status(user_id): db.update_countGroup(group_id, -1) + + await message.answer("Группа успешно удалена из списка уведомлений!") + except Exception as e: + await message.answer("Произошла ошибка! Проверьте правильность написания короткого адреса страницы " + "и имеете ли вы доступ к этой странице!") + else: + if message.get_command() == "/add": + await message.answer("Команда введена некорректно, такой страницы не существует или она закрыта для " + "просмотра!\n\nКорректный ввод команд: /add example", types.ParseMode.HTML) + elif message.get_command() == "/del": + await message.answer("Команда введена некорректно, такой страницы не существует или она закрыта для " + "просмотра!\n\nКорректный ввод команд: /del example", types.ParseMode.HTML) + + +@dp.message_handler(commands=["list"]) +async def lst(message: types.Message): + user_id = login(message.chat.id, du, db) + groups = db.get_user_groups(user_id) + user_groups = list(map(int, groups.split(";") if groups else [])) + + if user_groups: + group_ids = [du.get_vk_id(id) for id in user_groups] + + vk = VkParser(config.serviceToken) + peoples, groups = vk.info(group_ids) + + text = "* Список страниц, от которых вы получаете уведомления!\n" + + if peoples: + text += "\nЛичные страницы пользователей\n" + for i, people in enumerate(peoples): + text += f'{emojize(":green_circle:") if people[2] else emojize(":red_circle:")} ' \ + f'{i + 1}. {people[1]} @{people[0]}\n' + + if groups: + text += "\nГруппы / сообщества / паблики\n" + for i, group in enumerate(groups): + text += f'{i + 1}. {group[1]} @{group[0]}\n' + + await message.answer(text, types.ParseMode.HTML) + else: + await message.answer("Вы не добавили ни одной страницы для отслеживания публикаций!") + + +@dp.message_handler(commands=["like"]) +async def like(message: types.Message): + user_id = login(message.chat.id, du, db) + token = db.get_token(user_id) + + if token and 'reply_to_message' in message: + url = '' + + if 'entities' in message.reply_to_message: + for i in message.reply_to_message.entities: + if i['type'] == 'text_link': url = i['url']; break + elif 'caption_entities' in message.reply_to_message: + for i in message.reply_to_message.caption_entities: + if i['type'] == 'text_link': url = i['url']; break + + if url: + try: + [group_id, last_post] = list(map(int, url.split('wall')[-1].split('_'))) + + vk = VkParser(token) + vk.like(group_id, last_post) + + await message.answer(text='Вы поставили лайк 😉') + except Exception as e: + await message.answer(text='По неизвестной причине не удалось поставить лайк!') + else: + await message.answer(text='Вы ответили не на тот пост, для отправки лайка!') + else: + await message.answer(text='Вы не отметили пост который хотите лайкнуть или не прислали свой токен для ' + 'возможности лайкать посты!') + + +# ВЗАИМОДЕЙСТВИЕ С ДАННЫМИ ВК ПОСТОВ +@dp.message_handler(commands=["last_post"]) +async def last_post(message: types.Message): + user_id = message.chat.id + short_id = login(user_id, du, db) + domain = message.get_args() + + if domain: + try: + token = db.get_token(short_id) + if token: vk = VkParser(token) + else: vk = VkParser(config.serviceToken) + + output = vk.last_post(domain=domain); vk.login(domain) + text, audio, media = pars_post(types, output) + + if audio and media: + post_message = await bot.send_media_group(chat_id=user_id, media=media) + await bot.send_media_group(chat_id=user_id, media=audio, reply_to_message_id=post_message[0].message_id) + elif audio and media == []: + post_message = await bot.send_message(chat_id=user_id, text=text, parse_mode=types.ParseMode.MARKDOWN) + await bot.send_media_group(chat_id=user_id, media=audio, reply_to_message_id=(post_message[0].message_id)) + elif audio == [] and media: + await bot.send_media_group(chat_id=user_id, media=media) + else: + await bot.send_message(chat_id=user_id, text=text, parse_mode=types.ParseMode.MARKDOWN) + + except Exception as e: + await message.answer("Короткое имя страницы неверное или у вас нет доступа к этой странице!") + else: + await message.answer("Команда введена некорректно! Корректный ввод: /last_post example") + + +# ПОЛУЧЕНИЕ ТОКЕНА ПОЛЬЗОВАТЕЛЯ +@dp.message_handler(content_types="text") +async def url(message: types.Message): + user_id = login(message.chat.id, du, db) + + if config.checkUrl in message.text: + try: + token = message.text.split("&")[0].split("=")[-1] + info = VkParser(token).check() + + db.update_token(user_id, token) + await message.answer("Токен успешно сохранён!") + except Exception as e: + await message.answer("Ваша ссылка не корректна, попробуйте повторить копирование!") + else: + await message.answer("Ваше сообщение не корректно, необходима ссылка, что отобразилась в строке поиске после" + " подтверждения доступа!") + + +# ПРОВЕРКА СТРАНИЦ НА НОВЫЕ ПОСТЫ +async def timer(wait_for): + while True: + await asyncio.sleep(wait_for) + + notif_group = list(map(lambda x: x[0], db.all_notifGroup())) + activ_user = list(map(lambda x: [x[0], list(map(int, x[1].split(';')))], db.all_activUser())) + sub_user = list(map(lambda x: [x[0], list(map(int, x[1].split(';')))], db.all_subUser())) + + for group_id in notif_group: + time.sleep(1) + + tokens = [x[0] for x in activ_user if group_id in x[1]] + users = [x[0] for x in sub_user if group_id in x[1]] + + if tokens: + user_id = tokens[random.randrange(len(tokens))] + vk = VkParser(db.get_token(user_id)) + else: vk = VkParser(config.serviceToken) + + try: + output = vk.last_post(owner_id=du.get_vk_id(group_id)) + last_post = db.get_postGroup(group_id) + + if output[3] > last_post: + text, audio, media = pars_post(types, output) + db.update_postGroup(group_id, output[3]) + + for sub in users: + tg_id = du.get_tg_id(sub) + + if audio and media: + post_message = await bot.send_media_group(chat_id=tg_id, media=media) + await bot.send_media_group(chat_id=tg_id, media=audio, reply_to_message_id=post_message[0].message_id) + elif audio and media == []: + post_message = await bot.send_message(chat_id=tg_id, text=text, parse_mode=types.ParseMode.MARKDOWN) + await bot.send_media_group(chat_id=tg_id, media=audio, reply_to_message_id=post_message[0].message_id) + elif audio == [] and media: + await bot.send_media_group(chat_id=tg_id, media=media) + else: + await bot.send_message(chat_id=tg_id, text=text, parse_mode=types.ParseMode.MARKDOWN) + + except Exception as e: + print(repr(e)) + + +if __name__ == '__main__': + loop = asyncio.get_event_loop() + loop.create_task(timer(60)) # ПРОВЕРКА КАЖДУЮ МИНУТУ + executor.start_polling(dp, skip_updates=True) diff --git a/code/config.py b/code/config.py new file mode 100644 index 0000000..93d5fef --- /dev/null +++ b/code/config.py @@ -0,0 +1,14 @@ +# TOKENS +botToken = '**********' +serviceToken = "**********" + +# URL +loginUrl = "************" +checkUrl = "https://oauth.vk.com/blank.html#access_token=" + +# VARIABILITY +unvote = {True: 'без возможности переголосовать', False: 'с возможностью переголосовать'} +anonymous = {True: 'анонимный опрос', False: 'не анонимный опрос'} + +# DATA +data = {0: 'Б', 1: 'КБ', 2: 'МБ', 3: 'ГБ', 4: 'ТБ'} diff --git a/code/scripts.py b/code/scripts.py new file mode 100644 index 0000000..d774876 --- /dev/null +++ b/code/scripts.py @@ -0,0 +1,57 @@ +import config + + +def login(user_id, du, db): + user_id = int(user_id) + if not du.user_exists(user_id): du.add_user(user_id) + + user_id = du.get_user_id(user_id) + if not db.infoUser_exists(user_id): db.add_infoUser(user_id) + + return user_id + + +def pars_post(types, output): + media, ttl, url, audio, poll, link = [], [], [], [], [], [] + + for group in output[0]: + if group[0] == "poll": poll = group[1] + elif group[0] == "link": link.append(group[1]) + elif group[0] == "video": ttl.append(group[1]) + elif group[0] == "doc" and group[1][2] != 4: url.append([group[1][0], group[1][1], group[1][3]]) + elif group[0] == "audio": audio.append(types.InputMediaAudio(media=group[1][1], parse_mode=types.ParseMode.MARKDOWN, + caption=f"*Название: {group[1][0]} / Автор: {group[1][2]}*")) + + if output[1] != "": text = f"{output[2]}\n\n*{output[1]}*\n" + else: text = f"{output[2]}\n" + + if poll: + text += f"\n*> Проводиться {config.anonymous[poll[3]]} {config.unvote[poll[2]]}!" + text += f"*\n*---------------------*\n*- Вопрос: {poll[0]} [{poll[1]}]*\n" + text += ''.join([f'*{i}. Ответ: {ans[0]} [{ans[1]}]*\n' for i, ans in enumerate(poll[4])]) + text += "*---------------------*\n" + + if ttl: text += f"\n*Видео -* находятся в оригинальном посте в количестве {len(ttl)} записей\n" + + if url: + for data in url: + k, dt = 0, data[2] + while True: + if dt > 1024: dt = dt // 1024; k += 1 + else: break + text += f"\n*Документ - [* [{data[0]}]({data[1]}) ({dt} {config.data[k]}) *]*" + text += "\n" + + if link: text += ''.join([f"\n*Ссылка - [* [{s[0]}]({s[1]}) *]*" for s in link]) + "\n" + if audio: text += '\n*« Также присутствуют аудио файлы »*' + + for i, group in enumerate(output[0]): + if group[0] == "photo": + if i: media.append(types.InputMediaPhoto(media=group[1])) + else: media.append(types.InputMediaPhoto(media=group[1], caption=text, parse_mode=types.ParseMode.MARKDOWN)) + elif group[0] == "doc": + if group[1][2] == 4: + if i: media.append(types.InputMediaPhoto(media=group[1][1])) + else: media.append(types.InputMediaPhoto(media=group[1][1], caption=text, parse_mode=types.ParseMode.MARKDOWN)) + + return text, audio, media diff --git a/code/sql.py b/code/sql.py new file mode 100644 index 0000000..cc98bf9 --- /dev/null +++ b/code/sql.py @@ -0,0 +1,168 @@ +import sqlite3 + + +class Users: + def __init__(self, database): + """Подключаемся к БД и сохраняем курсор соединения""" + self.connection = sqlite3.connect(database) + self.cursor = self.connection.cursor() + + # КОМАНДЫ USER + def user_exists(self, user_id): + """Проверяем, есть ли уже пользователь в базе""" + with self.connection: + result = self.cursor.execute('SELECT * FROM `user` WHERE `user_id` = ?', (user_id,)).fetchall() + return bool(len(result)) + + def add_user(self, user_id): + """Добавляем нового пользователя""" + with self.connection: + return self.cursor.execute("INSERT INTO `user` (`user_id`) VALUES(?)", (user_id,)) + + def get_user_id(self, user_id): + """Получаем короткое айди юзера""" + with self.connection: + return self.cursor.execute('SELECT `id` FROM `user` WHERE `user_id` = ?', (user_id,)).fetchone()[0] + + def get_tg_id(self, user_id): + """Получаем длинное айди юзера""" + with self.connection: + return self.cursor.execute('SELECT `user_id` FROM `user` WHERE `id` = ?', (user_id,)).fetchone()[0] + + # КОМАНДЫ GROUP + def group_exists(self, group_id): + """Проверяем, есть ли уже группа в базе""" + with self.connection: + result = self.cursor.execute('SELECT * FROM `group` WHERE `group_id` = ?', (group_id,)).fetchall() + return bool(len(result)) + + def add_group(self, group_id): + """Добавляем новую группу""" + with self.connection: + return self.cursor.execute("INSERT INTO `group` (`group_id`) VALUES(?)", (group_id,)) + + def get_group_id(self, group_id): + """Получаем короткое айди группы""" + with self.connection: + return self.cursor.execute('SELECT `id` FROM `group` WHERE `group_id` = ?', (group_id,)).fetchone()[0] + + def get_vk_id(self, group_id): + """Получаем длинное айди группы""" + with self.connection: + return self.cursor.execute('SELECT `group_id` FROM `group` WHERE `id` = ?', (group_id,)).fetchone()[0] + + # ЗАКРЫТИЕ ВЫЗОВА + def close(self): + """Закрываем соединение с БД""" + self.connection.close() + + +class Base: + def __init__(self, database): + """Подключаемся к БД и сохраняем курсор соединения""" + self.connection = sqlite3.connect(database) + self.cursor = self.connection.cursor() + + # КОМАНДЫ USER + def infoUser_exists(self, user_id): + """Проверяем, есть ли данные уже в базе""" + with self.connection: + result = self.cursor.execute('SELECT * FROM `user` WHERE `user_id` = ?', (user_id,)).fetchall() + return bool(len(result)) + + def add_infoUser(self, user_id): + """Добавляем информацию о пользователе""" + with self.connection: + return self.cursor.execute("INSERT INTO `user` (`user_id`) VALUES(?)", (user_id, )) + + def all_activUser(self): + """Список активных пользователей""" + with self.connection: + return self.cursor.execute('SELECT `user_id`, `groups` FROM `user` WHERE `status` = 1 AND `count` > 0 ' + 'AND `token` NOT NULL').fetchall() + + def all_subUser(self): + """Список пользователей подписанных на группу""" + with self.connection: + return self.cursor.execute('SELECT `user_id`, `groups` FROM `user` WHERE `status` = 1 AND `count` > 0').fetchall() + + def get_status(self, user_id): + """Получаем статус рассылки уведомлений""" + with self.connection: + return self.cursor.execute('SELECT `status` FROM `user` WHERE `user_id` = ?', (user_id,)).fetchone()[0] + + def update_status(self, user_id): + """Обновляем статус рассылки уведомлений""" + with self.connection: + status = self.cursor.execute('SELECT `status` FROM `user` WHERE `user_id` = ?', (user_id,)).fetchone()[0] + return self.cursor.execute("UPDATE `user` SET `status` = ? WHERE `user_id` = ?", (not status, user_id)) + + def get_user_groups(self, user_id): + """Получаем группы на которые подписан пользователь""" + with self.connection: + return self.cursor.execute('SELECT `groups` FROM `user` WHERE `user_id` = ?', (user_id,)).fetchone()[0] + + def update_user_groups(self, user_id, groups): + """Обновляем группы на которые подписан пользователь""" + with self.connection: + return self.cursor.execute("UPDATE `user` SET `groups` = ? WHERE `user_id` = ?", (groups, user_id)) + + def get_token(self, user_id): + """Получаем access token пользователя""" + with self.connection: + return self.cursor.execute('SELECT `token` FROM `user` WHERE `user_id` = ?', (user_id,)).fetchone()[0] + + def update_token(self, user_id, token): + """Обновляем access token пользователя""" + with self.connection: + return self.cursor.execute("UPDATE `user` SET `token` = ? WHERE `user_id` = ?", (token, user_id)) + + def get_countUser(self, user_id): + """Получаем количество подписок пользователя""" + with self.connection: + return self.cursor.execute('SELECT `count` FROM `user` WHERE `user_id` = ?', (user_id,)).fetchone()[0] + + def update_countUser(self, user_id, num): + """Обновляем количество подписок пользователя""" + with self.connection: + count = self.cursor.execute('SELECT `count` FROM `user` WHERE `user_id` = ?', (user_id,)).fetchone()[0] + return self.cursor.execute("UPDATE `user` SET `count` = ? WHERE `user_id` = ?", (count + num, user_id)) + + # КОМАНДЫ GROUP + def infoGroup_exists(self, group_id): + """Проверяем, есть ли данные уже в базе""" + with self.connection: + result = self.cursor.execute('SELECT * FROM `group` WHERE `group_id` = ?', (group_id,)).fetchall() + return bool(len(result)) + + def add_infoGroup(self, group_id, tp, last_post): + """Добавляем информацию о группе""" + with self.connection: + return self.cursor.execute("INSERT INTO `group` (`group_id`, `type`, `last_post`) VALUES(?, ?, ?)", + (group_id, tp, last_post)) + + def all_notifGroup(self): + """Список отслеживаемых групп""" + with self.connection: + return self.cursor.execute('SELECT `group_id` FROM `group` WHERE `count` > 0').fetchall() + + def get_postGroup(self, group_id): + """Получаем номер последнего поста""" + with self.connection: + return self.cursor.execute('SELECT `last_post` FROM `group` WHERE `group_id` = ?', (group_id,)).fetchone()[0] + + def update_postGroup(self, group_id, last_post): + """Обновляем номер последнего поста""" + with self.connection: + return self.cursor.execute("UPDATE `group` SET `last_post` = ? WHERE `group_id` = ?", (last_post, group_id)) + + def update_countGroup(self, group_id, num): + """Обновляем количество подписок на группу""" + with self.connection: + count = self.cursor.execute('SELECT `count` FROM `group` WHERE `group_id` = ?', (group_id,)).fetchone()[0] + return self.cursor.execute("UPDATE `group` SET `count` = ? WHERE `group_id` = ?", (count + num, group_id)) + + # ЗАКРЫТИЕ ВЫЗОВА + def close(self): + """Закрываем соединение с БД""" + self.connection.close() diff --git a/code/vk_scripts.py b/code/vk_scripts.py new file mode 100644 index 0000000..9f02e09 --- /dev/null +++ b/code/vk_scripts.py @@ -0,0 +1,76 @@ +import vk_api + + +class VkParser: + def __init__(self, token): + """Подключаемся к API VK""" + self.session = vk_api.VkApi(token=token) + self.vk = self.session.get_api() + + def check(self): + return self.vk.account.getInfo(fields="lang") + + def like(self, owner_id, post_id): + return self.vk.likes.add(type="post", owner_id=owner_id, item_id=post_id) + + def login(self, domain): + posts = self.vk.wall.get(domain=domain, count=3) + post = max([[int(pt["id"]), int(pt["owner_id"])] for pt in posts["items"]]) + + [last_post, group_id] = post + typ = 0 if group_id > 0 else 1 + return group_id, typ, last_post + + def info(self, group_ids): + groups, peoples = [], [] + + for id in group_ids: + if id > 0: peoples.append(id) + else: groups.append(id) + + if groups: + data = self.vk.groups.getById(group_ids=", ".join(list(map(lambda x: str(x)[1:], groups)))) + groups = [[elem['screen_name'], elem['name']] for elem in data] + + if peoples: + data = self.vk.users.get(user_ids=", ".join(list(map(str, peoples))), fields="domain, online") + peoples = [[elem['domain'], elem['first_name'] + ' ' + elem['last_name'], elem['online']] for elem in data] + + return peoples, groups + + def last_post(self, owner_id=None, domain=None): + wall = self.vk.wall.get(owner_id=owner_id, domain=domain, count=2, extended=1) + post = max([[int(pt["id"]), pt] for pt in wall["items"]]) + + [post_id, post] = post + owner_id, output = post['owner_id'], [] + + if owner_id > 0: [name, domain] = [[per['first_name'] + ' ' + per['last_name'], per['screen_name']] + for per in wall["profiles"] if per["id"] == owner_id][0] + else: [name, domain] = [[gro['name'], gro['screen_name']] + for gro in wall["groups"] if gro["id"] == int(str(owner_id)[1:])][0] + + attachments = post['attachments'] + types = [[typ['type'], typ] for typ in attachments] + + for typ in types: + if typ[0] == 'photo': + output.append([typ[0], typ[1]['photo']['sizes'][-1]['url']]) + elif typ[0] == 'video': + output.append([typ[0], typ[1]['video']['title']]) + elif typ[0] == "doc": + output.append([typ[0], [typ[1]['doc']['title'], typ[1]['doc']['url'], + typ[1]['doc']['type'], typ[1]['doc']['size']]]) + elif typ[0] == "audio": + output.append([typ[0], [typ[1]['audio']['title'], typ[1]['audio']['url'], typ[1]['audio']['artist']]]) + elif typ[0] == "poll": + answer = [[que['text'], que['votes']] for que in typ[1]['poll']['answers']] + output.append([typ[0], [typ[1]['poll']['question'], typ[1]['poll']['votes'], + typ[1]['poll']['disable_unvote'], typ[1]['poll']['anonymous'], answer]]) + elif typ[0] == "link": + output.append([typ[0], [typ[1]['link']['title'], typ[1]['link']['url']]]) + + return [output, post['text'], + f"*Автор поста -* [{name}](https://vk.com/{domain}?w=wall{owner_id}_{post_id})", post_id] + + diff --git a/db/base.db b/db/base.db new file mode 100644 index 0000000000000000000000000000000000000000..69d4c44c883ac6859a7caa51b37bcc0a16c69150 GIT binary patch literal 16384 zcmeI#%SyvQ7zN--6#`YG8_hzHpDv_vdz))0N_Wpq5)grq}(bBg4D6^HcTwe%o`oN8D}r9(^;mS|-Zo z>h!Ov8St7a%IG#6QgC*h6@=`{RE$ekQ96|4ewAJlrLm}Fjb&%FQ8sPc9_QC>`Y>0B z@jj?RRo#})>K%D)3R+y<$@gm{AL5W2t(Nb(!9?}Psw$W9yy z9kS5RQD4Bb25wFOhe@drFQcI91W4f?Dw?)AGpRRC+`HgogY4Q_%6_Yrng6#C5CRZ@00bZa0SG_<0uX=z1Rwx`DFm?o zp8^j+*A6$-TN(TC2W@Qp&h&xZH<7U+oX>sSoz2wnp`q zKP^`^?I+dVxrIOg0R#|0009ILKmY**5J2Ee1!krhhN0fxRP)70@m{VsU-i;>Ol_1| z$)bnYN~gZ-NO$!n!z8l