diff --git a/code/bot.py b/code/bot.py
index bc006c3..1cb4065 100644
--- a/code/bot.py
+++ b/code/bot.py
@@ -1,61 +1,60 @@
-import asyncio, logging, time, random, scripts, vk_scripts
+import asyncio
+import logging
+import random
-from init import *
-from config import *
+import scripts
+import vk_scripts
+from init import bot, dp, du, db
+from config import serviceToken
from handlers import router
+async def check_group(group_id, activ_user, sub_user):
+ 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:
+ vk = vk_scripts.VkParser(db.get_token(random.choice(tokens)))
+ else: vk = vk_scripts.VkParser(serviceToken)
+
+ # vk_api синхронный — в отдельном потоке, чтобы не замирал весь бот
+ output = await asyncio.to_thread(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 = scripts.pars_post(output)
+ db.update_postGroup(group_id, output[3])
+
+ for sub in users:
+ try:
+ await scripts.send_post(bot, du.get_tg_id(sub), text, audio, media)
+ except Exception:
+ # подписчик мог заблокировать бота — остальным пост всё равно уходит
+ logging.warning("Не удалось отправить пост подписчику %s", sub, exc_info=True)
+
+
async def timer(wait_for) -> None:
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()))
+ notif_group = [x[0] for x in db.all_notifGroup()]
+ activ_user = [[x[0], list(map(int, x[1].split(';')))] for x in db.all_activUser() if x[1]]
+ sub_user = [[x[0], list(map(int, x[1].split(';')))] for x in db.all_subUser() if x[1]]
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 = vk_scripts.VkParser(db.get_token(user_id))
- else: vk = vk_scripts.VkParser(serviceToken)
+ await asyncio.sleep(1) # пауза между страницами — лимиты VK API
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 = scripts.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)
- 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, disable_web_page_preview=True)
-
- except Exception as err:
+ await check_group(group_id, activ_user, sub_user)
+ except Exception:
logging.error("Ошибка обновления поста:", exc_info=True)
async def main() -> None:
dp.include_router(router)
await bot.delete_webhook(drop_pending_updates=True)
- await dp.start_polling(bot, allowed_updates=dp.resolve_used_update_types(), skipUpdates=True)
+ await dp.start_polling(bot, allowed_updates=dp.resolve_used_update_types())
async def process() -> None:
@@ -63,7 +62,5 @@ async def process() -> None:
if __name__ == "__main__":
- logging.basicConfig(level=logging.INFO)
-
try: asyncio.run(process())
except KeyboardInterrupt: pass
diff --git a/code/config.py b/code/config.py
index 95f35ab..da5ff56 100644
--- a/code/config.py
+++ b/code/config.py
@@ -1,9 +1,13 @@
+import os
+
# TOKENS
-botToken = '**********'
-serviceToken = "**********"
+botToken = os.getenv("BOT_TOKEN", "XXXXXXXXXXXXXXXXXXXXXXXX") # @vkportalbot
+serviceToken = os.getenv("VK_SERVICE_TOKEN", "") # сервисный ключ приложения VK
# URL
-loginUrl = "************"
+loginUrl = os.getenv("VK_LOGIN_URL", "https://oauth.vk.com/authorize?client_id=6121396&scope=215985366"
+ "&redirect_uri=https://oauth.vk.com/blank.html&display=page"
+ "&response_type=token&revoke=1")
checkUrl = "https://oauth.vk.com/blank.html#access_token="
# VARIABILITY
@@ -12,3 +16,4 @@ anonymous = {True: 'анонимный опрос', False: 'не анонимн
# DATA
data = {0: 'Б', 1: 'КБ', 2: 'МБ', 3: 'ГБ', 4: 'ТБ'}
+dura = {0: 'с.', 1: 'мин.'}
diff --git a/code/handlers.py b/code/handlers.py
index 1dd8b3e..5ee8d18 100644
--- a/code/handlers.py
+++ b/code/handlers.py
@@ -1,13 +1,16 @@
+import asyncio
+import logging
+
from aiogram import types, F, Router
from aiogram.types import Message, CallbackQuery, ContentType
from aiogram.filters import Command
from emoji import emojize
-from init import *
-from config import *
+from init import bot, du, db
+from config import checkUrl, loginUrl, serviceToken
from vk_scripts import VkParser
-from scripts import login, pars_post
+from scripts import login, pars_post, send_post
router = Router()
@@ -18,7 +21,7 @@ async def start(msg: Message) -> None:
buttons = [[types.InlineKeyboardButton(text="КОМАНДЫ", callback_data="com"),
types.InlineKeyboardButton(text="АВТОР", callback_data="auth")]]
- keyboard = types.InlineKeyboardMarkup(inline_keyboard=buttons, row_width=2)
+ keyboard = types.InlineKeyboardMarkup(inline_keyboard=buttons)
await msg.answer(text=f'Portal in VK - это бот для перепоста постов со страниц в социальной сети ВКонтакте. '
f'Для начала работы вам нужно всего лишь вызвать команду /add и добавить к ней '
@@ -39,7 +42,9 @@ async def function(call: CallbackQuery) -> None:
'/list - список страниц от, которых вы получаете уведомления\n'
'/notif - отписка или подписка от всех уведомлений\n'
'/last_post - получение последнего поста по короткому имени страницы\n'
- '/add и /del - добавление и удаление странички из списка подписок\n')
+ '/add и /del - добавление и удаление странички из списка подписок\n'
+ '/update - ответом на пост: прислать его заново с актуальными данными\n'
+ '/logout - удалить сохранённый токен VK\n')
@router.callback_query(F.data == "auth")
@@ -51,7 +56,7 @@ async def author(call: CallbackQuery) -> None:
'возможность ставить через Telegram лайки на посты в самой социальной сети!'
'\n\nЯ же пишу подобные небольшие проекты, о которых вы можете узнать '
- 'больше на моём GitHub.')
+ 'больше на моём GitHub.')
# КОМАНДЫ
@@ -60,8 +65,10 @@ async def notification(msg: Message) -> None:
user_id = login(msg.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)
+ # у пользователя может ещё не быть ни одной подписки
+ groups = db.get_user_groups(user_id)
+ for group in map(int, groups.split(";") if groups else []):
+ db.update_countGroup(group, -1 if status else 1)
if status: await msg.answer("Получение постов из ВК выключено!")
else: await msg.answer("Получение постов из ВК включено!")
@@ -81,7 +88,7 @@ async def add_del(msg: Message) -> None:
if token: vk = VkParser(token)
else: vk = VkParser(serviceToken)
- group_id, typ, last_post = vk.login(domain)
+ group_id, typ, last_post = await asyncio.to_thread(vk.login, domain)
if not du.group_exists(group_id):
du.add_group(group_id)
@@ -118,7 +125,7 @@ async def add_del(msg: Message) -> None:
if db.get_status(user_id): db.update_countGroup(group_id, -1)
await msg.answer("Группа успешно удалена из списка уведомлений!")
- except Exception as err:
+ except Exception:
logging.info("Нет доступа к страницы:", exc_info=True)
await msg.answer("Произошла ошибка! Проверьте правильность написания короткого адреса "
"страницы, имеете ли вы доступ к этой странице и есть ли на ней хотя бы "
@@ -142,7 +149,7 @@ async def lst(msg: Message) -> None:
group_ids = [du.get_vk_id(id) for id in user_groups]
vk = VkParser(serviceToken)
- peoples, groups = vk.info(group_ids)
+ peoples, groups = await asyncio.to_thread(vk.info, group_ids)
text = "* Список страниц, от которых вы получаете уведомления!\n"
@@ -186,10 +193,10 @@ async def like(msg: Message) -> None:
[group_id, last_post] = list(map(int, url.split('wall')[-1].split('_')))
vk = VkParser(token)
- vk.like(group_id, last_post)
+ await asyncio.to_thread(vk.like, group_id, last_post)
await msg.answer('Вы поставили лайк 😉')
- except Exception as err:
+ except Exception:
logging.error("Не удалось поставить лайк:", exc_info=True)
await msg.answer('По неизвестной причине не удалось поставить лайк!')
else:
@@ -226,27 +233,16 @@ async def update(msg: Message) -> None:
if token: vk = VkParser(token)
else: vk = VkParser(serviceToken)
- output = vk.last_post(post=f"{group_id}_{last_post}")
- text, audio, media = pars_post(types, output)
+ output = await asyncio.to_thread(vk.last_post, post=f"{group_id}_{last_post}")
+ text, audio, media = pars_post(output)
- delete_r = await bot.delete_message(chat_id=user_id, message_id=msg.reply_to_message.message_id)
- delete = await bot.delete_message(chat_id=user_id, message_id=msg.message_id)
+ await bot.delete_message(chat_id=user_id, message_id=msg.reply_to_message.message_id)
+ await bot.delete_message(chat_id=user_id, message_id=msg.message_id)
- 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)
- 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, disable_web_page_preview=True)
+ await send_post(bot, user_id, text, audio, media)
- except Exception as err:
- logging.danger("Ошибка обновления поста:", exc_info=True)
+ except Exception:
+ logging.error("Ошибка обновления поста:", exc_info=True)
await msg.answer(text='По неизвестной причине не удалось обновить пост!')
else: await msg.answer(text='Вы ответили не на тот пост!')
else: await msg.answer(text='Вы не отметили пост который хотите обновить!')
@@ -265,26 +261,29 @@ async def last_post(msg: Message) -> None:
if token: vk = VkParser(token)
else: vk = VkParser(serviceToken)
- output = vk.last_post(domain=domain); vk.login(domain)
- text, audio, media = pars_post(types, output)
+ output = await asyncio.to_thread(vk.last_post, domain=domain)
+ text, audio, media = pars_post(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)
- 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, disable_web_page_preview=True)
+ await send_post(bot, user_id, text, audio, media)
- except Exception as err:
+ except Exception:
logging.info("Некорректное/недоступное короткое имя:", exc_info=True)
await msg.answer("Короткое имя страницы неверное или у вас нет доступа к этой странице!")
else: await msg.answer("Команда введена некорректно! Корректный ввод: /last_post example")
+@router.message(Command("logout"))
+async def logout(msg: Message) -> None:
+ user_id = login(msg.chat.id, du, db)
+
+ if db.get_token(user_id):
+ db.update_token(user_id, None)
+ await msg.answer("Токен VK удалён, бот снова работает на сервисном ключе. Полностью отозвать доступ "
+ "можно в настройках VK: Приложения и сайты.")
+ else:
+ await msg.answer("Сохранённого токена нет.")
+
+
# ПОЛУЧЕНИЕ ТОКЕНА ПОЛЬЗОВАТЕЛЯ
@router.message(F.content_type == ContentType.TEXT)
async def url(msg: Message) -> None:
@@ -293,11 +292,14 @@ async def url(msg: Message) -> None:
if checkUrl in msg.text:
try:
token = msg.text.split("&")[0].split("=")[-1]
- info = VkParser(token).check()
+ await asyncio.to_thread(VkParser(token).check)
db.update_token(user_id, token)
- await msg.answer("Токен успешно сохранён!")
- except Exception as err:
+ # ссылка с токеном не должна оставаться в переписке
+ try: await msg.delete()
+ except Exception: pass
+ await msg.answer("Токен успешно сохранён! Удалить его можно командой /logout")
+ except Exception:
logging.info("Некорректная ссылка:", exc_info=True)
await msg.answer("Ваша ссылка не корректна, попробуйте повторить копирование!")
else: await msg.answer("Ваше сообщение не корректно, необходима ссылка, что отобразилась в строке "
diff --git a/code/init.py b/code/init.py
index 7f5bbd0..856283f 100644
--- a/code/init.py
+++ b/code/init.py
@@ -1,22 +1,21 @@
+import logging
+import os
+
from aiogram import Bot, Dispatcher
from aiogram.enums.parse_mode import ParseMode
from aiogram.fsm.storage.memory import MemoryStorage
from aiogram.client.bot import DefaultBotProperties
-
from config import botToken
+from sql import Users, Base
bot = Bot(token=botToken, default=DefaultBotProperties(parse_mode=ParseMode.HTML))
dp = Dispatcher(storage=MemoryStorage())
-
-from sql import Users, Base
-
+os.makedirs("../db", exist_ok=True)
du = Users('../db/users.db')
db = Base('../db/base.db')
-
-import logging, functools
-
-logging.basicConfig(level=logging.INFO, filename='../info.log',filemode="w",
+# лог в файл, если задан LOG_FILE (так бот работал на сервере), иначе — в консоль
+logging.basicConfig(level=logging.INFO, filename=os.getenv("LOG_FILE") or None,
format="%(asctime)s %(levelname)s %(message)s")
diff --git a/code/scripts.py b/code/scripts.py
index 00fa9a1..ddcabf5 100644
--- a/code/scripts.py
+++ b/code/scripts.py
@@ -1,5 +1,12 @@
+from html import escape
+
+from aiogram import types
+
import config
+CAPTION_LIMIT = 1024 # подпись к фото в Telegram
+TEXT_LIMIT = 4096 # обычное сообщение
+
def login(user_id, du, db):
user_id = int(user_id)
@@ -11,7 +18,9 @@ def login(user_id, du, db):
return user_id
-def pars_post(types, output):
+def pars_post(output):
+ """Пост из vk_scripts.get_output → текст в HTML, аудио и медиа для Telegram.
+ Всё, что пришло из ВК, экранируется: «<» или «&» в посте иначе ломают отправку"""
media, video, url, audio, poll, link = [], [], [], [], [], []
for group in output[0]:
@@ -20,55 +29,98 @@ def pars_post(types, output):
elif group[0] == "video": video.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], caption=f"Название: {group[1][0]} / Автор: {group[1][2]}"))
+ media=group[1][1], caption=f"Название: {escape(group[1][0])} / Автор: {escape(group[1][2])}"))
if output[1] != "":
- post = [elem_2 for elem_1 in output[1].split("[") for elem_2 in elem_1.split("]")]
+ # упоминания ВК вида [id1|Имя] превращаются в ссылки
+ post = [elem_2 for elem_1 in escape(output[1], quote=False).split("[") for elem_2 in elem_1.split("]")]
for i, elem in enumerate(post):
if "|" in elem and i != 0:
- elem = elem.split("|")
- post[i] = f"{elem[1]}"
+ elem = elem.split("|", 1)
+ post[i] = f"{elem[1]}"
text = f"{output[2]}\n\n{''.join(post)}\n"
else: text = f"{output[2]}\n"
if poll:
- text += f"\n> Проводиться {config.anonymous[poll[3]]} {config.unvote[poll[2]]}! Вопрос: {poll[0]} [{poll[1]}]\n"
- text += ''.join([f'{i + 1}. Ответ: {ans[0]} [{ans[1]}]\n' for i, ans in enumerate(poll[4])]) + "\n"
+ text += (f"\n> Проводится {config.anonymous[poll[3]]} {config.unvote[poll[2]]}! "
+ f"Вопрос: {escape(poll[0])} [{poll[1]}]\n")
+ text += ''.join([f'{i + 1}. Ответ: {escape(ans[0])} [{ans[1]}]\n'
+ for i, ans in enumerate(poll[4])]) + "\n"
if video:
for frame in video:
- text += f"\nВидео « {frame[0]} »\n"
+ text += f"\nВидео « {escape(frame[0])} »\n"
k, dura = 0, frame[1]
- while k < 1:
- if dura > 60: dura = dura // 60; k += 1
- else: break
+ if dura > 60: dura, k = dura // 60, 1
- text += f"Длительность: {dura} {config.dura[k]}; Лайков: {frame[2]};\n"
+ text += f"Длительность: {dura} {config.dura[k]}; Просмотров: {frame[2]};\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]} ({dt} {config.data[k]}) ]"
+ while dt > 1024 and k < len(config.data) - 1:
+ dt, k = dt // 1024, k + 1
+ text += (f"\nДокумент - [ {escape(data[0])} "
+ f"({dt} {config.data[k]}) ]")
text += "\n"
- if link: text += ''.join([f"\nСсылка - [ [{s[0]}]({s[1]}) ]" for s in link]) + "\n"
+ if link:
+ text += ''.join([f"\nСсылка - [ {escape(s[0])} ]"
+ for s in link]) + "\n"
if audio: text += '\n« Также присутствуют аудио файлы »'
- for i, group in enumerate(output[0]):
+ for group in 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))
- elif group[0] == "video":
- if i: media.append(types.InputMediaPhoto(media=group[1][3]))
- else: media.append(types.InputMediaPhoto(media=group[1][3], caption=text))
- 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))
+ media.append(types.InputMediaPhoto(media=group[1]))
+ elif group[0] == "video" and group[1][3]: # у видео может не быть обложки
+ media.append(types.InputMediaPhoto(media=group[1][3]))
+ elif group[0] == "doc" and group[1][2] == 4:
+ media.append(types.InputMediaPhoto(media=group[1][1]))
- return text, audio, media
+ return text, audio[:10], media[:10] # в одном альбоме Telegram не больше 10 элементов
+
+
+def split_text(text, limit=TEXT_LIMIT):
+ """Делит длинный текст по строкам, чтобы не разрывать HTML-теги посередине"""
+ parts, current = [], ""
+ for line in text.split("\n"):
+ while len(line) > limit: # одна строка длиннее лимита — режем как есть
+ if current: parts.append(current); current = ""
+ parts.append(line[:limit]); line = line[limit:]
+ if len(current) + len(line) + 1 > limit:
+ parts.append(current); current = ""
+ current += line + "\n"
+ if current.strip(): parts.append(current)
+ return parts
+
+
+async def send_post(bot, chat_id, text, audio, media):
+ """Отправляет пост с учётом ограничений Telegram: альбом — от 2 до 10 элементов, подпись —
+ до 1024 символов, сообщение — до 4096"""
+ first = None
+
+ if media:
+ caption = text if len(text) <= CAPTION_LIMIT else None
+ if len(media) == 1:
+ first = await bot.send_photo(chat_id=chat_id, photo=media[0].media, caption=caption)
+ else:
+ media[0].caption = caption
+ first = (await bot.send_media_group(chat_id=chat_id, media=media))[0]
+ if caption is None:
+ for part in split_text(text):
+ await bot.send_message(chat_id=chat_id, text=part, disable_web_page_preview=True,
+ reply_to_message_id=first.message_id)
+ else:
+ for part in split_text(text):
+ sent = await bot.send_message(chat_id=chat_id, text=part, disable_web_page_preview=True)
+ first = first or sent
+
+ if audio:
+ reply_to = first.message_id if first else None
+ if len(audio) == 1:
+ await bot.send_audio(chat_id=chat_id, audio=audio[0].media, caption=audio[0].caption,
+ reply_to_message_id=reply_to)
+ else:
+ await bot.send_media_group(chat_id=chat_id, media=audio, reply_to_message_id=reply_to)
diff --git a/code/sql.py b/code/sql.py
index a1b249b..a5287eb 100644
--- a/code/sql.py
+++ b/code/sql.py
@@ -7,6 +7,11 @@ class Users:
self.connection = sqlite3.connect(database)
self.cursor = self.connection.cursor()
+ # на новой установке (например, в Docker с пустым томом) таблиц ещё нет
+ with self.connection:
+ self.cursor.execute("CREATE TABLE IF NOT EXISTS user (id INTEGER PRIMARY KEY, user_id INTEGER NOT NULL)")
+ self.cursor.execute("CREATE TABLE IF NOT EXISTS \"group\" (id INTEGER PRIMARY KEY, group_id INTEGER NOT NULL)")
+
# КОМАНДЫ USER
def user_exists(self, user_id):
"""Проверяем, есть ли уже пользователь в базе"""
@@ -63,6 +68,12 @@ class Base:
self.connection = sqlite3.connect(database)
self.cursor = self.connection.cursor()
+ with self.connection:
+ self.cursor.execute("CREATE TABLE IF NOT EXISTS user (user_id INTEGER NOT NULL, status BOOLEAN NOT NULL "
+ "DEFAULT (True), count INTEGER NOT NULL DEFAULT (0), groups TEXT, token TEXT)")
+ self.cursor.execute("CREATE TABLE IF NOT EXISTS \"group\" (group_id INTEGER NOT NULL, type BOOLEAN NOT NULL, "
+ "count INTEGER NOT NULL DEFAULT (0), last_post INTEGER NOT NULL)")
+
# КОМАНДЫ USER
def infoUser_exists(self, user_id):
"""Проверяем, есть ли данные уже в базе"""
@@ -166,4 +177,3 @@ class Base:
def close(self):
"""Закрываем соединение с БД"""
self.connection.close()
-
diff --git a/code/vk_scripts.py b/code/vk_scripts.py
index 0d5b56c..bf05160 100644
--- a/code/vk_scripts.py
+++ b/code/vk_scripts.py
@@ -1,3 +1,5 @@
+from html import escape
+
import vk_api
@@ -70,7 +72,7 @@ def get_output(post, name, domain, repost=None):
[post_id, post] = post
owner_id, output = post['owner_id'], []
- attachments = post['attachments']
+ attachments = post.get('attachments', [])
types = [[typ['type'], typ] for typ in attachments]
for typ in types:
@@ -78,12 +80,12 @@ def get_output(post, name, domain, repost=None):
output.append([typ[0], typ[1]['photo']['sizes'][-1]['url']])
elif typ[0] == 'video':
video = typ[1]['video']
- if 'photo_1280' in video:
- frame = video['photo_1280']
- else:
- frame = video['photo_800']
+ # обложка: самая крупная из доступных
+ frame = video.get('photo_1280') or video.get('photo_800') or video.get('photo_320')
+ if frame is None and video.get('image'):
+ frame = video['image'][-1]['url']
- output.append([typ[0], [video['title'], video['duration'], video['views'], frame]])
+ output.append([typ[0], [video['title'], video.get('duration', 0), video.get('views', 0), frame]])
elif typ[0] == "doc":
output.append([typ[0], [typ[1]['doc']['title'], typ[1]['doc']['url'],
typ[1]['doc']['type'], typ[1]['doc']['size']]])
@@ -99,11 +101,11 @@ def get_output(post, name, domain, repost=None):
if repost:
[author_id, author_owner_id, author_name, author_domain, author_comment] = repost
- comment = f"Автор репоста - {author_name}"
- if author_comment != "": comment += f"\n{author_comment}
\n"
- comment += f"\nАвтор поста - {name}"
+ comment = f"Автор репоста - {escape(author_name)}"
+ if author_comment != "": comment += f"\n{escape(author_comment)}
\n"
+ comment += f"\nАвтор поста - {escape(name)}"
return [output, f"{post['text']}", comment, author_id]
else:
return [output, f"{post['text']}",
- f"Автор поста - {name}", post_id]
\ No newline at end of file
+ f"Автор поста - {escape(name)}", post_id]
\ No newline at end of file
diff --git a/db/.gitkeep b/db/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/db/base.db b/db/base.db
deleted file mode 100644
index 69d4c44..0000000
Binary files a/db/base.db and /dev/null differ
diff --git a/db/users.db b/db/users.db
deleted file mode 100644
index 71ae8f0..0000000
Binary files a/db/users.db and /dev/null differ