mirror of
https://github.com/civsocit/olgram.git
synced 2025-05-24 11:33:24 +00:00
Merge branch 'main' into stable
This commit is contained in:
commit
44f39e4de0
25
.readthedocs.yaml
Normal file
25
.readthedocs.yaml
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
# Read the Docs configuration file for Sphinx projects
|
||||||
|
|
||||||
|
# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details
|
||||||
|
|
||||||
|
|
||||||
|
# Required
|
||||||
|
|
||||||
|
version: 2
|
||||||
|
|
||||||
|
|
||||||
|
# Set the OS, Python version and other tools you might need
|
||||||
|
|
||||||
|
build:
|
||||||
|
os: ubuntu-22.04
|
||||||
|
tools:
|
||||||
|
python: "3.8"
|
||||||
|
jobs:
|
||||||
|
post_create_environment:
|
||||||
|
- python -m pip install sphinx_rtd_theme
|
||||||
|
|
||||||
|
# Build documentation in the "docs/" directory with Sphinx
|
||||||
|
|
||||||
|
sphinx:
|
||||||
|
|
||||||
|
configuration: docs/source/conf.py
|
|
@ -1,7 +1,7 @@
|
||||||
FROM python:3.8-buster
|
FROM python:3.8-buster
|
||||||
|
|
||||||
ENV PYTHONUNBUFFERED=1 \
|
ENV PYTHONUNBUFFERED=1 \
|
||||||
POETRY_VERSION=1.1.12 \
|
POETRY_VERSION=1.5.1 \
|
||||||
POETRY_VIRTUALENVS_CREATE="false"
|
POETRY_VIRTUALENVS_CREATE="false"
|
||||||
|
|
||||||
RUN apt-get update && \
|
RUN apt-get update && \
|
||||||
|
|
|
@ -20,6 +20,7 @@ Litecoin:
|
||||||
История изменений
|
История изменений
|
||||||
----------------
|
----------------
|
||||||
|
|
||||||
|
- `2024-03-01` Непрерывные потоки сообщений (опция)
|
||||||
- `2024-02-17` Опция смены режима работы автоответчика: автоответчик отвечает на КАЖДОЕ сообщение
|
- `2024-02-17` Опция смены режима работы автоответчика: автоответчик отвечает на КАЖДОЕ сообщение
|
||||||
- `2024-01-12` Мультиязычность (стартовое сообщение и автоответчик)
|
- `2024-01-12` Мультиязычность (стартовое сообщение и автоответчик)
|
||||||
- `2022-08-01` Защита от флуда
|
- `2022-08-01` Защита от флуда
|
||||||
|
|
|
@ -58,3 +58,26 @@ Olgram пересылает сообщения так, чтобы сообщен
|
||||||
|
|
||||||
По-умолчанию автоответчик отвечает только на первое сообщение в диалоге с пользователем. Чтобы автоответчик отвечал на
|
По-умолчанию автоответчик отвечает только на первое сообщение в диалоге с пользователем. Чтобы автоответчик отвечал на
|
||||||
КАЖДОЕ входящее сообщение, включите эту опцию.
|
КАЖДОЕ входящее сообщение, включите эту опцию.
|
||||||
|
|
||||||
|
|
||||||
|
.. thread_interrupt:
|
||||||
|
|
||||||
|
Прерывать поток
|
||||||
|
--------------------------------
|
||||||
|
|
||||||
|
По-умолчанию поток сообщений от одного пользователя прерывается каждые 24 часа. Без этой опции поток сообщений не
|
||||||
|
прерывается никогда.
|
||||||
|
|
||||||
|
|
||||||
|
.. _mailing:
|
||||||
|
|
||||||
|
Рассылка
|
||||||
|
---------------
|
||||||
|
|
||||||
|
После включения этой опции ваш бот будет запоминать всех пользователей, которые пишут в ваш бот.
|
||||||
|
Вы сможете запустить рассылку по этим пользователям.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
Включение этой опции меняет текст политики конфиденциальности вашего feedback бота (команда /security_policy)
|
||||||
|
и может отпугнуть некоторых пользователей. Не включайте эту опцию без необходимости.
|
||||||
|
|
|
@ -5,8 +5,8 @@
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: \n"
|
"Project-Id-Version: \n"
|
||||||
"POT-Creation-Date: 2022-09-02 05:02+0400\n"
|
"POT-Creation-Date: 2024-03-02 19:47+0400\n"
|
||||||
"PO-Revision-Date: 2022-09-02 05:07+0400\n"
|
"PO-Revision-Date: 2024-03-02 19:48+0400\n"
|
||||||
"Last-Translator: \n"
|
"Last-Translator: \n"
|
||||||
"Language-Team: \n"
|
"Language-Team: \n"
|
||||||
"Language: en_US\n"
|
"Language: en_US\n"
|
||||||
|
@ -15,7 +15,7 @@ msgstr ""
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||||
"Generated-By: pygettext.py 1.5\n"
|
"Generated-By: pygettext.py 1.5\n"
|
||||||
"X-Generator: Poedit 3.1\n"
|
"X-Generator: Poedit 3.4.2\n"
|
||||||
|
|
||||||
#: olgram/commands/admin.py:21 olgram/commands/info.py:21
|
#: olgram/commands/admin.py:21 olgram/commands/info.py:21
|
||||||
#: olgram/commands/promo.py:23 olgram/commands/promo.py:39
|
#: olgram/commands/promo.py:23 olgram/commands/promo.py:39
|
||||||
|
@ -62,27 +62,27 @@ msgstr "Cancel"
|
||||||
msgid "Отправлено"
|
msgid "Отправлено"
|
||||||
msgstr "Sent"
|
msgstr "Sent"
|
||||||
|
|
||||||
#: olgram/commands/bot_actions.py:22
|
#: olgram/commands/bot_actions.py:27
|
||||||
msgid "Бот удалён"
|
msgid "Бот удалён"
|
||||||
msgstr "Bot removed"
|
msgstr "Bot removed"
|
||||||
|
|
||||||
#: olgram/commands/bot_actions.py:38 olgram/commands/bot_actions.py:50
|
#: olgram/commands/bot_actions.py:49 olgram/commands/bot_actions.py:67
|
||||||
msgid "Текст сброшен"
|
msgid "Текст сброшен"
|
||||||
msgstr "Text is reset"
|
msgstr "Text is reset"
|
||||||
|
|
||||||
#: olgram/commands/bot_actions.py:64
|
#: olgram/commands/bot_actions.py:81
|
||||||
msgid "Выбран личный чат"
|
msgid "Выбран личный чат"
|
||||||
msgstr "Personal chat selected"
|
msgstr "Personal chat selected"
|
||||||
|
|
||||||
#: olgram/commands/bot_actions.py:77
|
#: olgram/commands/bot_actions.py:94
|
||||||
msgid "Бот вышел из чатов"
|
msgid "Бот вышел из чатов"
|
||||||
msgstr "Bot leaved chats"
|
msgstr "Bot leaved chats"
|
||||||
|
|
||||||
#: olgram/commands/bot_actions.py:83
|
#: olgram/commands/bot_actions.py:100
|
||||||
msgid "Нельзя привязать бота к этому чату"
|
msgid "Нельзя привязать бота к этому чату"
|
||||||
msgstr "You can't bind a bot to this chat room"
|
msgstr "You can't bind a bot to this chat room"
|
||||||
|
|
||||||
#: olgram/commands/bot_actions.py:87
|
#: olgram/commands/bot_actions.py:104
|
||||||
msgid "Выбран чат {0}"
|
msgid "Выбран чат {0}"
|
||||||
msgstr "Selected chat {0}"
|
msgstr "Selected chat {0}"
|
||||||
|
|
||||||
|
@ -195,7 +195,11 @@ msgstr "All bots have outgoing messages: {0}\n"
|
||||||
msgid "Промо-кодов выдано: {0}\n"
|
msgid "Промо-кодов выдано: {0}\n"
|
||||||
msgstr "Promo codes issued: {0}\n"
|
msgstr "Promo codes issued: {0}\n"
|
||||||
|
|
||||||
#: olgram/commands/menu.py:31
|
#: olgram/commands/info.py:40
|
||||||
|
msgid "Рекламную плашку выключили: {0}\n"
|
||||||
|
msgstr "Ad disabled:: {0}\n"
|
||||||
|
|
||||||
|
#: olgram/commands/menu.py:33
|
||||||
msgid ""
|
msgid ""
|
||||||
"\n"
|
"\n"
|
||||||
" У вас нет добавленных ботов.\n"
|
" У вас нет добавленных ботов.\n"
|
||||||
|
@ -209,25 +213,25 @@ msgstr ""
|
||||||
" Send the command /addbot to add a bot.\n"
|
" Send the command /addbot to add a bot.\n"
|
||||||
" "
|
" "
|
||||||
|
|
||||||
#: olgram/commands/menu.py:46
|
#: olgram/commands/menu.py:48
|
||||||
msgid "Ваши боты"
|
msgid "Ваши боты"
|
||||||
msgstr "Your bots"
|
msgstr "Your bots"
|
||||||
|
|
||||||
#: olgram/commands/menu.py:67
|
#: olgram/commands/menu.py:69
|
||||||
msgid "Личные сообщения"
|
msgid "Личные сообщения"
|
||||||
msgstr "Personal messages"
|
msgstr "Personal messages"
|
||||||
|
|
||||||
#: olgram/commands/menu.py:72
|
#: olgram/commands/menu.py:74
|
||||||
msgid "❗️ Выйти из всех чатов"
|
msgid "❗️ Выйти из всех чатов"
|
||||||
msgstr "❗️ Leave all chats"
|
msgstr "❗️ Leave all chats"
|
||||||
|
|
||||||
#: olgram/commands/menu.py:77 olgram/commands/menu.py:122
|
#: olgram/commands/menu.py:79 olgram/commands/menu.py:124
|
||||||
#: olgram/commands/menu.py:148 olgram/commands/menu.py:184
|
#: olgram/commands/menu.py:156 olgram/commands/menu.py:209
|
||||||
#: olgram/commands/menu.py:247
|
#: olgram/commands/menu.py:390
|
||||||
msgid "<< Назад"
|
msgid "<< Назад"
|
||||||
msgstr "<< Back"
|
msgstr "<< Back"
|
||||||
|
|
||||||
#: olgram/commands/menu.py:83
|
#: olgram/commands/menu.py:85
|
||||||
msgid ""
|
msgid ""
|
||||||
"\n"
|
"\n"
|
||||||
" Этот бот не добавлен в чаты, поэтому все сообщения будут приходить "
|
" Этот бот не добавлен в чаты, поэтому все сообщения будут приходить "
|
||||||
|
@ -249,7 +253,7 @@ msgstr ""
|
||||||
" again.\n"
|
" again.\n"
|
||||||
" "
|
" "
|
||||||
|
|
||||||
#: olgram/commands/menu.py:90
|
#: olgram/commands/menu.py:92
|
||||||
msgid ""
|
msgid ""
|
||||||
"\n"
|
"\n"
|
||||||
" В этом разделе вы можете привязать бота @{0} к чату.\n"
|
" В этом разделе вы можете привязать бота @{0} к чату.\n"
|
||||||
|
@ -261,27 +265,31 @@ msgstr ""
|
||||||
" Select the chat room where the bot will forward messages.\n"
|
" Select the chat room where the bot will forward messages.\n"
|
||||||
" "
|
" "
|
||||||
|
|
||||||
#: olgram/commands/menu.py:102
|
#: olgram/commands/menu.py:104
|
||||||
msgid "Текст"
|
msgid "Текст"
|
||||||
msgstr "Text"
|
msgstr "Text"
|
||||||
|
|
||||||
#: olgram/commands/menu.py:107
|
#: olgram/commands/menu.py:109
|
||||||
msgid "Чат"
|
msgid "Чат"
|
||||||
msgstr "Chat"
|
msgstr "Chat"
|
||||||
|
|
||||||
#: olgram/commands/menu.py:112
|
#: olgram/commands/menu.py:114
|
||||||
msgid "Удалить бот"
|
msgid "Удалить бот"
|
||||||
msgstr "Delete bot"
|
msgstr "Delete bot"
|
||||||
|
|
||||||
#: olgram/commands/menu.py:117
|
#: olgram/commands/menu.py:119
|
||||||
msgid "Статистика"
|
msgid "Статистика"
|
||||||
msgstr "Statistics"
|
msgstr "Statistics"
|
||||||
|
|
||||||
#: olgram/commands/menu.py:126
|
#: olgram/commands/menu.py:128
|
||||||
msgid "Опции"
|
msgid "Опции"
|
||||||
msgstr "Options"
|
msgstr "Options"
|
||||||
|
|
||||||
#: olgram/commands/menu.py:131
|
#: olgram/commands/menu.py:134 olgram/commands/menu.py:190
|
||||||
|
msgid "Рассылка"
|
||||||
|
msgstr "Mailing"
|
||||||
|
|
||||||
|
#: olgram/commands/menu.py:139
|
||||||
msgid ""
|
msgid ""
|
||||||
"\n"
|
"\n"
|
||||||
" Управление ботом @{0}.\n"
|
" Управление ботом @{0}.\n"
|
||||||
|
@ -299,11 +307,11 @@ msgstr ""
|
||||||
" @civsocit_feedback_bot\n"
|
" @civsocit_feedback_bot\n"
|
||||||
" "
|
" "
|
||||||
|
|
||||||
#: olgram/commands/menu.py:143
|
#: olgram/commands/menu.py:151
|
||||||
msgid "Да, удалить бот"
|
msgid "Да, удалить бот"
|
||||||
msgstr "Yes, delete the bot"
|
msgstr "Yes, delete the bot"
|
||||||
|
|
||||||
#: olgram/commands/menu.py:152
|
#: olgram/commands/menu.py:160
|
||||||
msgid ""
|
msgid ""
|
||||||
"\n"
|
"\n"
|
||||||
" Вы уверены, что хотите удалить бота @{0}?\n"
|
" Вы уверены, что хотите удалить бота @{0}?\n"
|
||||||
|
@ -313,43 +321,73 @@ msgstr ""
|
||||||
" Are you sure you want to delete the bot @{0}?\n"
|
" Are you sure you want to delete the bot @{0}?\n"
|
||||||
" "
|
" "
|
||||||
|
|
||||||
#: olgram/commands/menu.py:161
|
#: olgram/commands/menu.py:169
|
||||||
msgid "Потоки сообщений"
|
msgid "Потоки сообщений"
|
||||||
msgstr "Message threads"
|
msgstr "Message threads"
|
||||||
|
|
||||||
#: olgram/commands/menu.py:166
|
#: olgram/commands/menu.py:174
|
||||||
msgid "Данные пользователя"
|
msgid "Данные пользователя"
|
||||||
msgstr "User data"
|
msgstr "User data"
|
||||||
|
|
||||||
#: olgram/commands/menu.py:171
|
#: olgram/commands/menu.py:179
|
||||||
msgid "Антифлуд"
|
msgid "Антифлуд"
|
||||||
msgstr "Antiflood"
|
msgstr "Antiflood"
|
||||||
|
|
||||||
#: olgram/commands/menu.py:178
|
#: olgram/commands/menu.py:184
|
||||||
|
msgid "Автоответчик всегда"
|
||||||
|
msgstr "Autorespond always"
|
||||||
|
|
||||||
|
#: olgram/commands/menu.py:195
|
||||||
|
msgid "Прерывать поток"
|
||||||
|
msgstr "Inteeupt thread"
|
||||||
|
|
||||||
|
#: olgram/commands/menu.py:203
|
||||||
msgid "Olgram подпись"
|
msgid "Olgram подпись"
|
||||||
msgstr "Olgram signature"
|
msgstr "Olgram signature"
|
||||||
|
|
||||||
#: olgram/commands/menu.py:189 olgram/commands/menu.py:190
|
#: olgram/commands/menu.py:214 olgram/commands/menu.py:215
|
||||||
msgid "включены"
|
msgid "включены"
|
||||||
msgstr "enabled"
|
msgstr "enabled"
|
||||||
|
|
||||||
#: olgram/commands/menu.py:189 olgram/commands/menu.py:190
|
#: olgram/commands/menu.py:214 olgram/commands/menu.py:215
|
||||||
msgid "выключены"
|
msgid "выключены"
|
||||||
msgstr "disabled"
|
msgstr "disabled"
|
||||||
|
|
||||||
#: olgram/commands/menu.py:191
|
#: olgram/commands/menu.py:216
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
#| msgid "включены"
|
#| msgid "включены"
|
||||||
msgid "включен"
|
msgid "включен"
|
||||||
msgstr "enabled"
|
msgstr "enabled"
|
||||||
|
|
||||||
#: olgram/commands/menu.py:191
|
#: olgram/commands/menu.py:216 olgram/commands/menu.py:217
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
#| msgid "выключены"
|
#| msgid "выключены"
|
||||||
msgid "выключен"
|
msgid "выключен"
|
||||||
msgstr "disabled"
|
msgstr "disabled"
|
||||||
|
|
||||||
#: olgram/commands/menu.py:192
|
#: olgram/commands/menu.py:217
|
||||||
|
#, fuzzy
|
||||||
|
#| msgid "включены"
|
||||||
|
msgid "включён"
|
||||||
|
msgstr "enabled"
|
||||||
|
|
||||||
|
#: olgram/commands/menu.py:218
|
||||||
|
msgid "да"
|
||||||
|
msgstr "yes"
|
||||||
|
|
||||||
|
#: olgram/commands/menu.py:218
|
||||||
|
msgid "нет"
|
||||||
|
msgstr "no"
|
||||||
|
|
||||||
|
#: olgram/commands/menu.py:219 olgram/commands/menu.py:231
|
||||||
|
msgid "включена"
|
||||||
|
msgstr "enabled"
|
||||||
|
|
||||||
|
#: olgram/commands/menu.py:219 olgram/commands/menu.py:231
|
||||||
|
msgid "выключена"
|
||||||
|
msgstr "disabled"
|
||||||
|
|
||||||
|
#: olgram/commands/menu.py:220
|
||||||
msgid ""
|
msgid ""
|
||||||
"\n"
|
"\n"
|
||||||
" <a href=\"https://olgram.readthedocs.io/ru/latest/options."
|
" <a href=\"https://olgram.readthedocs.io/ru/latest/options."
|
||||||
|
@ -358,6 +396,12 @@ msgid ""
|
||||||
"info\">Данные пользователя</a>: <b>{1}</b>\n"
|
"info\">Данные пользователя</a>: <b>{1}</b>\n"
|
||||||
" <a href=\"https://olgram.readthedocs.io/ru/latest/options."
|
" <a href=\"https://olgram.readthedocs.io/ru/latest/options."
|
||||||
"html#antiflood\">Антифлуд</a>: <b>{2}</b>\n"
|
"html#antiflood\">Антифлуд</a>: <b>{2}</b>\n"
|
||||||
|
" <a href=\"https://olgram.readthedocs.io/ru/latest/options."
|
||||||
|
"html#always_second_message\">Автоответчик всегда</a>: <b>{3}</b>\n"
|
||||||
|
" <a href=\"https://olgram.readthedocs.io/ru/latest/options."
|
||||||
|
"html#thread_interrupt\">Прерывать поток</a>: <b>{4}</b>\n"
|
||||||
|
" <a href=\"https://olgram.readthedocs.io/ru/latest/options."
|
||||||
|
"html#mailing\">Рассылка</a>: <b>{5}</b>\n"
|
||||||
" "
|
" "
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"\n"
|
"\n"
|
||||||
|
@ -366,60 +410,86 @@ msgstr ""
|
||||||
" <a href=\"https://olgram.readthedocs.io/ru/latest/options.html#user-"
|
" <a href=\"https://olgram.readthedocs.io/ru/latest/options.html#user-"
|
||||||
"info\">User data</a>: <b>{1}</b>\n"
|
"info\">User data</a>: <b>{1}</b>\n"
|
||||||
" <a href=\"https://olgram.readthedocs.io/ru/latest/options."
|
" <a href=\"https://olgram.readthedocs.io/ru/latest/options."
|
||||||
"html#antiflood\">Antiflood</a>: <b>{2}</b>"
|
"html#antiflood\">Anti-flood</a>: <b>{2}</b>\n"
|
||||||
|
" <a href=\"https://olgram.readthedocs.io/ru/latest/options."
|
||||||
|
"html#always_second_message\">Autorespond always</a>: <b>{3}</b>\n"
|
||||||
|
" <a href=\"https://olgram.readthedocs.io/ru/latest/options."
|
||||||
|
"html#thread_interrupt\">Interrupt threads</a>: <b>{4}</b>\n"
|
||||||
|
" <a href=\"https://olgram.readthedocs.io/ru/latest/options."
|
||||||
|
"html#mailing\">Mailing</a>: <b>{5}</b>\n"
|
||||||
|
" "
|
||||||
|
|
||||||
#: olgram/commands/menu.py:199
|
#: olgram/commands/menu.py:232
|
||||||
msgid "включена"
|
|
||||||
msgstr "enabled"
|
|
||||||
|
|
||||||
#: olgram/commands/menu.py:199
|
|
||||||
msgid "выключена"
|
|
||||||
msgstr "disabled"
|
|
||||||
|
|
||||||
#: olgram/commands/menu.py:200
|
|
||||||
msgid "Olgram подпись: <b>{0}</b>"
|
msgid "Olgram подпись: <b>{0}</b>"
|
||||||
msgstr "Olgram signature: <b>{0}</b>"
|
msgstr "Olgram signature: <b>{0}</b>"
|
||||||
|
|
||||||
#: olgram/commands/menu.py:210 olgram/commands/menu.py:272
|
#: olgram/commands/menu.py:259 olgram/commands/menu.py:421
|
||||||
#: olgram/commands/menu.py:314
|
#: olgram/commands/menu.py:480
|
||||||
msgid "<< Завершить редактирование"
|
msgid "<< Завершить редактирование"
|
||||||
msgstr "<< Finish editing"
|
msgstr "<< Finish editing"
|
||||||
|
|
||||||
#: olgram/commands/menu.py:214
|
#: olgram/commands/menu.py:263
|
||||||
msgid "Автоответчик"
|
msgid "Автоответчик"
|
||||||
msgstr "Autoresponder"
|
msgstr "Autoresponder"
|
||||||
|
|
||||||
#: olgram/commands/menu.py:219 olgram/commands/menu.py:286
|
#: olgram/commands/menu.py:268 olgram/commands/menu.py:435
|
||||||
msgid "Сбросить текст"
|
msgid "Сбросить текст"
|
||||||
msgstr "Reset text"
|
msgstr "Reset text"
|
||||||
|
|
||||||
#: olgram/commands/menu.py:224
|
#: olgram/commands/menu.py:273 olgram/commands/menu.py:440
|
||||||
|
msgid "[все языки]"
|
||||||
|
msgstr "[all languages]"
|
||||||
|
|
||||||
|
#: olgram/commands/menu.py:290
|
||||||
msgid ""
|
msgid ""
|
||||||
"\n"
|
"\n"
|
||||||
" Сейчас вы редактируете текст, который отправляется после того, как "
|
" Сейчас вы редактируете текст, который отправляется после того, как "
|
||||||
"пользователь отправит вашему боту @{0}\n"
|
"пользователь отправит вашему боту @{0}\n"
|
||||||
" команду /start\n"
|
" команду /start\n"
|
||||||
"\n"
|
"\n"
|
||||||
" Текущий текст:\n"
|
" Текущий текст{2}:\n"
|
||||||
" <pre>\n"
|
" <pre>{1}</pre>\n"
|
||||||
" {1}\n"
|
|
||||||
" </pre>\n"
|
|
||||||
" Отправьте сообщение, чтобы изменить текст.\n"
|
" Отправьте сообщение, чтобы изменить текст.\n"
|
||||||
" "
|
" "
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: olgram/commands/menu.py:300 olgram/commands/menu.py:467
|
||||||
|
msgid " (для языка {0})"
|
||||||
|
msgstr " (for language {0})"
|
||||||
|
|
||||||
|
#: olgram/commands/menu.py:313
|
||||||
|
msgid "<< Отменить рассылку"
|
||||||
|
msgstr "<< Cancel"
|
||||||
|
|
||||||
|
#: olgram/commands/menu.py:317
|
||||||
|
msgid ""
|
||||||
"\n"
|
"\n"
|
||||||
" You are now editing the text that is sent after the user sends your bot "
|
" Напишите сообщение, которое нужно разослать всем подписчикам вашего бота "
|
||||||
"@{0}\n"
|
"@{0}. \n"
|
||||||
" /start command.\n"
|
" У сообщения будет до {1} получателей. \n"
|
||||||
|
" Учтите, что\n"
|
||||||
|
" 1. Рассылается только одно сообщение за раз (в т.ч. только одна "
|
||||||
|
"картинка)\n"
|
||||||
|
" 2. Когда рассылка запущена, её нельзя отменить \n"
|
||||||
|
" "
|
||||||
|
msgstr ""
|
||||||
"\n"
|
"\n"
|
||||||
" Current text:\n"
|
" Please send mailing message to send all @{0} subscribers. \n"
|
||||||
" <pre>\n"
|
" Message will have up to {1} recipients. \n"
|
||||||
" {1}\n"
|
" Take note:\n"
|
||||||
" </pre>\n"
|
" 1. Only one message per mailing\n"
|
||||||
" Send a message to change the text.\n"
|
" 2.Mailing cant be interrupted \n"
|
||||||
" "
|
" "
|
||||||
|
|
||||||
#: olgram/commands/menu.py:251
|
#: olgram/commands/menu.py:367
|
||||||
|
msgid "Не удалось загрузить файл (слишком большой размер?)"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: olgram/commands/menu.py:374
|
||||||
|
msgid "Да, начать рассылку"
|
||||||
|
msgstr "Yes, start mailing"
|
||||||
|
|
||||||
|
#: olgram/commands/menu.py:394
|
||||||
msgid ""
|
msgid ""
|
||||||
"\n"
|
"\n"
|
||||||
" Статистика по боту @{0}\n"
|
" Статистика по боту @{0}\n"
|
||||||
|
@ -439,45 +509,32 @@ msgstr ""
|
||||||
" Banned users: <b>{4}</b>\n"
|
" Banned users: <b>{4}</b>\n"
|
||||||
" "
|
" "
|
||||||
|
|
||||||
#: olgram/commands/menu.py:276
|
#: olgram/commands/menu.py:425
|
||||||
msgid "Предыдущий текст"
|
msgid "Предыдущий текст"
|
||||||
msgstr "Previous text"
|
msgstr "Previous text"
|
||||||
|
|
||||||
#: olgram/commands/menu.py:281
|
#: olgram/commands/menu.py:430
|
||||||
msgid "Шаблоны ответов..."
|
msgid "Шаблоны ответов..."
|
||||||
msgstr "Answer templates..."
|
msgstr "Answer templates..."
|
||||||
|
|
||||||
#: olgram/commands/menu.py:291
|
#: olgram/commands/menu.py:457
|
||||||
msgid ""
|
msgid ""
|
||||||
"\n"
|
"\n"
|
||||||
" Сейчас вы редактируете текст автоответчика. Это сообщение отправляется в "
|
" Сейчас вы редактируете текст автоответчика. Это сообщение отправляется в "
|
||||||
"ответ на все входящие сообщения @{0} автоматически. По умолчанию оно "
|
"ответ на все входящие сообщения @{0} автоматически. По умолчанию оно "
|
||||||
"отключено.\n"
|
"отключено.\n"
|
||||||
"\n"
|
"\n"
|
||||||
" Текущий текст:\n"
|
" Текущий текст{2}:\n"
|
||||||
" <pre>"
|
" <pre>{1}</pre>\n"
|
||||||
" {1}\n"
|
|
||||||
" </pre>\n"
|
|
||||||
" Отправьте сообщение, чтобы изменить текст.\n"
|
" Отправьте сообщение, чтобы изменить текст.\n"
|
||||||
" "
|
" "
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"\n"
|
|
||||||
" You are now editing the autoresponder text. This message is sent in "
|
|
||||||
"response to all incoming @{0} messages automatically. It is disabled by "
|
|
||||||
"default.\n"
|
|
||||||
"\n"
|
|
||||||
" Current text:\n"
|
|
||||||
" <pre>\n"
|
|
||||||
" {1}\n"
|
|
||||||
" </pre>\n"
|
|
||||||
" Send a message to change the text.\n"
|
|
||||||
" "
|
|
||||||
|
|
||||||
#: olgram/commands/menu.py:301
|
#: olgram/commands/menu.py:466
|
||||||
msgid "(отключено)"
|
msgid "отключено"
|
||||||
msgstr "(disabled)"
|
msgstr "disabled"
|
||||||
|
|
||||||
#: olgram/commands/menu.py:318
|
#: olgram/commands/menu.py:484
|
||||||
msgid ""
|
msgid ""
|
||||||
"\n"
|
"\n"
|
||||||
" Сейчас вы редактируете шаблоны ответов для @{0}. Текущие шаблоны:\n"
|
" Сейчас вы редактируете шаблоны ответов для @{0}. Текущие шаблоны:\n"
|
||||||
|
@ -503,30 +560,50 @@ msgstr ""
|
||||||
" To remove a template from the list, send its number in the list (for "
|
" To remove a template from the list, send its number in the list (for "
|
||||||
"example, 4) "
|
"example, 4) "
|
||||||
|
|
||||||
#: olgram/commands/menu.py:337
|
#: olgram/commands/menu.py:503
|
||||||
msgid "(нет шаблонов)"
|
msgid "(нет шаблонов)"
|
||||||
msgstr "(no templates)"
|
msgstr "(no templates)"
|
||||||
|
|
||||||
#: olgram/commands/menu.py:376
|
#: olgram/commands/menu.py:565
|
||||||
msgid "У вас нет шаблонов, чтобы их удалять"
|
msgid "У вас нет шаблонов, чтобы их удалять"
|
||||||
msgstr "You don't have templates to delete them"
|
msgstr "You don't have templates to delete them"
|
||||||
|
|
||||||
#: olgram/commands/menu.py:378
|
#: olgram/commands/menu.py:567
|
||||||
msgid "Неправильное число. Чтобы удалить шаблон, введите число от 0 до {0}"
|
msgid "Неправильное число. Чтобы удалить шаблон, введите число от 0 до {0}"
|
||||||
msgstr "To delete a template, enter a number between 0 and {0}"
|
msgstr "To delete a template, enter a number between 0 and {0}"
|
||||||
|
|
||||||
#: olgram/commands/menu.py:386
|
#: olgram/commands/menu.py:575
|
||||||
msgid "У вашего бота уже слишком много шаблонов"
|
msgid "У вашего бота уже слишком много шаблонов"
|
||||||
msgstr "Your bot already has too many templates"
|
msgstr "Your bot already has too many templates"
|
||||||
|
|
||||||
#: olgram/commands/menu.py:390
|
#: olgram/commands/menu.py:579
|
||||||
msgid "Такой текст уже есть в списке шаблонов"
|
msgid "Такой текст уже есть в списке шаблонов"
|
||||||
msgstr "This text is already in the list of templates"
|
msgstr "This text is already in the list of templates"
|
||||||
|
|
||||||
#: olgram/commands/menu.py:408
|
#: olgram/commands/menu.py:597
|
||||||
msgid "У вас нет прав на этого бота"
|
msgid "У вас нет прав на этого бота"
|
||||||
msgstr "You have no permissions to this bot"
|
msgstr "You have no permissions to this bot"
|
||||||
|
|
||||||
|
#: olgram/commands/menu.py:617 olgram/commands/menu.py:643
|
||||||
|
msgid "Рассылка была совсем недавно, подождите немного"
|
||||||
|
msgstr "Mailing was recently, wait a bit please"
|
||||||
|
|
||||||
|
#: olgram/commands/menu.py:619 olgram/commands/menu.py:645
|
||||||
|
msgid "Нет пользователей для рассылки"
|
||||||
|
msgstr "No users for mailing"
|
||||||
|
|
||||||
|
#: olgram/commands/menu.py:647
|
||||||
|
msgid "Рассылка запущена"
|
||||||
|
msgstr "Mailing started"
|
||||||
|
|
||||||
|
#: olgram/commands/menu.py:649
|
||||||
|
msgid "Рассылка завершена, отправлено {0} сообщений"
|
||||||
|
msgstr "Mailing completed, {0} messages sent"
|
||||||
|
|
||||||
|
#: olgram/commands/menu.py:651
|
||||||
|
msgid "Устарело, создайте новую рассылку"
|
||||||
|
msgstr "Expired, please create new mailing"
|
||||||
|
|
||||||
#: olgram/commands/promo.py:27
|
#: olgram/commands/promo.py:27
|
||||||
msgid ""
|
msgid ""
|
||||||
"Новый промокод\n"
|
"Новый промокод\n"
|
||||||
|
@ -551,8 +628,8 @@ msgstr "Promotion code withdrawn"
|
||||||
msgid ""
|
msgid ""
|
||||||
"Укажите аргумент: промокод. Например: <pre>/setpromo my-promo-code</pre>"
|
"Укажите аргумент: промокод. Например: <pre>/setpromo my-promo-code</pre>"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Specify the argument: promo code. For example: <pre>/setpromo my-promo-"
|
"Specify the argument: promo code. For example: <pre>/setpromo my-promo-code</"
|
||||||
"code</pre>"
|
"pre>"
|
||||||
|
|
||||||
#: olgram/commands/promo.py:78 olgram/commands/promo.py:82
|
#: olgram/commands/promo.py:78 olgram/commands/promo.py:82
|
||||||
msgid "Промокод не найден"
|
msgid "Промокод не найден"
|
||||||
|
@ -619,87 +696,102 @@ msgstr ""
|
||||||
" Write your question and we will answer you shortly.\n"
|
" Write your question and we will answer you shortly.\n"
|
||||||
" "
|
" "
|
||||||
|
|
||||||
#: olgram/utils/permissions.py:40
|
#: olgram/utils/permissions.py:41
|
||||||
msgid "Владелец бота ограничил доступ к этому функционалу 😞"
|
msgid "Владелец бота ограничил доступ к этому функционалу 😞"
|
||||||
msgstr "The bot owner has restricted access to this functionality 😞"
|
msgstr "The bot owner has restricted access to this functionality 😞"
|
||||||
|
|
||||||
#: olgram/utils/permissions.py:52
|
#: olgram/utils/permissions.py:53
|
||||||
msgid "Владелец бота ограничил доступ к этому функционалу😞"
|
msgid "Владелец бота ограничил доступ к этому функционалу😞"
|
||||||
msgstr "The owner of the bot has restricted access to this function😞"
|
msgstr "The owner of the bot has restricted access to this function😞"
|
||||||
|
|
||||||
#: server/custom.py:55
|
#: server/custom.py:57
|
||||||
msgid ""
|
msgid ""
|
||||||
"<b>Политика конфиденциальности</b>\n"
|
"<b>Политика конфиденциальности</b>\n"
|
||||||
"\n"
|
"\n"
|
||||||
"Этот бот не хранит ваши сообщения, имя пользователя и @username. При "
|
"Этот бот не хранит ваши сообщения, имя пользователя и @username. При "
|
||||||
"отправке сообщения (кроме команд /start и /security_policy) ваш "
|
"отправке сообщения (кроме команд /start и /security_policy) ваш "
|
||||||
"идентификатор пользователя записывается в кеш на некоторое время и потом "
|
"идентификатор пользователя записывается в кеш на некоторое время и потом "
|
||||||
"удаляется из кеша. Этот идентификатор используется только для общения с "
|
"удаляется из кеша. Этот идентификатор используется для общения с "
|
||||||
"оператором; боты Olgram не делают массовых рассылок.\n"
|
"оператором.\n"
|
||||||
"\n"
|
"\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"<b>Privacy Policy</b>.\n"
|
"<b>Privacy Policy</b>.\n"
|
||||||
"\n"
|
"\n"
|
||||||
"This bot does not store your messages, username and @username. When you send "
|
"This bot does not store your messages, username and @username. When you send "
|
||||||
"a message (except for /start and /security_policy), your username is cached "
|
"a message (except for /start and /security_policy), your username is cached "
|
||||||
"for a while and then deleted from the cache. This ID is only used for "
|
"for a while and then deleted from the cache. This ID is used for "
|
||||||
"communicating with the operator; Olgram bots do not do mass mailings.\n"
|
"communicating with the operator\n"
|
||||||
"\n"
|
"\n"
|
||||||
|
|
||||||
#: server/custom.py:61
|
#: server/custom.py:62
|
||||||
msgid ""
|
msgid ""
|
||||||
"При отправке сообщения (кроме команд /start и /security_policy) оператор "
|
"При отправке сообщения (кроме команд /start и /security_policy) оператор "
|
||||||
"<b>видит</b> ваши имя пользователя, @username и идентификатор пользователя в "
|
"<b>видит</b> ваши имя пользователя, @username и идентификатор пользователя в "
|
||||||
"силу настроек, которые оператор указал при создании бота."
|
"силу настроек, которые оператор указал при создании бота.\n"
|
||||||
|
"\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"When sending a message (except /start and /security_policy), the operator "
|
"When sending a message (except /start and /security_policy), the operator "
|
||||||
"<b>sees</b> your username, @username and user ID by virtue of the settings "
|
"<b>sees</b> your username, @username and user ID by virtue of the settings "
|
||||||
"that the operator specified when creating the bot."
|
"that the operator specified when creating the bot.\n"
|
||||||
|
"\n"
|
||||||
|
|
||||||
#: server/custom.py:65
|
#: server/custom.py:66
|
||||||
msgid ""
|
msgid ""
|
||||||
"В зависимости от ваших настроек конфиденциальности Telegram, оператор может "
|
"В зависимости от ваших настроек конфиденциальности Telegram, оператор может "
|
||||||
"видеть ваш username, имя пользователя и другую информацию."
|
"видеть ваш username, имя пользователя и другую информацию.\n"
|
||||||
|
"\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Depending on your Telegram privacy settings, the operator may see your "
|
"Depending on your Telegram privacy settings, the operator may see your "
|
||||||
"username, username and other information."
|
"username, username and other information.\n"
|
||||||
|
"\n"
|
||||||
|
|
||||||
#: server/custom.py:76
|
#: server/custom.py:70
|
||||||
|
msgid ""
|
||||||
|
"В этом боте включена массовая рассылка в силу настроек, которые оператор "
|
||||||
|
"указал при создании бота. Ваш идентификатор пользователя может быть записан "
|
||||||
|
"в базу данных на долгое время"
|
||||||
|
msgstr "Mailing enabled for this bot"
|
||||||
|
|
||||||
|
#: server/custom.py:73
|
||||||
|
msgid "В этом боте нет массовой рассылки сообщений"
|
||||||
|
msgstr "Mailing disabled for this bot"
|
||||||
|
|
||||||
|
#: server/custom.py:83
|
||||||
msgid "Сообщение от пользователя "
|
msgid "Сообщение от пользователя "
|
||||||
msgstr "Message from the user "
|
msgstr "Message from the user "
|
||||||
|
|
||||||
#: server/custom.py:135
|
#: server/custom.py:157
|
||||||
msgid "Вы заблокированы в этом боте"
|
msgid "Вы заблокированы в этом боте"
|
||||||
msgstr "You are blocked in this bot"
|
msgstr "You are blocked in this bot"
|
||||||
|
|
||||||
#: server/custom.py:141
|
#: server/custom.py:163
|
||||||
msgid "Слишком много сообщений, подождите одну минуту"
|
msgid "Слишком много сообщений, подождите одну минуту"
|
||||||
msgstr "Too many messages, wait one minute"
|
msgstr "Too many messages, wait one minute"
|
||||||
|
|
||||||
#: server/custom.py:148
|
#: server/custom.py:170
|
||||||
msgid "Не удаётся связаться с владельцем бота"
|
msgid "Не удаётся связаться с владельцем бота"
|
||||||
msgstr "Cannot contact the owner of the bot"
|
msgstr "Cannot contact the owner of the bot"
|
||||||
|
|
||||||
#: server/custom.py:179
|
#: server/custom.py:202
|
||||||
msgid ""
|
msgid ""
|
||||||
"<i>Невозможно переслать сообщение: автор не найден (сообщение слишком "
|
"<i>Невозможно переслать сообщение: автор не найден (сообщение слишком "
|
||||||
"старое?)</i>"
|
"старое?)</i>"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"<i>Cannot forward this message: author not found (message too old?)</i>"
|
"<i>Cannot forward this message: author not found (message too old?)</i>"
|
||||||
|
|
||||||
#: server/custom.py:187
|
#: server/custom.py:210
|
||||||
msgid "Пользователь заблокирован"
|
msgid "Пользователь заблокирован"
|
||||||
msgstr "User is blocked"
|
msgstr "User is blocked"
|
||||||
|
|
||||||
#: server/custom.py:192
|
#: server/custom.py:215
|
||||||
msgid "Пользователь не был забанен"
|
msgid "Пользователь не был забанен"
|
||||||
msgstr "The user was not banned"
|
msgstr "The user was not banned"
|
||||||
|
|
||||||
#: server/custom.py:195
|
#: server/custom.py:218
|
||||||
msgid "Пользователь разбанен"
|
msgid "Пользователь разбанен"
|
||||||
msgstr "A user has been unlocked"
|
msgstr "A user has been unlocked"
|
||||||
|
|
||||||
#: server/custom.py:200
|
#: server/custom.py:223
|
||||||
msgid "<i>Невозможно переслать сообщение (автор заблокировал бота?)</i>"
|
msgid "<i>Невозможно переслать сообщение (автор заблокировал бота?)</i>"
|
||||||
msgstr "<i>Cannot forward the message (has the author blocked the bot?)</i>"
|
msgstr "<i>Cannot forward the message (has the author blocked the bot?)</i>"
|
||||||
|
|
||||||
|
@ -711,11 +803,11 @@ msgstr "(Re)launch the bot"
|
||||||
msgid "Политика конфиденциальности"
|
msgid "Политика конфиденциальности"
|
||||||
msgstr "Privacy Policy"
|
msgstr "Privacy Policy"
|
||||||
|
|
||||||
msgid ""
|
#~ msgid ""
|
||||||
"\n"
|
#~ "\n"
|
||||||
"\n"
|
#~ "\n"
|
||||||
"Этот бот создан с помощью @OlgramBot"
|
#~ "Этот бот создан с помощью @OlgramBot"
|
||||||
msgstr ""
|
#~ msgstr ""
|
||||||
"\n"
|
#~ "\n"
|
||||||
"\n"
|
#~ "\n"
|
||||||
"This bot was created using @OlgramBot"
|
#~ "This bot was created using @OlgramBot"
|
||||||
|
|
|
@ -5,8 +5,8 @@
|
||||||
msgid ""
|
msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: \n"
|
"Project-Id-Version: \n"
|
||||||
"POT-Creation-Date: 2022-09-02 05:07+0400\n"
|
"POT-Creation-Date: 2024-03-02 19:47+0400\n"
|
||||||
"PO-Revision-Date: 2022-09-02 05:12+0400\n"
|
"PO-Revision-Date: 2024-03-02 19:48+0400\n"
|
||||||
"Last-Translator: \n"
|
"Last-Translator: \n"
|
||||||
"Language-Team: \n"
|
"Language-Team: \n"
|
||||||
"Language: uk_UA\n"
|
"Language: uk_UA\n"
|
||||||
|
@ -16,7 +16,7 @@ msgstr ""
|
||||||
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
|
"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && "
|
||||||
"n%10<=4 && (n%100<12 || n%100>14) ? 1 : 2);\n"
|
"n%10<=4 && (n%100<12 || n%100>14) ? 1 : 2);\n"
|
||||||
"Generated-By: pygettext.py 1.5\n"
|
"Generated-By: pygettext.py 1.5\n"
|
||||||
"X-Generator: Poedit 3.1\n"
|
"X-Generator: Poedit 3.4.2\n"
|
||||||
|
|
||||||
#: olgram/commands/admin.py:21 olgram/commands/info.py:21
|
#: olgram/commands/admin.py:21 olgram/commands/info.py:21
|
||||||
#: olgram/commands/promo.py:23 olgram/commands/promo.py:39
|
#: olgram/commands/promo.py:23 olgram/commands/promo.py:39
|
||||||
|
@ -63,27 +63,27 @@ msgstr "Скасувати"
|
||||||
msgid "Отправлено"
|
msgid "Отправлено"
|
||||||
msgstr "Надіслано"
|
msgstr "Надіслано"
|
||||||
|
|
||||||
#: olgram/commands/bot_actions.py:22
|
#: olgram/commands/bot_actions.py:27
|
||||||
msgid "Бот удалён"
|
msgid "Бот удалён"
|
||||||
msgstr "Бот видалений"
|
msgstr "Бот видалений"
|
||||||
|
|
||||||
#: olgram/commands/bot_actions.py:38 olgram/commands/bot_actions.py:50
|
#: olgram/commands/bot_actions.py:49 olgram/commands/bot_actions.py:67
|
||||||
msgid "Текст сброшен"
|
msgid "Текст сброшен"
|
||||||
msgstr "Текст скинутий"
|
msgstr "Текст скинутий"
|
||||||
|
|
||||||
#: olgram/commands/bot_actions.py:64
|
#: olgram/commands/bot_actions.py:81
|
||||||
msgid "Выбран личный чат"
|
msgid "Выбран личный чат"
|
||||||
msgstr "Вибраний особистий чат"
|
msgstr "Вибраний особистий чат"
|
||||||
|
|
||||||
#: olgram/commands/bot_actions.py:77
|
#: olgram/commands/bot_actions.py:94
|
||||||
msgid "Бот вышел из чатов"
|
msgid "Бот вышел из чатов"
|
||||||
msgstr "Бот вийшов із чатів"
|
msgstr "Бот вийшов із чатів"
|
||||||
|
|
||||||
#: olgram/commands/bot_actions.py:83
|
#: olgram/commands/bot_actions.py:100
|
||||||
msgid "Нельзя привязать бота к этому чату"
|
msgid "Нельзя привязать бота к этому чату"
|
||||||
msgstr "Не можна прив'язати робота до цього чату"
|
msgstr "Не можна прив'язати робота до цього чату"
|
||||||
|
|
||||||
#: olgram/commands/bot_actions.py:87
|
#: olgram/commands/bot_actions.py:104
|
||||||
msgid "Выбран чат {0}"
|
msgid "Выбран чат {0}"
|
||||||
msgstr "Вибраний чат {0}"
|
msgstr "Вибраний чат {0}"
|
||||||
|
|
||||||
|
@ -198,7 +198,11 @@ msgstr "Вихідних повідомлень у всіх роботів: {0}\
|
||||||
msgid "Промо-кодов выдано: {0}\n"
|
msgid "Промо-кодов выдано: {0}\n"
|
||||||
msgstr "Промо-кодів видано: {0}\n"
|
msgstr "Промо-кодів видано: {0}\n"
|
||||||
|
|
||||||
#: olgram/commands/menu.py:31
|
#: olgram/commands/info.py:40
|
||||||
|
msgid "Рекламную плашку выключили: {0}\n"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: olgram/commands/menu.py:33
|
||||||
msgid ""
|
msgid ""
|
||||||
"\n"
|
"\n"
|
||||||
" У вас нет добавленных ботов.\n"
|
" У вас нет добавленных ботов.\n"
|
||||||
|
@ -213,25 +217,25 @@ msgstr ""
|
||||||
" \n"
|
" \n"
|
||||||
" "
|
" "
|
||||||
|
|
||||||
#: olgram/commands/menu.py:46
|
#: olgram/commands/menu.py:48
|
||||||
msgid "Ваши боты"
|
msgid "Ваши боты"
|
||||||
msgstr "Ваші боти"
|
msgstr "Ваші боти"
|
||||||
|
|
||||||
#: olgram/commands/menu.py:67
|
#: olgram/commands/menu.py:69
|
||||||
msgid "Личные сообщения"
|
msgid "Личные сообщения"
|
||||||
msgstr "Особисті повідомлення"
|
msgstr "Особисті повідомлення"
|
||||||
|
|
||||||
#: olgram/commands/menu.py:72
|
#: olgram/commands/menu.py:74
|
||||||
msgid "❗️ Выйти из всех чатов"
|
msgid "❗️ Выйти из всех чатов"
|
||||||
msgstr "❗️ Вийти зі всіх чатів"
|
msgstr "❗️ Вийти зі всіх чатів"
|
||||||
|
|
||||||
#: olgram/commands/menu.py:77 olgram/commands/menu.py:122
|
#: olgram/commands/menu.py:79 olgram/commands/menu.py:124
|
||||||
#: olgram/commands/menu.py:148 olgram/commands/menu.py:184
|
#: olgram/commands/menu.py:156 olgram/commands/menu.py:209
|
||||||
#: olgram/commands/menu.py:247
|
#: olgram/commands/menu.py:390
|
||||||
msgid "<< Назад"
|
msgid "<< Назад"
|
||||||
msgstr "<< Назад"
|
msgstr "<< Назад"
|
||||||
|
|
||||||
#: olgram/commands/menu.py:83
|
#: olgram/commands/menu.py:85
|
||||||
msgid ""
|
msgid ""
|
||||||
"\n"
|
"\n"
|
||||||
" Этот бот не добавлен в чаты, поэтому все сообщения будут приходить "
|
" Этот бот не добавлен в чаты, поэтому все сообщения будут приходить "
|
||||||
|
@ -254,7 +258,7 @@ msgstr ""
|
||||||
" \n"
|
" \n"
|
||||||
" "
|
" "
|
||||||
|
|
||||||
#: olgram/commands/menu.py:90
|
#: olgram/commands/menu.py:92
|
||||||
msgid ""
|
msgid ""
|
||||||
"\n"
|
"\n"
|
||||||
" В этом разделе вы можете привязать бота @{0} к чату.\n"
|
" В этом разделе вы можете привязать бота @{0} к чату.\n"
|
||||||
|
@ -267,27 +271,31 @@ msgstr ""
|
||||||
" \n"
|
" \n"
|
||||||
" "
|
" "
|
||||||
|
|
||||||
#: olgram/commands/menu.py:102
|
#: olgram/commands/menu.py:104
|
||||||
msgid "Текст"
|
msgid "Текст"
|
||||||
msgstr "Текст"
|
msgstr "Текст"
|
||||||
|
|
||||||
#: olgram/commands/menu.py:107
|
#: olgram/commands/menu.py:109
|
||||||
msgid "Чат"
|
msgid "Чат"
|
||||||
msgstr "Чат"
|
msgstr "Чат"
|
||||||
|
|
||||||
#: olgram/commands/menu.py:112
|
#: olgram/commands/menu.py:114
|
||||||
msgid "Удалить бот"
|
msgid "Удалить бот"
|
||||||
msgstr "Видалити бот"
|
msgstr "Видалити бот"
|
||||||
|
|
||||||
#: olgram/commands/menu.py:117
|
#: olgram/commands/menu.py:119
|
||||||
msgid "Статистика"
|
msgid "Статистика"
|
||||||
msgstr "Статистика"
|
msgstr "Статистика"
|
||||||
|
|
||||||
#: olgram/commands/menu.py:126
|
#: olgram/commands/menu.py:128
|
||||||
msgid "Опции"
|
msgid "Опции"
|
||||||
msgstr "Опції"
|
msgstr "Опції"
|
||||||
|
|
||||||
#: olgram/commands/menu.py:131
|
#: olgram/commands/menu.py:134 olgram/commands/menu.py:190
|
||||||
|
msgid "Рассылка"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: olgram/commands/menu.py:139
|
||||||
msgid ""
|
msgid ""
|
||||||
"\n"
|
"\n"
|
||||||
" Управление ботом @{0}.\n"
|
" Управление ботом @{0}.\n"
|
||||||
|
@ -305,11 +313,11 @@ msgstr ""
|
||||||
" @civsocit_feedback_bot\n"
|
" @civsocit_feedback_bot\n"
|
||||||
" "
|
" "
|
||||||
|
|
||||||
#: olgram/commands/menu.py:143
|
#: olgram/commands/menu.py:151
|
||||||
msgid "Да, удалить бот"
|
msgid "Да, удалить бот"
|
||||||
msgstr "Так, видалити бот"
|
msgstr "Так, видалити бот"
|
||||||
|
|
||||||
#: olgram/commands/menu.py:152
|
#: olgram/commands/menu.py:160
|
||||||
msgid ""
|
msgid ""
|
||||||
"\n"
|
"\n"
|
||||||
" Вы уверены, что хотите удалить бота @{0}?\n"
|
" Вы уверены, что хотите удалить бота @{0}?\n"
|
||||||
|
@ -319,43 +327,75 @@ msgstr ""
|
||||||
" Ви впевнені, що хочете видалити бота @{0}?\n"
|
" Ви впевнені, що хочете видалити бота @{0}?\n"
|
||||||
" "
|
" "
|
||||||
|
|
||||||
#: olgram/commands/menu.py:161
|
#: olgram/commands/menu.py:169
|
||||||
msgid "Потоки сообщений"
|
msgid "Потоки сообщений"
|
||||||
msgstr "Потоки повідомлень"
|
msgstr "Потоки повідомлень"
|
||||||
|
|
||||||
#: olgram/commands/menu.py:166
|
#: olgram/commands/menu.py:174
|
||||||
msgid "Данные пользователя"
|
msgid "Данные пользователя"
|
||||||
msgstr "Дані користувача"
|
msgstr "Дані користувача"
|
||||||
|
|
||||||
#: olgram/commands/menu.py:171
|
#: olgram/commands/menu.py:179
|
||||||
msgid "Антифлуд"
|
msgid "Антифлуд"
|
||||||
msgstr "Антифлуд"
|
msgstr "Антифлуд"
|
||||||
|
|
||||||
#: olgram/commands/menu.py:178
|
#: olgram/commands/menu.py:184
|
||||||
|
#, fuzzy
|
||||||
|
#| msgid "Автоответчик"
|
||||||
|
msgid "Автоответчик всегда"
|
||||||
|
msgstr "Автовідповідач"
|
||||||
|
|
||||||
|
#: olgram/commands/menu.py:195
|
||||||
|
msgid "Прерывать поток"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: olgram/commands/menu.py:203
|
||||||
msgid "Olgram подпись"
|
msgid "Olgram подпись"
|
||||||
msgstr "Olgram підпис"
|
msgstr "Olgram підпис"
|
||||||
|
|
||||||
#: olgram/commands/menu.py:189 olgram/commands/menu.py:190
|
#: olgram/commands/menu.py:214 olgram/commands/menu.py:215
|
||||||
msgid "включены"
|
msgid "включены"
|
||||||
msgstr "включені"
|
msgstr "включені"
|
||||||
|
|
||||||
#: olgram/commands/menu.py:189 olgram/commands/menu.py:190
|
#: olgram/commands/menu.py:214 olgram/commands/menu.py:215
|
||||||
msgid "выключены"
|
msgid "выключены"
|
||||||
msgstr "вимкнені"
|
msgstr "вимкнені"
|
||||||
|
|
||||||
#: olgram/commands/menu.py:191
|
#: olgram/commands/menu.py:216
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
#| msgid "включены"
|
#| msgid "включены"
|
||||||
msgid "включен"
|
msgid "включен"
|
||||||
msgstr "включені"
|
msgstr "включені"
|
||||||
|
|
||||||
#: olgram/commands/menu.py:191
|
#: olgram/commands/menu.py:216 olgram/commands/menu.py:217
|
||||||
#, fuzzy
|
#, fuzzy
|
||||||
#| msgid "выключены"
|
#| msgid "выключены"
|
||||||
msgid "выключен"
|
msgid "выключен"
|
||||||
msgstr "вимкнені"
|
msgstr "вимкнені"
|
||||||
|
|
||||||
#: olgram/commands/menu.py:192
|
#: olgram/commands/menu.py:217
|
||||||
|
#, fuzzy
|
||||||
|
#| msgid "включены"
|
||||||
|
msgid "включён"
|
||||||
|
msgstr "включені"
|
||||||
|
|
||||||
|
#: olgram/commands/menu.py:218
|
||||||
|
msgid "да"
|
||||||
|
msgstr "Ча"
|
||||||
|
|
||||||
|
#: olgram/commands/menu.py:218
|
||||||
|
msgid "нет"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: olgram/commands/menu.py:219 olgram/commands/menu.py:231
|
||||||
|
msgid "включена"
|
||||||
|
msgstr "включена"
|
||||||
|
|
||||||
|
#: olgram/commands/menu.py:219 olgram/commands/menu.py:231
|
||||||
|
msgid "выключена"
|
||||||
|
msgstr "вимкнена"
|
||||||
|
|
||||||
|
#: olgram/commands/menu.py:220
|
||||||
msgid ""
|
msgid ""
|
||||||
"\n"
|
"\n"
|
||||||
" <a href=\"https://olgram.readthedocs.io/ru/latest/options."
|
" <a href=\"https://olgram.readthedocs.io/ru/latest/options."
|
||||||
|
@ -364,65 +404,81 @@ msgid ""
|
||||||
"info\">Данные пользователя</a>: <b>{1}</b>\n"
|
"info\">Данные пользователя</a>: <b>{1}</b>\n"
|
||||||
" <a href=\"https://olgram.readthedocs.io/ru/latest/options."
|
" <a href=\"https://olgram.readthedocs.io/ru/latest/options."
|
||||||
"html#antiflood\">Антифлуд</a>: <b>{2}</b>\n"
|
"html#antiflood\">Антифлуд</a>: <b>{2}</b>\n"
|
||||||
|
" <a href=\"https://olgram.readthedocs.io/ru/latest/options."
|
||||||
|
"html#always_second_message\">Автоответчик всегда</a>: <b>{3}</b>\n"
|
||||||
|
" <a href=\"https://olgram.readthedocs.io/ru/latest/options."
|
||||||
|
"html#thread_interrupt\">Прерывать поток</a>: <b>{4}</b>\n"
|
||||||
|
" <a href=\"https://olgram.readthedocs.io/ru/latest/options."
|
||||||
|
"html#mailing\">Рассылка</a>: <b>{5}</b>\n"
|
||||||
" "
|
" "
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"\n"
|
|
||||||
" <a href=\"https://olgram.readthedocs.io/ru/latest/options."
|
|
||||||
"html#threads\">Потоки повідомлень</a>: <b>{0}</b>\n"
|
|
||||||
" <a href=\"https://olgram.readthedocs.io/ru/latest/options.html#user-"
|
|
||||||
"info\">Дані користувача</a>: <b>{1}</b>\n"
|
|
||||||
" <a href=\"https://olgram.readthedocs.io/ru/latest/options."
|
|
||||||
"html#antiflood\">Anti-flood</a>: <b>{2}</b>"
|
|
||||||
|
|
||||||
#: olgram/commands/menu.py:199
|
#: olgram/commands/menu.py:232
|
||||||
msgid "включена"
|
|
||||||
msgstr "включена"
|
|
||||||
|
|
||||||
#: olgram/commands/menu.py:199
|
|
||||||
msgid "выключена"
|
|
||||||
msgstr "вимкнена"
|
|
||||||
|
|
||||||
#: olgram/commands/menu.py:200
|
|
||||||
msgid "Olgram подпись: <b>{0}</b>"
|
msgid "Olgram подпись: <b>{0}</b>"
|
||||||
msgstr "Olgram підпис: <b>{0}</b>"
|
msgstr "Olgram підпис: <b>{0}</b>"
|
||||||
|
|
||||||
#: olgram/commands/menu.py:210 olgram/commands/menu.py:272
|
#: olgram/commands/menu.py:259 olgram/commands/menu.py:421
|
||||||
#: olgram/commands/menu.py:314
|
#: olgram/commands/menu.py:480
|
||||||
msgid "<< Завершить редактирование"
|
msgid "<< Завершить редактирование"
|
||||||
msgstr "<< Завершити редагування"
|
msgstr "<< Завершити редагування"
|
||||||
|
|
||||||
#: olgram/commands/menu.py:214
|
#: olgram/commands/menu.py:263
|
||||||
msgid "Автоответчик"
|
msgid "Автоответчик"
|
||||||
msgstr "Автовідповідач"
|
msgstr "Автовідповідач"
|
||||||
|
|
||||||
#: olgram/commands/menu.py:219 olgram/commands/menu.py:286
|
#: olgram/commands/menu.py:268 olgram/commands/menu.py:435
|
||||||
msgid "Сбросить текст"
|
msgid "Сбросить текст"
|
||||||
msgstr "Скинути текст"
|
msgstr "Скинути текст"
|
||||||
|
|
||||||
#: olgram/commands/menu.py:224
|
#: olgram/commands/menu.py:273 olgram/commands/menu.py:440
|
||||||
|
msgid "[все языки]"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: olgram/commands/menu.py:290
|
||||||
msgid ""
|
msgid ""
|
||||||
"\n"
|
"\n"
|
||||||
" Сейчас вы редактируете текст, который отправляется после того, как "
|
" Сейчас вы редактируете текст, который отправляется после того, как "
|
||||||
"пользователь отправит вашему боту @{0}\n"
|
"пользователь отправит вашему боту @{0}\n"
|
||||||
" команду /start\n"
|
" команду /start\n"
|
||||||
"\n"
|
"\n"
|
||||||
" Текущий текст:\n"
|
" Текущий текст{2}:\n"
|
||||||
" <pre>{1}</pre>\n"
|
" <pre>{1}</pre>\n"
|
||||||
" Отправьте сообщение, чтобы изменить текст.\n"
|
" Отправьте сообщение, чтобы изменить текст.\n"
|
||||||
" "
|
" "
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"\n"
|
|
||||||
" Зараз ви редагуєте текст, який надсилається після того, як користувач "
|
|
||||||
"надішле вашому боту @{0}\n"
|
|
||||||
" команду /start\n"
|
|
||||||
"\n"
|
|
||||||
" Поточний текст:\n"
|
|
||||||
" <pre>{1}</pre>\n"
|
|
||||||
" Надішліть повідомлення, щоб змінити текст.\n"
|
|
||||||
" \n"
|
|
||||||
" "
|
|
||||||
|
|
||||||
#: olgram/commands/menu.py:251
|
#: olgram/commands/menu.py:300 olgram/commands/menu.py:467
|
||||||
|
msgid " (для языка {0})"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: olgram/commands/menu.py:313
|
||||||
|
#, fuzzy
|
||||||
|
#| msgid "Отменить"
|
||||||
|
msgid "<< Отменить рассылку"
|
||||||
|
msgstr "Скасувати"
|
||||||
|
|
||||||
|
#: olgram/commands/menu.py:317
|
||||||
|
msgid ""
|
||||||
|
"\n"
|
||||||
|
" Напишите сообщение, которое нужно разослать всем подписчикам вашего бота "
|
||||||
|
"@{0}. \n"
|
||||||
|
" У сообщения будет до {1} получателей. \n"
|
||||||
|
" Учтите, что\n"
|
||||||
|
" 1. Рассылается только одно сообщение за раз (в т.ч. только одна "
|
||||||
|
"картинка)\n"
|
||||||
|
" 2. Когда рассылка запущена, её нельзя отменить \n"
|
||||||
|
" "
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: olgram/commands/menu.py:367
|
||||||
|
msgid "Не удалось загрузить файл (слишком большой размер?)"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: olgram/commands/menu.py:374
|
||||||
|
msgid "Да, начать рассылку"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: olgram/commands/menu.py:394
|
||||||
msgid ""
|
msgid ""
|
||||||
"\n"
|
"\n"
|
||||||
" Статистика по боту @{0}\n"
|
" Статистика по боту @{0}\n"
|
||||||
|
@ -442,43 +498,32 @@ msgstr ""
|
||||||
" Забанено користувачів: <b>{4}</b>\n"
|
" Забанено користувачів: <b>{4}</b>\n"
|
||||||
" "
|
" "
|
||||||
|
|
||||||
#: olgram/commands/menu.py:276
|
#: olgram/commands/menu.py:425
|
||||||
msgid "Предыдущий текст"
|
msgid "Предыдущий текст"
|
||||||
msgstr "Попередній текст"
|
msgstr "Попередній текст"
|
||||||
|
|
||||||
#: olgram/commands/menu.py:281
|
#: olgram/commands/menu.py:430
|
||||||
msgid "Шаблоны ответов..."
|
msgid "Шаблоны ответов..."
|
||||||
msgstr "Шаблони відповідей..."
|
msgstr "Шаблони відповідей..."
|
||||||
|
|
||||||
#: olgram/commands/menu.py:291
|
#: olgram/commands/menu.py:457
|
||||||
msgid ""
|
msgid ""
|
||||||
"\n"
|
"\n"
|
||||||
" Сейчас вы редактируете текст автоответчика. Это сообщение отправляется в "
|
" Сейчас вы редактируете текст автоответчика. Это сообщение отправляется в "
|
||||||
"ответ на все входящие сообщения @{0} автоматически. По умолчанию оно "
|
"ответ на все входящие сообщения @{0} автоматически. По умолчанию оно "
|
||||||
"отключено.\n"
|
"отключено.\n"
|
||||||
"\n"
|
"\n"
|
||||||
" Текущий текст:\n"
|
" Текущий текст{2}:\n"
|
||||||
" <pre>{1}</pre>\n"
|
" <pre>{1}</pre>\n"
|
||||||
" Отправьте сообщение, чтобы изменить текст.\n"
|
" Отправьте сообщение, чтобы изменить текст.\n"
|
||||||
" "
|
" "
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"\n"
|
|
||||||
" Зараз ви редагуєте текст автовідповідача. Це повідомлення надсилається у "
|
|
||||||
"відповідь на всі вхідні повідомлення @{0} автоматично. За замовчуванням його "
|
|
||||||
"вимкнено.\n"
|
|
||||||
"\n"
|
|
||||||
" Поточний текст:\n"
|
|
||||||
" <pre>\n"
|
|
||||||
" {1}\n"
|
|
||||||
" </pre>\n"
|
|
||||||
" Надішліть повідомлення, щоб змінити текст.\n"
|
|
||||||
" "
|
|
||||||
|
|
||||||
#: olgram/commands/menu.py:301
|
#: olgram/commands/menu.py:466
|
||||||
msgid "(отключено)"
|
msgid "отключено"
|
||||||
msgstr "(відключено)"
|
msgstr "відключено"
|
||||||
|
|
||||||
#: olgram/commands/menu.py:318
|
#: olgram/commands/menu.py:484
|
||||||
msgid ""
|
msgid ""
|
||||||
"\n"
|
"\n"
|
||||||
" Сейчас вы редактируете шаблоны ответов для @{0}. Текущие шаблоны:\n"
|
" Сейчас вы редактируете шаблоны ответов для @{0}. Текущие шаблоны:\n"
|
||||||
|
@ -504,30 +549,50 @@ msgstr ""
|
||||||
" \n"
|
" \n"
|
||||||
" "
|
" "
|
||||||
|
|
||||||
#: olgram/commands/menu.py:337
|
#: olgram/commands/menu.py:503
|
||||||
msgid "(нет шаблонов)"
|
msgid "(нет шаблонов)"
|
||||||
msgstr "(Немає шаблонів)"
|
msgstr "(Немає шаблонів)"
|
||||||
|
|
||||||
#: olgram/commands/menu.py:376
|
#: olgram/commands/menu.py:565
|
||||||
msgid "У вас нет шаблонов, чтобы их удалять"
|
msgid "У вас нет шаблонов, чтобы их удалять"
|
||||||
msgstr "У вас немає шаблонів, щоб їх видаляти"
|
msgstr "У вас немає шаблонів, щоб їх видаляти"
|
||||||
|
|
||||||
#: olgram/commands/menu.py:378
|
#: olgram/commands/menu.py:567
|
||||||
msgid "Неправильное число. Чтобы удалить шаблон, введите число от 0 до {0}"
|
msgid "Неправильное число. Чтобы удалить шаблон, введите число от 0 до {0}"
|
||||||
msgstr "Неправильне число. Щоб видалити шаблон, введіть число від 0 до {0}"
|
msgstr "Неправильне число. Щоб видалити шаблон, введіть число від 0 до {0}"
|
||||||
|
|
||||||
#: olgram/commands/menu.py:386
|
#: olgram/commands/menu.py:575
|
||||||
msgid "У вашего бота уже слишком много шаблонов"
|
msgid "У вашего бота уже слишком много шаблонов"
|
||||||
msgstr "У вашого бота вже дуже багато шаблонів"
|
msgstr "У вашого бота вже дуже багато шаблонів"
|
||||||
|
|
||||||
#: olgram/commands/menu.py:390
|
#: olgram/commands/menu.py:579
|
||||||
msgid "Такой текст уже есть в списке шаблонов"
|
msgid "Такой текст уже есть в списке шаблонов"
|
||||||
msgstr "Такий текст вже є у списку шаблонів"
|
msgstr "Такий текст вже є у списку шаблонів"
|
||||||
|
|
||||||
#: olgram/commands/menu.py:408
|
#: olgram/commands/menu.py:597
|
||||||
msgid "У вас нет прав на этого бота"
|
msgid "У вас нет прав на этого бота"
|
||||||
msgstr "У вас немає прав на цього бота"
|
msgstr "У вас немає прав на цього бота"
|
||||||
|
|
||||||
|
#: olgram/commands/menu.py:617 olgram/commands/menu.py:643
|
||||||
|
msgid "Рассылка была совсем недавно, подождите немного"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: olgram/commands/menu.py:619 olgram/commands/menu.py:645
|
||||||
|
msgid "Нет пользователей для рассылки"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: olgram/commands/menu.py:647
|
||||||
|
msgid "Рассылка запущена"
|
||||||
|
msgstr "Розсилка запущена"
|
||||||
|
|
||||||
|
#: olgram/commands/menu.py:649
|
||||||
|
msgid "Рассылка завершена, отправлено {0} сообщений"
|
||||||
|
msgstr "Розсилка завершена, надіслано {0} повідомлень"
|
||||||
|
|
||||||
|
#: olgram/commands/menu.py:651
|
||||||
|
msgid "Устарело, создайте новую рассылку"
|
||||||
|
msgstr "Застаріло, створіть нову розсилку"
|
||||||
|
|
||||||
#: olgram/commands/promo.py:27
|
#: olgram/commands/promo.py:27
|
||||||
msgid ""
|
msgid ""
|
||||||
"Новый промокод\n"
|
"Новый промокод\n"
|
||||||
|
@ -623,23 +688,23 @@ msgstr ""
|
||||||
" \n"
|
" \n"
|
||||||
" "
|
" "
|
||||||
|
|
||||||
#: olgram/utils/permissions.py:40
|
#: olgram/utils/permissions.py:41
|
||||||
msgid "Владелец бота ограничил доступ к этому функционалу 😞"
|
msgid "Владелец бота ограничил доступ к этому функционалу 😞"
|
||||||
msgstr "Власник бота обмежив доступ до цього функціоналу 😞"
|
msgstr "Власник бота обмежив доступ до цього функціоналу 😞"
|
||||||
|
|
||||||
#: olgram/utils/permissions.py:52
|
#: olgram/utils/permissions.py:53
|
||||||
msgid "Владелец бота ограничил доступ к этому функционалу😞"
|
msgid "Владелец бота ограничил доступ к этому функционалу😞"
|
||||||
msgstr "Власник бота обмежив доступ до цього функціоналу 😞"
|
msgstr "Власник бота обмежив доступ до цього функціоналу 😞"
|
||||||
|
|
||||||
#: server/custom.py:55
|
#: server/custom.py:57
|
||||||
msgid ""
|
msgid ""
|
||||||
"<b>Политика конфиденциальности</b>\n"
|
"<b>Политика конфиденциальности</b>\n"
|
||||||
"\n"
|
"\n"
|
||||||
"Этот бот не хранит ваши сообщения, имя пользователя и @username. При "
|
"Этот бот не хранит ваши сообщения, имя пользователя и @username. При "
|
||||||
"отправке сообщения (кроме команд /start и /security_policy) ваш "
|
"отправке сообщения (кроме команд /start и /security_policy) ваш "
|
||||||
"идентификатор пользователя записывается в кеш на некоторое время и потом "
|
"идентификатор пользователя записывается в кеш на некоторое время и потом "
|
||||||
"удаляется из кеша. Этот идентификатор используется только для общения с "
|
"удаляется из кеша. Этот идентификатор используется для общения с "
|
||||||
"оператором; боты Olgram не делают массовых рассылок.\n"
|
"оператором.\n"
|
||||||
"\n"
|
"\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"<b>Політика конфіденційності</b>\n"
|
"<b>Політика конфіденційності</b>\n"
|
||||||
|
@ -647,45 +712,63 @@ msgstr ""
|
||||||
"Цей бот не зберігає ваші повідомлення, ім'я користувача та @username. При "
|
"Цей бот не зберігає ваші повідомлення, ім'я користувача та @username. При "
|
||||||
"надсиланні повідомлення (крім команд /start та /security_policy) ваш "
|
"надсиланні повідомлення (крім команд /start та /security_policy) ваш "
|
||||||
"ідентифікатор користувача записується в кеш на деякий час і потім "
|
"ідентифікатор користувача записується в кеш на деякий час і потім "
|
||||||
"видаляється з кеша. Цей ідентифікатор використовується лише для спілкування "
|
"видаляється з кеша. Цей ідентифікатор використовується для спілкування з "
|
||||||
"з оператором; боти Olgram не роблять масових розсилок.\n"
|
"оператором.\n"
|
||||||
"\n"
|
"\n"
|
||||||
|
|
||||||
#: server/custom.py:61
|
#: server/custom.py:62
|
||||||
msgid ""
|
msgid ""
|
||||||
"При отправке сообщения (кроме команд /start и /security_policy) оператор "
|
"При отправке сообщения (кроме команд /start и /security_policy) оператор "
|
||||||
"<b>видит</b> ваши имя пользователя, @username и идентификатор пользователя в "
|
"<b>видит</b> ваши имя пользователя, @username и идентификатор пользователя в "
|
||||||
"силу настроек, которые оператор указал при создании бота."
|
"силу настроек, которые оператор указал при создании бота.\n"
|
||||||
|
"\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"При надсиланні повідомлення (крім команд /start та /security_policy) "
|
"При надсиланні повідомлення (крім команд /start та /security_policy) "
|
||||||
"оператор <b>бачить</b> ваше ім'я користувача, @username та ідентифікатор "
|
"оператор <b>бачить</b> ваше ім'я користувача, @username та ідентифікатор "
|
||||||
"користувача через налаштування, які оператор вказав при створенні бота."
|
"користувача через налаштування, які оператор вказав при створенні бота.\n"
|
||||||
|
"\n"
|
||||||
|
|
||||||
#: server/custom.py:65
|
#: server/custom.py:66
|
||||||
msgid ""
|
msgid ""
|
||||||
"В зависимости от ваших настроек конфиденциальности Telegram, оператор может "
|
"В зависимости от ваших настроек конфиденциальности Telegram, оператор может "
|
||||||
"видеть ваш username, имя пользователя и другую информацию."
|
"видеть ваш username, имя пользователя и другую информацию.\n"
|
||||||
|
"\n"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Залежно від ваших налаштувань конфіденційності Telegram оператор може бачити "
|
"Залежно від ваших налаштувань конфіденційності Telegram оператор може бачити "
|
||||||
"ваш username, ім'я користувача та іншу інформацію."
|
"ваш username, ім'я користувача та іншу інформацію.\n"
|
||||||
|
"\n"
|
||||||
|
|
||||||
#: server/custom.py:76
|
#: server/custom.py:70
|
||||||
|
msgid ""
|
||||||
|
"В этом боте включена массовая рассылка в силу настроек, которые оператор "
|
||||||
|
"указал при создании бота. Ваш идентификатор пользователя может быть записан "
|
||||||
|
"в базу данных на долгое время"
|
||||||
|
msgstr ""
|
||||||
|
"У цьому роботі включено масове розсилання в силу налаштувань, які оператор "
|
||||||
|
"вказав при створенні робота. Ваш ідентифікатор користувача може бути "
|
||||||
|
"записаний до бази даних на довгий час"
|
||||||
|
|
||||||
|
#: server/custom.py:73
|
||||||
|
msgid "В этом боте нет массовой рассылки сообщений"
|
||||||
|
msgstr "У цьому роботі немає масової розсилки повідомлень"
|
||||||
|
|
||||||
|
#: server/custom.py:83
|
||||||
msgid "Сообщение от пользователя "
|
msgid "Сообщение от пользователя "
|
||||||
msgstr "Допис від користувача "
|
msgstr "Допис від користувача "
|
||||||
|
|
||||||
#: server/custom.py:135
|
#: server/custom.py:157
|
||||||
msgid "Вы заблокированы в этом боте"
|
msgid "Вы заблокированы в этом боте"
|
||||||
msgstr "Ви заблоковані у цьому боті"
|
msgstr "Ви заблоковані у цьому боті"
|
||||||
|
|
||||||
#: server/custom.py:141
|
#: server/custom.py:163
|
||||||
msgid "Слишком много сообщений, подождите одну минуту"
|
msgid "Слишком много сообщений, подождите одну минуту"
|
||||||
msgstr "Забагато повідомлень, зачекайте одну хвилину"
|
msgstr "Забагато повідомлень, зачекайте одну хвилину"
|
||||||
|
|
||||||
#: server/custom.py:148
|
#: server/custom.py:170
|
||||||
msgid "Не удаётся связаться с владельцем бота"
|
msgid "Не удаётся связаться с владельцем бота"
|
||||||
msgstr "Не вдається зв'язатися з власником бота"
|
msgstr "Не вдається зв'язатися з власником бота"
|
||||||
|
|
||||||
#: server/custom.py:179
|
#: server/custom.py:202
|
||||||
msgid ""
|
msgid ""
|
||||||
"<i>Невозможно переслать сообщение: автор не найден (сообщение слишком "
|
"<i>Невозможно переслать сообщение: автор не найден (сообщение слишком "
|
||||||
"старое?)</i>"
|
"старое?)</i>"
|
||||||
|
@ -693,19 +776,19 @@ msgstr ""
|
||||||
"<i>Неможливо надіслати повідомлення: автора не знайдено (повідомлення "
|
"<i>Неможливо надіслати повідомлення: автора не знайдено (повідомлення "
|
||||||
"занадто старе?)</i>"
|
"занадто старе?)</i>"
|
||||||
|
|
||||||
#: server/custom.py:187
|
#: server/custom.py:210
|
||||||
msgid "Пользователь заблокирован"
|
msgid "Пользователь заблокирован"
|
||||||
msgstr "Користувач заблоковано"
|
msgstr "Користувач заблоковано"
|
||||||
|
|
||||||
#: server/custom.py:192
|
#: server/custom.py:215
|
||||||
msgid "Пользователь не был забанен"
|
msgid "Пользователь не был забанен"
|
||||||
msgstr "Користувач не був забанений"
|
msgstr "Користувач не був забанений"
|
||||||
|
|
||||||
#: server/custom.py:195
|
#: server/custom.py:218
|
||||||
msgid "Пользователь разбанен"
|
msgid "Пользователь разбанен"
|
||||||
msgstr "Користувач розбанений"
|
msgstr "Користувач розбанений"
|
||||||
|
|
||||||
#: server/custom.py:200
|
#: server/custom.py:223
|
||||||
msgid "<i>Невозможно переслать сообщение (автор заблокировал бота?)</i>"
|
msgid "<i>Невозможно переслать сообщение (автор заблокировал бота?)</i>"
|
||||||
msgstr "<i>Неможливо надіслати повідомлення (автор заблокував робота?)</i>"
|
msgstr "<i>Неможливо надіслати повідомлення (автор заблокував робота?)</i>"
|
||||||
|
|
||||||
|
@ -717,11 +800,11 @@ msgstr "(Пере) запустити бота"
|
||||||
msgid "Политика конфиденциальности"
|
msgid "Политика конфиденциальности"
|
||||||
msgstr "Політика конфіденційності"
|
msgstr "Політика конфіденційності"
|
||||||
|
|
||||||
msgid ""
|
#~ msgid ""
|
||||||
"\n"
|
#~ "\n"
|
||||||
"\n"
|
#~ "\n"
|
||||||
"Этот бот создан с помощью @OlgramBot"
|
#~ "Этот бот создан с помощью @OlgramBot"
|
||||||
msgstr ""
|
#~ msgstr ""
|
||||||
"\n"
|
#~ "\n"
|
||||||
"\n"
|
#~ "\n"
|
||||||
"Цей бот створено за допомогою @OlgramBot"
|
#~ "Цей бот створено за допомогою @OlgramBot"
|
||||||
|
|
|
@ -1,8 +1,13 @@
|
||||||
"""
|
"""
|
||||||
Здесь работа с конкретным ботом
|
Здесь работа с конкретным ботом
|
||||||
"""
|
"""
|
||||||
|
import logging
|
||||||
|
|
||||||
from aiogram import types
|
from aiogram import types
|
||||||
from aiogram.utils.exceptions import TelegramAPIError, Unauthorized
|
from asyncio import sleep
|
||||||
|
from datetime import datetime
|
||||||
|
from olgram.utils.mix import send_stored_message
|
||||||
|
from aiogram.utils import exceptions
|
||||||
from aiogram import Bot as AioBot
|
from aiogram import Bot as AioBot
|
||||||
from olgram.models.models import Bot, BotStartMessage, BotSecondMessage
|
from olgram.models.models import Bot, BotStartMessage, BotSecondMessage
|
||||||
from server.server import unregister_token
|
from server.server import unregister_token
|
||||||
|
@ -15,14 +20,14 @@ async def delete_bot(bot: Bot, call: types.CallbackQuery):
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
await unregister_token(bot.decrypted_token())
|
await unregister_token(bot.decrypted_token())
|
||||||
except Unauthorized:
|
except exceptions.Unauthorized:
|
||||||
# Вероятно пользователь сбросил токен или удалил бот, это уже не наши проблемы
|
# Вероятно пользователь сбросил токен или удалил бот, это уже не наши проблемы
|
||||||
pass
|
pass
|
||||||
await bot.delete()
|
await bot.delete()
|
||||||
await call.answer(_("Бот удалён"))
|
await call.answer(_("Бот удалён"))
|
||||||
try:
|
try:
|
||||||
await call.message.delete()
|
await call.message.delete()
|
||||||
except TelegramAPIError:
|
except exceptions.TelegramAPIError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
@ -84,7 +89,7 @@ async def select_chat(bot: Bot, call: types.CallbackQuery, chat: str):
|
||||||
try:
|
try:
|
||||||
await chat.delete()
|
await chat.delete()
|
||||||
await a_bot.leave_chat(chat.chat_id)
|
await a_bot.leave_chat(chat.chat_id)
|
||||||
except TelegramAPIError:
|
except exceptions.TelegramAPIError:
|
||||||
pass
|
pass
|
||||||
await call.answer(_("Бот вышел из чатов"))
|
await call.answer(_("Бот вышел из чатов"))
|
||||||
await a_bot.session.close()
|
await a_bot.session.close()
|
||||||
|
@ -114,6 +119,11 @@ async def always_second_message(bot: Bot, call: types.CallbackQuery):
|
||||||
await bot.save(update_fields=["enable_always_second_message"])
|
await bot.save(update_fields=["enable_always_second_message"])
|
||||||
|
|
||||||
|
|
||||||
|
async def thread_interrupt(bot: Bot, call: types.CallbackQuery):
|
||||||
|
bot.enable_thread_interrupt = not bot.enable_thread_interrupt
|
||||||
|
await bot.save(update_fields=["enable_thread_interrupt"])
|
||||||
|
|
||||||
|
|
||||||
async def olgram_text(bot: Bot, call: types.CallbackQuery):
|
async def olgram_text(bot: Bot, call: types.CallbackQuery):
|
||||||
if await bot.is_promo():
|
if await bot.is_promo():
|
||||||
bot.enable_olgram_text = not bot.enable_olgram_text
|
bot.enable_olgram_text = not bot.enable_olgram_text
|
||||||
|
@ -123,3 +133,38 @@ async def olgram_text(bot: Bot, call: types.CallbackQuery):
|
||||||
async def antiflood(bot: Bot, call: types.CallbackQuery):
|
async def antiflood(bot: Bot, call: types.CallbackQuery):
|
||||||
bot.enable_antiflood = not bot.enable_antiflood
|
bot.enable_antiflood = not bot.enable_antiflood
|
||||||
await bot.save(update_fields=["enable_antiflood"])
|
await bot.save(update_fields=["enable_antiflood"])
|
||||||
|
|
||||||
|
|
||||||
|
async def mailing(bot: Bot, call: types.CallbackQuery):
|
||||||
|
bot.enable_mailing = not bot.enable_mailing
|
||||||
|
await bot.save(update_fields=["enable_mailing"])
|
||||||
|
|
||||||
|
|
||||||
|
async def go_mailing(bot: Bot, context: dict) -> int:
|
||||||
|
users = await bot.mailing_users
|
||||||
|
a_bot = AioBot(bot.decrypted_token())
|
||||||
|
|
||||||
|
count = 0
|
||||||
|
|
||||||
|
for user in users:
|
||||||
|
bot.last_mailing_at = datetime.now()
|
||||||
|
await bot.save(update_fields=["last_mailing_at"])
|
||||||
|
try:
|
||||||
|
await sleep(0.05)
|
||||||
|
try:
|
||||||
|
file_id = await send_stored_message(context, a_bot, user.telegram_id)
|
||||||
|
except exceptions.RetryAfter as err:
|
||||||
|
await sleep(err.timeout)
|
||||||
|
file_id = await send_stored_message(context, a_bot, user.telegram_id)
|
||||||
|
|
||||||
|
if file_id:
|
||||||
|
context["mailing_id"] = file_id
|
||||||
|
count += 1
|
||||||
|
except (exceptions.ChatNotFound, exceptions.BotBlocked, exceptions.UserDeactivated):
|
||||||
|
await user.delete()
|
||||||
|
except Exception as err:
|
||||||
|
logging.error("mailing error")
|
||||||
|
logging.error(err, exc_info=True)
|
||||||
|
pass
|
||||||
|
|
||||||
|
return count
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
|
import logging
|
||||||
|
from io import BytesIO
|
||||||
from olgram.router import dp
|
from olgram.router import dp
|
||||||
|
from datetime import datetime, timedelta, timezone
|
||||||
from aiogram import types, Bot as AioBot
|
from aiogram import types, Bot as AioBot
|
||||||
from olgram.models.models import Bot, User, DefaultAnswer, BotStartMessage, BotSecondMessage
|
from olgram.models.models import Bot, User, DefaultAnswer, BotStartMessage, BotSecondMessage
|
||||||
from aiogram.dispatcher import FSMContext
|
from aiogram.dispatcher import FSMContext
|
||||||
from aiogram.utils.callback_data import CallbackData
|
from aiogram.utils.callback_data import CallbackData
|
||||||
from textwrap import dedent
|
from textwrap import dedent
|
||||||
from olgram.utils.mix import edit_or_create, button_text_limit, wrap
|
from olgram.utils.mix import edit_or_create, button_text_limit, wrap, send_stored_message
|
||||||
from olgram.commands import bot_actions
|
from olgram.commands import bot_actions
|
||||||
from locales.locale import _
|
from locales.locale import _
|
||||||
|
|
||||||
|
@ -127,6 +129,12 @@ async def send_bot_menu(bot: Bot, call: types.CallbackQuery):
|
||||||
callback_data=menu_callback.new(level=2, bot_id=bot.id, operation="settings",
|
callback_data=menu_callback.new(level=2, bot_id=bot.id, operation="settings",
|
||||||
chat=empty))
|
chat=empty))
|
||||||
)
|
)
|
||||||
|
if bot.enable_mailing:
|
||||||
|
keyboard.insert(
|
||||||
|
types.InlineKeyboardButton(text=_("Рассылка"),
|
||||||
|
callback_data=menu_callback.new(level=2, bot_id=bot.id, operation="go_mailing",
|
||||||
|
chat=empty))
|
||||||
|
)
|
||||||
|
|
||||||
await edit_or_create(call, dedent(_("""
|
await edit_or_create(call, dedent(_("""
|
||||||
Управление ботом @{0}.
|
Управление ботом @{0}.
|
||||||
|
@ -178,6 +186,17 @@ async def send_bot_settings_menu(bot: Bot, call: types.CallbackQuery):
|
||||||
operation="always_second_message",
|
operation="always_second_message",
|
||||||
chat=empty))
|
chat=empty))
|
||||||
)
|
)
|
||||||
|
keyboard.insert(
|
||||||
|
types.InlineKeyboardButton(text=_("Рассылка"),
|
||||||
|
callback_data=menu_callback.new(level=3, bot_id=bot.id, operation="mailing",
|
||||||
|
chat=empty))
|
||||||
|
)
|
||||||
|
keyboard.insert(
|
||||||
|
types.InlineKeyboardButton(text=_("Прерывать поток"),
|
||||||
|
callback_data=menu_callback.new(level=3, bot_id=bot.id,
|
||||||
|
operation="thread_interrupt",
|
||||||
|
chat=empty))
|
||||||
|
)
|
||||||
is_promo = await bot.is_promo()
|
is_promo = await bot.is_promo()
|
||||||
if is_promo:
|
if is_promo:
|
||||||
keyboard.insert(
|
keyboard.insert(
|
||||||
|
@ -196,12 +215,17 @@ async def send_bot_settings_menu(bot: Bot, call: types.CallbackQuery):
|
||||||
info_turn = _("включены") if bot.enable_additional_info else _("выключены")
|
info_turn = _("включены") if bot.enable_additional_info else _("выключены")
|
||||||
antiflood_turn = _("включен") if bot.enable_antiflood else _("выключен")
|
antiflood_turn = _("включен") if bot.enable_antiflood else _("выключен")
|
||||||
enable_always_second_message = _("включён") if bot.enable_always_second_message else _("выключен")
|
enable_always_second_message = _("включён") if bot.enable_always_second_message else _("выключен")
|
||||||
|
thread_interrupt = _("да") if bot.enable_thread_interrupt else _("нет")
|
||||||
|
mailing_turn = _("включена") if bot.enable_mailing else _("выключена")
|
||||||
text = dedent(_("""
|
text = dedent(_("""
|
||||||
<a href="https://olgram.readthedocs.io/ru/latest/options.html#threads">Потоки сообщений</a>: <b>{0}</b>
|
<a href="https://olgram.readthedocs.io/ru/latest/options.html#threads">Потоки сообщений</a>: <b>{0}</b>
|
||||||
<a href="https://olgram.readthedocs.io/ru/latest/options.html#user-info">Данные пользователя</a>: <b>{1}</b>
|
<a href="https://olgram.readthedocs.io/ru/latest/options.html#user-info">Данные пользователя</a>: <b>{1}</b>
|
||||||
<a href="https://olgram.readthedocs.io/ru/latest/options.html#antiflood">Антифлуд</a>: <b>{2}</b>
|
<a href="https://olgram.readthedocs.io/ru/latest/options.html#antiflood">Антифлуд</a>: <b>{2}</b>
|
||||||
<a href="https://olgram.readthedocs.io/ru/latest/options.html#always_second_message">Автоответчик всегда</a>: <b>{3}</b>
|
<a href="https://olgram.readthedocs.io/ru/latest/options.html#always_second_message">Автоответчик всегда</a>: <b>{3}</b>
|
||||||
""")).format(thread_turn, info_turn, antiflood_turn, enable_always_second_message)
|
<a href="https://olgram.readthedocs.io/ru/latest/options.html#thread_interrupt">Прерывать поток</a>: <b>{4}</b>
|
||||||
|
<a href="https://olgram.readthedocs.io/ru/latest/options.html#mailing">Рассылка</a>: <b>{5}</b>
|
||||||
|
""")).format(thread_turn, info_turn, antiflood_turn, enable_always_second_message, thread_interrupt,
|
||||||
|
mailing_turn)
|
||||||
|
|
||||||
if is_promo:
|
if is_promo:
|
||||||
olgram_turn = _("включена") if bot.enable_olgram_text else _("выключена")
|
olgram_turn = _("включена") if bot.enable_olgram_text else _("выключена")
|
||||||
|
@ -280,6 +304,83 @@ async def send_bot_text_menu(bot: Bot, call: ty.Optional[types.CallbackQuery] =
|
||||||
await AioBot.get_current().send_message(chat_id, text, reply_markup=keyboard, parse_mode="HTML")
|
await AioBot.get_current().send_message(chat_id, text, reply_markup=keyboard, parse_mode="HTML")
|
||||||
|
|
||||||
|
|
||||||
|
async def send_bot_mailing_menu(bot: Bot, call: ty.Optional[types.CallbackQuery] = None,
|
||||||
|
chat_id: ty.Optional[int] = None):
|
||||||
|
if call:
|
||||||
|
await call.answer()
|
||||||
|
keyboard = types.InlineKeyboardMarkup(row_width=1)
|
||||||
|
keyboard.insert(
|
||||||
|
types.InlineKeyboardButton(text=_("<< Отменить рассылку"),
|
||||||
|
callback_data=menu_callback.new(level=1, bot_id=bot.id, operation=empty, chat=empty))
|
||||||
|
)
|
||||||
|
|
||||||
|
text = dedent(_("""
|
||||||
|
Напишите сообщение, которое нужно разослать всем подписчикам вашего бота @{0}.
|
||||||
|
У сообщения будет до {1} получателей.
|
||||||
|
Учтите, что
|
||||||
|
1. Рассылается только одно сообщение за раз (в т.ч. только одна картинка)
|
||||||
|
2. Когда рассылка запущена, её нельзя отменить
|
||||||
|
"""))
|
||||||
|
text = text.format(bot.name, len(await bot.mailing_users))
|
||||||
|
if call:
|
||||||
|
await edit_or_create(call, text, keyboard, parse_mode="HTML")
|
||||||
|
else:
|
||||||
|
await AioBot.get_current().send_message(chat_id, text, reply_markup=keyboard, parse_mode="HTML")
|
||||||
|
|
||||||
|
|
||||||
|
@dp.message_handler(state="wait_mailing_text",
|
||||||
|
content_types=[types.ContentType.TEXT,
|
||||||
|
types.ContentType.LOCATION,
|
||||||
|
types.ContentType.DOCUMENT,
|
||||||
|
types.ContentType.PHOTO,
|
||||||
|
types.ContentType.AUDIO,
|
||||||
|
types.ContentType.VIDEO]) # TODO: not command
|
||||||
|
async def mailing_text_received(message: types.Message, state: FSMContext):
|
||||||
|
async with state.proxy() as proxy:
|
||||||
|
bot_id = proxy["bot_id"]
|
||||||
|
proxy["mailing_content_type"] = message.content_type
|
||||||
|
|
||||||
|
buffer = BytesIO()
|
||||||
|
|
||||||
|
if message.content_type == types.ContentType.TEXT:
|
||||||
|
proxy["mailing_text"] = message.html_text
|
||||||
|
elif message.content_type == types.ContentType.LOCATION:
|
||||||
|
proxy["mailing_location"] = message.location
|
||||||
|
elif message.content_type in (types.ContentType.PHOTO, types.ContentType.DOCUMENT, types.ContentType.AUDIO,
|
||||||
|
types.ContentType.VIDEO):
|
||||||
|
proxy["mailing_caption"] = message.caption
|
||||||
|
|
||||||
|
if message.content_type == types.ContentType.PHOTO:
|
||||||
|
obj = message.photo[-1]
|
||||||
|
elif message.content_type == types.ContentType.DOCUMENT:
|
||||||
|
obj = message.document
|
||||||
|
elif message.content_type == types.ContentType.AUDIO:
|
||||||
|
obj = message.audio
|
||||||
|
elif message.content_type == types.ContentType.VIDEO:
|
||||||
|
obj = message.video
|
||||||
|
|
||||||
|
try:
|
||||||
|
await obj.download(buffer, timeout=5)
|
||||||
|
except Exception as err:
|
||||||
|
logging.error("Error downloading file")
|
||||||
|
logging.error(err, exc_info=True)
|
||||||
|
return await message.answer(_("Не удалось загрузить файл (слишком большой размер?)"))
|
||||||
|
proxy["mailing_data"] = buffer.getvalue()
|
||||||
|
proxy["mailing_file_name"] = getattr(obj, "file_name")
|
||||||
|
_message_id = await send_stored_message(proxy, AioBot.get_current(), message.chat.id)
|
||||||
|
|
||||||
|
keyboard = types.InlineKeyboardMarkup(row_width=1)
|
||||||
|
keyboard.insert(
|
||||||
|
types.InlineKeyboardButton(text=_("Да, начать рассылку"),
|
||||||
|
callback_data=menu_callback.new(level=3, bot_id=bot_id, operation="go_go_mailing",
|
||||||
|
chat=empty))
|
||||||
|
)
|
||||||
|
|
||||||
|
await AioBot.get_current().send_message(message.chat.id, reply_to_message_id=_message_id,
|
||||||
|
text="Вы уверены, что хотите разослать это сообщение всем пользователям?",
|
||||||
|
reply_markup=keyboard)
|
||||||
|
|
||||||
|
|
||||||
async def send_bot_statistic_menu(bot: Bot, call: ty.Optional[types.CallbackQuery] = None,
|
async def send_bot_statistic_menu(bot: Bot, call: ty.Optional[types.CallbackQuery] = None,
|
||||||
chat_id: ty.Optional[int] = None):
|
chat_id: ty.Optional[int] = None):
|
||||||
if call:
|
if call:
|
||||||
|
@ -511,6 +612,15 @@ async def callback(call: types.CallbackQuery, callback_data: dict, state: FSMCon
|
||||||
return await send_bot_statistic_menu(bot, call)
|
return await send_bot_statistic_menu(bot, call)
|
||||||
if operation == "settings":
|
if operation == "settings":
|
||||||
return await send_bot_settings_menu(bot, call)
|
return await send_bot_settings_menu(bot, call)
|
||||||
|
if operation == "go_mailing":
|
||||||
|
if bot.last_mailing_at and bot.last_mailing_at >= datetime.now(tz=timezone.utc) - timedelta(minutes=5):
|
||||||
|
return await call.answer(_("Рассылка была совсем недавно, подождите немного"), show_alert=True)
|
||||||
|
if not await bot.mailing_users:
|
||||||
|
return await call.answer(_("Нет пользователей для рассылки"))
|
||||||
|
await state.set_state("wait_mailing_text")
|
||||||
|
async with state.proxy() as proxy:
|
||||||
|
proxy["bot_id"] = bot.id
|
||||||
|
return await send_bot_mailing_menu(bot, call)
|
||||||
if operation == "text":
|
if operation == "text":
|
||||||
await state.set_state("wait_start_text")
|
await state.set_state("wait_start_text")
|
||||||
async with state.proxy() as proxy:
|
async with state.proxy() as proxy:
|
||||||
|
@ -520,6 +630,25 @@ async def callback(call: types.CallbackQuery, callback_data: dict, state: FSMCon
|
||||||
if level == "3":
|
if level == "3":
|
||||||
if operation == "delete_yes":
|
if operation == "delete_yes":
|
||||||
return await bot_actions.delete_bot(bot, call)
|
return await bot_actions.delete_bot(bot, call)
|
||||||
|
if operation == "mailing":
|
||||||
|
await bot_actions.mailing(bot, call)
|
||||||
|
return await send_bot_settings_menu(bot, call)
|
||||||
|
if operation == "go_go_mailing":
|
||||||
|
if (await state.get_state()) == "wait_mailing_text":
|
||||||
|
async with state.proxy() as proxy:
|
||||||
|
mailing_data = dict(proxy)
|
||||||
|
await state.reset_state()
|
||||||
|
|
||||||
|
if bot.last_mailing_at and bot.last_mailing_at >= datetime.now(tz=timezone.utc) - timedelta(minutes=5):
|
||||||
|
return await call.answer(_("Рассылка была совсем недавно, подождите немного"), show_alert=True)
|
||||||
|
if not await bot.mailing_users:
|
||||||
|
return await call.answer(_("Нет пользователей для рассылки"))
|
||||||
|
|
||||||
|
await call.answer(_("Рассылка запущена"))
|
||||||
|
count = await bot_actions.go_mailing(bot, mailing_data)
|
||||||
|
return await call.message.answer(_("Рассылка завершена, отправлено {0} сообщений").format(count))
|
||||||
|
else:
|
||||||
|
return await call.answer(_("Устарело, создайте новую рассылку"))
|
||||||
if operation == "chat":
|
if operation == "chat":
|
||||||
return await bot_actions.select_chat(bot, call, callback_data.get("chat"))
|
return await bot_actions.select_chat(bot, call, callback_data.get("chat"))
|
||||||
if operation == "threads":
|
if operation == "threads":
|
||||||
|
@ -534,6 +663,12 @@ async def callback(call: types.CallbackQuery, callback_data: dict, state: FSMCon
|
||||||
if operation == "always_second_message":
|
if operation == "always_second_message":
|
||||||
await bot_actions.always_second_message(bot, call)
|
await bot_actions.always_second_message(bot, call)
|
||||||
return await send_bot_settings_menu(bot, call)
|
return await send_bot_settings_menu(bot, call)
|
||||||
|
if operation == "mailing":
|
||||||
|
await bot_actions.mailing(bot, call)
|
||||||
|
return await send_bot_settings_menu(bot, call)
|
||||||
|
if operation == "thread_interrupt":
|
||||||
|
await bot_actions.thread_interrupt(bot, call)
|
||||||
|
return await send_bot_settings_menu(bot, call)
|
||||||
if operation == "olgram_text":
|
if operation == "olgram_text":
|
||||||
await bot_actions.olgram_text(bot, call)
|
await bot_actions.olgram_text(bot, call)
|
||||||
return await send_bot_settings_menu(bot, call)
|
return await send_bot_settings_menu(bot, call)
|
||||||
|
|
4
olgram/migrations/models/19_20240301193152_update.sql
Normal file
4
olgram/migrations/models/19_20240301193152_update.sql
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
-- upgrade --
|
||||||
|
ALTER TABLE "bot" ADD "enable_thread_interrupt" BOOL NOT NULL DEFAULT True;
|
||||||
|
-- downgrade --
|
||||||
|
ALTER TABLE "bot" DROP COLUMN "enable_thread_interrupt";
|
6
olgram/migrations/models/20_20240301215418_update.sql
Normal file
6
olgram/migrations/models/20_20240301215418_update.sql
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
-- upgrade --
|
||||||
|
ALTER TABLE "bot" ADD "enable_mailing" BOOL NOT NULL DEFAULT False;
|
||||||
|
ALTER TABLE "bot" ADD "last_mailing_at" TIMESTAMPTZ;
|
||||||
|
-- downgrade --
|
||||||
|
ALTER TABLE "bot" DROP COLUMN "enable_mailing";
|
||||||
|
ALTER TABLE "bot" DROP COLUMN "last_mailing_at";
|
10
olgram/migrations/models/21_20240301222228_update.sql
Normal file
10
olgram/migrations/models/21_20240301222228_update.sql
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
-- upgrade --
|
||||||
|
CREATE TABLE IF NOT EXISTS "mailinguser" (
|
||||||
|
"id" BIGSERIAL NOT NULL PRIMARY KEY,
|
||||||
|
"telegram_id" BIGINT NOT NULL,
|
||||||
|
"bot_id" INT NOT NULL REFERENCES "bot" ("id") ON DELETE CASCADE,
|
||||||
|
CONSTRAINT "uid_mailinguser_bot_id_906a76" UNIQUE ("bot_id", "telegram_id")
|
||||||
|
);
|
||||||
|
CREATE INDEX IF NOT EXISTS "idx_mailinguser_telegra_55de60" ON "mailinguser" ("telegram_id");
|
||||||
|
-- downgrade --
|
||||||
|
DROP TABLE IF EXISTS "mailinguser";
|
|
@ -47,6 +47,9 @@ class Bot(Model):
|
||||||
enable_olgram_text = fields.BooleanField(default=True)
|
enable_olgram_text = fields.BooleanField(default=True)
|
||||||
enable_antiflood = fields.BooleanField(default=False)
|
enable_antiflood = fields.BooleanField(default=False)
|
||||||
enable_always_second_message = fields.BooleanField(default=False)
|
enable_always_second_message = fields.BooleanField(default=False)
|
||||||
|
enable_thread_interrupt = fields.BooleanField(default=True)
|
||||||
|
enable_mailing = fields.BooleanField(default=False)
|
||||||
|
last_mailing_at = fields.DatetimeField(null=True, default=None)
|
||||||
|
|
||||||
def decrypted_token(self):
|
def decrypted_token(self):
|
||||||
cryptor = DatabaseSettings.cryptor()
|
cryptor = DatabaseSettings.cryptor()
|
||||||
|
@ -105,6 +108,17 @@ class User(Model):
|
||||||
table = 'user'
|
table = 'user'
|
||||||
|
|
||||||
|
|
||||||
|
class MailingUser(Model):
|
||||||
|
id = fields.BigIntField(pk=True)
|
||||||
|
telegram_id = fields.BigIntField(index=True)
|
||||||
|
|
||||||
|
bot = fields.ForeignKeyField("models.Bot", related_name="mailing_users", on_delete=fields.relational.CASCADE)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
table = 'mailinguser'
|
||||||
|
unique_together = (("bot", "telegram_id"), )
|
||||||
|
|
||||||
|
|
||||||
class GroupChat(Model):
|
class GroupChat(Model):
|
||||||
id = fields.IntField(pk=True)
|
id = fields.IntField(pk=True)
|
||||||
chat_id = fields.BigIntField(index=True, unique=True)
|
chat_id = fields.BigIntField(index=True, unique=True)
|
||||||
|
|
|
@ -7,7 +7,6 @@ from datetime import timedelta
|
||||||
import typing as ty
|
import typing as ty
|
||||||
from olgram.utils.crypto import Cryptor
|
from olgram.utils.crypto import Cryptor
|
||||||
|
|
||||||
|
|
||||||
load_dotenv()
|
load_dotenv()
|
||||||
|
|
||||||
|
|
||||||
|
@ -41,7 +40,7 @@ class OlgramSettings(AbstractSettings):
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def version(cls):
|
def version(cls):
|
||||||
return "0.7.0"
|
return "0.7.1"
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
@lru_cache
|
@lru_cache
|
||||||
|
@ -161,4 +160,6 @@ TORTOISE_ORM = {
|
||||||
"default_connection": "default",
|
"default_connection": "default",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
"use_tz": False,
|
||||||
|
"timezone": "UTC"
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
|
import logging
|
||||||
|
from io import BytesIO
|
||||||
from aiogram.types import Message, CallbackQuery, InlineKeyboardMarkup
|
from aiogram.types import Message, CallbackQuery, InlineKeyboardMarkup
|
||||||
from aiogram.utils.exceptions import TelegramAPIError
|
from aiogram.utils.exceptions import TelegramAPIError
|
||||||
|
from aiogram import types, Bot as AioBot
|
||||||
|
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
|
@ -30,3 +33,31 @@ def wrap(data: str, max_len: int) -> str:
|
||||||
|
|
||||||
def button_text_limit(data: str) -> str:
|
def button_text_limit(data: str) -> str:
|
||||||
return wrap(data, 30)
|
return wrap(data, 30)
|
||||||
|
|
||||||
|
|
||||||
|
async def send_stored_message(storage: dict, bot: AioBot, chat_id: int):
|
||||||
|
content_type = storage["mailing_content_type"]
|
||||||
|
if content_type == types.ContentType.TEXT:
|
||||||
|
return await bot.send_message(chat_id, storage["mailing_text"], parse_mode="HTML")
|
||||||
|
if content_type == types.ContentType.LOCATION:
|
||||||
|
return await bot.send_location(chat_id, storage["mailing_location"][0], storage["mailing_location"][1])
|
||||||
|
if content_type in (types.ContentType.AUDIO, types.ContentType.VIDEO, types.ContentType.DOCUMENT,
|
||||||
|
types.ContentType.PHOTO):
|
||||||
|
caption = storage.get("mailing_caption")
|
||||||
|
if storage.get("mailing_id"):
|
||||||
|
logging.info("Mailing use file id")
|
||||||
|
obj = storage["mailing_id"]
|
||||||
|
else:
|
||||||
|
logging.info("Mailing upload file")
|
||||||
|
obj = types.InputFile(BytesIO(storage["mailing_data"]), filename=storage.get("mailing_file_name"))
|
||||||
|
|
||||||
|
if content_type == types.ContentType.AUDIO:
|
||||||
|
return (await bot.send_audio(chat_id, audio=obj, caption=caption)).audio.file_id
|
||||||
|
if content_type == types.ContentType.PHOTO:
|
||||||
|
return (await bot.send_photo(chat_id, photo=obj, caption=caption)).photo[-1].file_id
|
||||||
|
if content_type == types.ContentType.VIDEO:
|
||||||
|
return (await bot.send_video(chat_id, video=obj, caption=caption)).video.file_id
|
||||||
|
if content_type == types.ContentType.DOCUMENT:
|
||||||
|
return (await bot.send_document(chat_id, document=obj, caption=caption)).document.file_id
|
||||||
|
|
||||||
|
raise NotImplementedError("Mailing, unknown content type")
|
||||||
|
|
1378
poetry.lock
generated
1378
poetry.lock
generated
File diff suppressed because it is too large
Load Diff
|
@ -1 +1 @@
|
||||||
/usr/lib/python3.10/Tools/i18n/pygettext.py -d chinese -o locales/olgram.pot olgram/ server/
|
/usr/lib/python3.11/Tools/i18n/pygettext.py -d chinese -o locales/olgram.pot olgram/ server/
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
import asyncio
|
||||||
|
|
||||||
from aiogram import Bot as AioBot, Dispatcher
|
from aiogram import Bot as AioBot, Dispatcher
|
||||||
from aiogram.dispatcher.webhook import WebhookRequestHandler
|
from aiogram.dispatcher.webhook import WebhookRequestHandler
|
||||||
from aiogram.dispatcher.webhook import SendMessage
|
from aiogram.dispatcher.webhook import SendMessage
|
||||||
|
@ -11,7 +13,7 @@ from tortoise.expressions import F
|
||||||
import logging
|
import logging
|
||||||
import typing as ty
|
import typing as ty
|
||||||
from olgram.settings import ServerSettings
|
from olgram.settings import ServerSettings
|
||||||
from olgram.models.models import Bot, GroupChat, BannedUser, BotStartMessage, BotSecondMessage
|
from olgram.models.models import Bot, GroupChat, BannedUser, BotStartMessage, BotSecondMessage, MailingUser
|
||||||
from locales.locale import _, translators
|
from locales.locale import _, translators
|
||||||
from server.inlines import inline_handler
|
from server.inlines import inline_handler
|
||||||
|
|
||||||
|
@ -55,15 +57,20 @@ def _on_security_policy(message: types.Message, bot):
|
||||||
text = _("<b>Политика конфиденциальности</b>\n\n"
|
text = _("<b>Политика конфиденциальности</b>\n\n"
|
||||||
"Этот бот не хранит ваши сообщения, имя пользователя и @username. При отправке сообщения (кроме команд "
|
"Этот бот не хранит ваши сообщения, имя пользователя и @username. При отправке сообщения (кроме команд "
|
||||||
"/start и /security_policy) ваш идентификатор пользователя записывается в кеш на некоторое время и потом "
|
"/start и /security_policy) ваш идентификатор пользователя записывается в кеш на некоторое время и потом "
|
||||||
"удаляется из кеша. Этот идентификатор используется только для общения с оператором; боты Olgram "
|
"удаляется из кеша. Этот идентификатор используется для общения с оператором.\n\n")
|
||||||
"не делают массовых рассылок.\n\n")
|
|
||||||
if bot.enable_additional_info:
|
if bot.enable_additional_info:
|
||||||
text += _("При отправке сообщения (кроме команд /start и /security_policy) оператор <b>видит</b> ваши имя "
|
text += _("При отправке сообщения (кроме команд /start и /security_policy) оператор <b>видит</b> ваши имя "
|
||||||
"пользователя, @username и идентификатор пользователя в силу настроек, которые оператор указал при "
|
"пользователя, @username и идентификатор пользователя в силу настроек, которые оператор указал при "
|
||||||
"создании бота.")
|
"создании бота.\n\n")
|
||||||
else:
|
else:
|
||||||
text += _("В зависимости от ваших настроек конфиденциальности Telegram, оператор может видеть ваш username, "
|
text += _("В зависимости от ваших настроек конфиденциальности Telegram, оператор может видеть ваш username, "
|
||||||
"имя пользователя и другую информацию.")
|
"имя пользователя и другую информацию.\n\n")
|
||||||
|
|
||||||
|
if bot.enable_mailing:
|
||||||
|
text += _("В этом боте включена массовая рассылка в силу настроек, которые оператор указал при создании бота. "
|
||||||
|
"Ваш идентификатор пользователя может быть записан в базу данных на долгое время")
|
||||||
|
else:
|
||||||
|
text += _("В этом боте нет массовой рассылки сообщений")
|
||||||
|
|
||||||
return SendMessage(chat_id=message.chat.id,
|
return SendMessage(chat_id=message.chat.id,
|
||||||
text=text,
|
text=text,
|
||||||
|
@ -106,31 +113,43 @@ async def send_user_message(message: types.Message, super_chat_id: int, bot):
|
||||||
async def send_to_superchat(is_super_group: bool, message: types.Message, super_chat_id: int, bot):
|
async def send_to_superchat(is_super_group: bool, message: types.Message, super_chat_id: int, bot):
|
||||||
"""Пересылка сообщения от пользователя оператору (логика потоков сообщений)"""
|
"""Пересылка сообщения от пользователя оператору (логика потоков сообщений)"""
|
||||||
if is_super_group and bot.enable_threads:
|
if is_super_group and bot.enable_threads:
|
||||||
|
if bot.enable_thread_interrupt:
|
||||||
|
thread_timeout = ServerSettings.thread_timeout_ms()
|
||||||
|
else:
|
||||||
|
thread_timeout = ServerSettings.redis_timeout_ms()
|
||||||
thread_first_message = await _redis.get(_thread_uniqie_id(bot.pk, message.chat.id))
|
thread_first_message = await _redis.get(_thread_uniqie_id(bot.pk, message.chat.id))
|
||||||
if thread_first_message:
|
if thread_first_message:
|
||||||
# переслать в супер-чат, отвечая на предыдущее сообщение
|
# переслать в супер-чат, отвечая на предыдущее сообщение
|
||||||
try:
|
try:
|
||||||
new_message = await message.copy_to(super_chat_id, reply_to_message_id=int(thread_first_message))
|
new_message = await message.copy_to(super_chat_id, reply_to_message_id=int(thread_first_message))
|
||||||
await _redis.set(_message_unique_id(bot.pk, new_message.message_id), message.chat.id,
|
await _redis.set(_message_unique_id(bot.pk, new_message.message_id), message.chat.id,
|
||||||
pexpire=ServerSettings.redis_timeout_ms())
|
pexpire=thread_timeout)
|
||||||
except exceptions.BadRequest:
|
except exceptions.BadRequest:
|
||||||
new_message = await send_user_message(message, super_chat_id, bot)
|
new_message = await send_user_message(message, super_chat_id, bot)
|
||||||
await _redis.set(_thread_uniqie_id(bot.pk, message.chat.id), new_message.message_id,
|
await _redis.set(
|
||||||
pexpire=ServerSettings.thread_timeout_ms())
|
_thread_uniqie_id(bot.pk, message.chat.id), new_message.message_id, pexpire=thread_timeout)
|
||||||
else:
|
else:
|
||||||
# переслать супер-чат
|
# переслать супер-чат
|
||||||
new_message = await send_user_message(message, super_chat_id, bot)
|
new_message = await send_user_message(message, super_chat_id, bot)
|
||||||
await _redis.set(_thread_uniqie_id(bot.pk, message.chat.id), new_message.message_id,
|
await _redis.set(_thread_uniqie_id(bot.pk, message.chat.id), new_message.message_id,
|
||||||
pexpire=ServerSettings.thread_timeout_ms())
|
pexpire=thread_timeout)
|
||||||
else: # личные сообщения не поддерживают потоки сообщений: просто отправляем сообщение
|
else: # личные сообщения не поддерживают потоки сообщений: просто отправляем сообщение
|
||||||
await send_user_message(message, super_chat_id, bot)
|
await send_user_message(message, super_chat_id, bot)
|
||||||
|
|
||||||
|
|
||||||
|
async def _increase_count(_bot):
|
||||||
|
_bot.incoming_messages_count = F("incoming_messages_count") + 1
|
||||||
|
await _bot.save(update_fields=["incoming_messages_count"])
|
||||||
|
|
||||||
|
|
||||||
async def handle_user_message(message: types.Message, super_chat_id: int, bot):
|
async def handle_user_message(message: types.Message, super_chat_id: int, bot):
|
||||||
"""Обычный пользователь прислал сообщение в бот, нужно переслать его операторам"""
|
"""Обычный пользователь прислал сообщение в бот, нужно переслать его операторам"""
|
||||||
_ = _get_translator(message)
|
_ = _get_translator(message)
|
||||||
is_super_group = super_chat_id < 0
|
is_super_group = super_chat_id < 0
|
||||||
|
|
||||||
|
if bot.enable_mailing:
|
||||||
|
asyncio.create_task(MailingUser.get_or_create(telegram_id=message.chat.id, bot=bot))
|
||||||
|
|
||||||
# Проверить, не забанен ли пользователь
|
# Проверить, не забанен ли пользователь
|
||||||
banned = await bot.banned_users.filter(telegram_id=message.chat.id)
|
banned = await bot.banned_users.filter(telegram_id=message.chat.id)
|
||||||
if banned:
|
if banned:
|
||||||
|
@ -153,8 +172,7 @@ async def handle_user_message(message: types.Message, super_chat_id: int, bot):
|
||||||
_logger.error(f"(exception on forwarding) {err}")
|
_logger.error(f"(exception on forwarding) {err}")
|
||||||
return
|
return
|
||||||
|
|
||||||
bot.incoming_messages_count = F("incoming_messages_count") + 1
|
asyncio.create_task(_increase_count(bot))
|
||||||
await bot.save(update_fields=["incoming_messages_count"])
|
|
||||||
|
|
||||||
# И отправить пользователю специальный текст, если он указан и если давно не отправляли
|
# И отправить пользователю специальный текст, если он указан и если давно не отправляли
|
||||||
if bot.second_text:
|
if bot.second_text:
|
||||||
|
@ -211,6 +229,8 @@ async def handle_operator_message(message: types.Message, super_chat_id: int, bo
|
||||||
|
|
||||||
elif super_chat_id > 0:
|
elif super_chat_id > 0:
|
||||||
# в супер-чате кто-то пишет сообщение сам себе, только для личных сообщений
|
# в супер-чате кто-то пишет сообщение сам себе, только для личных сообщений
|
||||||
|
if bot.enable_mailing:
|
||||||
|
asyncio.create_task(MailingUser.get_or_create(telegram_id=message.chat.id, bot=bot))
|
||||||
await message.forward(super_chat_id)
|
await message.forward(super_chat_id)
|
||||||
# И отправить пользователю специальный текст, если он указан
|
# И отправить пользователю специальный текст, если он указан
|
||||||
if bot.second_text:
|
if bot.second_text:
|
||||||
|
|
Loading…
Reference in New Issue
Block a user