mirror of
https://github.com/civsocit/olgram.git
synced 2025-12-16 22:06:17 +00:00
Compare commits
34 Commits
bb1456dda1
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2305590899 | ||
|
|
a34e633b98 | ||
|
|
16da3634db | ||
|
|
a0c6c9415e | ||
|
|
dab803a4e8 | ||
|
|
0ceea778fe | ||
|
|
7ce6df7fd9 | ||
|
|
59da56d463 | ||
|
|
1c12730a4e | ||
|
|
d0b570baa9 | ||
|
|
1b1fe239f8 | ||
|
|
214824db14 | ||
|
|
147fc2a665 | ||
|
|
c027ec656b | ||
|
|
f79a9f317d | ||
|
|
eeb6c65f36 | ||
|
|
7a0ce10c56 | ||
|
|
44f39e4de0 | ||
|
|
120fdef189 | ||
|
|
f26958518c | ||
|
|
acb62fb644 | ||
|
|
ae45374490 | ||
|
|
7aacb2e38f | ||
|
|
0881c86349 | ||
|
|
1dd4d4d7fd | ||
|
|
82b68d1d9f | ||
|
|
02e91a596c | ||
|
|
a5e6fbce34 | ||
|
|
28ed36ffeb | ||
|
|
601c16622d | ||
|
|
9e46041d0f | ||
|
|
f41e17a15c | ||
|
|
a262d4e488 | ||
|
|
3e1f89034a |
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 && \
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
О проекте
|
О проекте
|
||||||
===================================
|
===================================
|
||||||
|
|
||||||
|
|
||||||
Зачем нужен Olgram
|
Зачем нужен Olgram
|
||||||
------------
|
------------
|
||||||
|
|
||||||
|
|||||||
@@ -4,21 +4,30 @@
|
|||||||
Донаты
|
Донаты
|
||||||
----------------
|
----------------
|
||||||
|
|
||||||
На рекламу проекта, аренду сервера и пиццу
|
На аренду сервера для этого проекта
|
||||||
|
|
||||||
Bitcoin:
|
Bitcoin:
|
||||||
``bc1qlq7cm5chc8flr3fy8ewk967aknq3dwmxtwn9hl``
|
``bc1qlq7cm5chc8flr3fy8ewk967aknq3dwmxtwn9hl``
|
||||||
|
|
||||||
Monero:
|
Litecoin:
|
||||||
``886AQ8tCVcQKp21xsuSLkfDdTAdtCFH1jR58Tw9MsaxFXoZ7YRHXx1cQcUfUnDX6hySzPsQEVt6RWPn3sXH9QUmwCr3oVqB``
|
``ltc1qxajsvz0lw44aa5nytuch8cp2g8x7a4cdase4y7``
|
||||||
|
|
||||||
Dash:
|
Monero:
|
||||||
``XqxetfWzr5n4Ms1TxMbdEEeHGe8CaMdmb6``
|
``84ymMfpw3vxFxsgmYbFURMiZLgQCmhKsZNiZiqZRbpH2WRka2UDjyDVZpX8XH1cZ9d5EghvPXrF5hEuzvK5NvHGE8za4Gmk``
|
||||||
|
|
||||||
|
Как убрать "Этот бот создан с помощью ..."
|
||||||
|
----------------
|
||||||
|
Напишите нам на `@civsocit_feedback_bot <https://t.me/civsocit_feedback_bot>`_.
|
||||||
|
|
||||||
|
|
||||||
История изменений
|
История изменений
|
||||||
----------------
|
----------------
|
||||||
|
|
||||||
|
- `2024-03-15` Тэги
|
||||||
|
- `2024-03-02` Рассылки
|
||||||
|
- `2024-03-01` Непрерывные потоки сообщений (опция)
|
||||||
|
- `2024-02-17` Опция смены режима работы автоответчика: автоответчик отвечает на КАЖДОЕ сообщение
|
||||||
|
- `2024-01-12` Мультиязычность (стартовое сообщение и автоответчик)
|
||||||
- `2022-08-01` Защита от флуда
|
- `2022-08-01` Защита от флуда
|
||||||
- `2022-07-23` Автоответчик не пишет сообщение лишний раз
|
- `2022-07-23` Автоответчик не пишет сообщение лишний раз
|
||||||
- `2022-07-04` Поддержка двух ботов в одном чате
|
- `2022-07-04` Поддержка двух ботов в одном чате
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
# -- Project information
|
# -- Project information
|
||||||
|
|
||||||
project = 'Olgram'
|
project = 'Olgram'
|
||||||
copyright = '2022, Civsocit'
|
copyright = '2024, Civsocit'
|
||||||
author = 'civsocit'
|
author = 'civsocit'
|
||||||
|
|
||||||
release = '0.1'
|
release = '0.1'
|
||||||
|
|||||||
@@ -49,3 +49,35 @@ Olgram пересылает сообщения так, чтобы сообщен
|
|||||||
|
|
||||||
При включении этой опции пользователю запрещается отправлять больше одного сообщения в минуту. Используйте её, если
|
При включении этой опции пользователю запрещается отправлять больше одного сообщения в минуту. Используйте её, если
|
||||||
не успеваете обрабатывать входящие сообщения.
|
не успеваете обрабатывать входящие сообщения.
|
||||||
|
|
||||||
|
|
||||||
|
.. _always_second_message:
|
||||||
|
|
||||||
|
Использовать автоответчик всегда
|
||||||
|
--------------------------------
|
||||||
|
|
||||||
|
По-умолчанию автоответчик отвечает только на первое сообщение в диалоге с пользователем. Чтобы автоответчик отвечал на
|
||||||
|
КАЖДОЕ входящее сообщение, включите эту опцию.
|
||||||
|
|
||||||
|
|
||||||
|
.. thread_interrupt:
|
||||||
|
|
||||||
|
Прерывать поток
|
||||||
|
--------------------------------
|
||||||
|
|
||||||
|
По-умолчанию поток сообщений от одного пользователя прерывается каждые 24 часа. Без этой опции поток сообщений не
|
||||||
|
прерывается никогда.
|
||||||
|
|
||||||
|
|
||||||
|
.. _mailing:
|
||||||
|
|
||||||
|
Рассылка
|
||||||
|
---------------
|
||||||
|
|
||||||
|
После включения этой опции ваш бот будет запоминать всех пользователей, которые пишут в ваш бот.
|
||||||
|
Вы сможете запустить рассылку по этим пользователям.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
Включение этой опции меняет текст политики конфиденциальности вашего feedback бота (команда /security_policy)
|
||||||
|
и может отпугнуть некоторых пользователей. Не включайте эту опцию без необходимости.
|
||||||
|
|||||||
@@ -68,6 +68,13 @@ BotFather - это официальный бот Telegram, создающий д
|
|||||||
|
|
||||||
Теперь просто отправьте новый текст приветствия.
|
Теперь просто отправьте новый текст приветствия.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
Чтобы настроить особый текст приветствия для, например, русскоязычных пользователей (т.е. тех пользователей, у
|
||||||
|
которых в настройках Telegram выставлена русская локализация), нажмите кнопку "Руссикй 🇷🇺" и только потом отправьте
|
||||||
|
текст приветствия. Чтобы отредактировать текст приветствия для всех остальных языков, нажмите "[все языки]".
|
||||||
|
|
||||||
|
|
||||||
Как привязать бота к групповому чату
|
Как привязать бота к групповому чату
|
||||||
------------------------------------
|
------------------------------------
|
||||||
|
|
||||||
@@ -108,3 +115,14 @@ BotFather - это официальный бот Telegram, создающий д
|
|||||||
|
|
||||||
Если у вас возникли вопросы по использованию бота, или вы нашли ошибку - напишите
|
Если у вас возникли вопросы по использованию бота, или вы нашли ошибку - напишите
|
||||||
нам `@civsocit_feedback_bot <https://t.me/civsocit_feedback_bot>`_.
|
нам `@civsocit_feedback_bot <https://t.me/civsocit_feedback_bot>`_.
|
||||||
|
|
||||||
|
Тэги пользователей
|
||||||
|
------------------
|
||||||
|
|
||||||
|
Пользователям можно проставлять теги. Например, в ответ на сообщение пользователя написать:
|
||||||
|
|
||||||
|
```
|
||||||
|
/tag #important
|
||||||
|
```
|
||||||
|
|
||||||
|
Тогда в user info (см. раздел опции) помимо информации о пользователе будет тег #important
|
||||||
|
|||||||
@@ -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>\n"
|
" <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>"
|
||||||
|
|
||||||
|
|||||||
@@ -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,69 +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>\n"
|
" <pre>{1}</pre>\n"
|
||||||
" {1}\n"
|
|
||||||
" </pre>\n"
|
|
||||||
" Отправьте сообщение, чтобы изменить текст.\n"
|
" Отправьте сообщение, чтобы изменить текст.\n"
|
||||||
" "
|
" "
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"\n"
|
|
||||||
" Зараз ви редагуєте текст, який надсилається після того, як користувач "
|
|
||||||
"надішле вашому боту @{0}\n"
|
|
||||||
" команду /start\n"
|
|
||||||
"\n"
|
|
||||||
" Поточний текст:\n"
|
|
||||||
" <pre>\n"
|
|
||||||
" {1}\n"
|
|
||||||
" </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"
|
||||||
@@ -446,45 +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>\n"
|
" <pre>{1}</pre>\n"
|
||||||
" {1}\n"
|
|
||||||
" </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"
|
||||||
@@ -510,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"
|
||||||
@@ -629,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"
|
||||||
@@ -653,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>"
|
||||||
@@ -699,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>"
|
||||||
|
|
||||||
|
|||||||
@@ -306,9 +306,7 @@ msgid ""
|
|||||||
" команду /start\n"
|
" команду /start\n"
|
||||||
"\n"
|
"\n"
|
||||||
" Текущий текст:\n"
|
" Текущий текст:\n"
|
||||||
" <pre>\n"
|
" <pre>{1}</pre>\n"
|
||||||
" {1}\n"
|
|
||||||
" </pre>\n"
|
|
||||||
" Отправьте сообщение, чтобы изменить текст.\n"
|
" Отправьте сообщение, чтобы изменить текст.\n"
|
||||||
" "
|
" "
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -317,9 +315,7 @@ msgstr ""
|
|||||||
" /start\n"
|
" /start\n"
|
||||||
"\n"
|
"\n"
|
||||||
" 目前的文本。\n"
|
" 目前的文本。\n"
|
||||||
" <pre>\n"
|
" <pre>{1}</pre>\n"
|
||||||
" {1}\n"
|
|
||||||
" </pre>\n"
|
|
||||||
" 发送消息,改变文本。\n"
|
" 发送消息,改变文本。\n"
|
||||||
" "
|
" "
|
||||||
|
|
||||||
@@ -359,9 +355,7 @@ msgid ""
|
|||||||
"отключено.\n"
|
"отключено.\n"
|
||||||
"\n"
|
"\n"
|
||||||
" Текущий текст:\n"
|
" Текущий текст:\n"
|
||||||
" <pre>\n"
|
" <pre>{1}</pre>\n"
|
||||||
" {1}\n"
|
|
||||||
" </pre>\n"
|
|
||||||
" Отправьте сообщение, чтобы изменить текст.\n"
|
" Отправьте сообщение, чтобы изменить текст.\n"
|
||||||
" "
|
" "
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@@ -370,9 +364,7 @@ msgstr ""
|
|||||||
"默认情况下,它是禁用的。\n"
|
"默认情况下,它是禁用的。\n"
|
||||||
"\n"
|
"\n"
|
||||||
" 目前的文本。\n"
|
" 目前的文本。\n"
|
||||||
" <pre>\n"
|
" <pre>{1}</pre>。\n"
|
||||||
" {1}\n"
|
|
||||||
" </pre>。\n"
|
|
||||||
" 发送消息,改变文本。\n"
|
" 发送消息,改变文本。\n"
|
||||||
" "
|
" "
|
||||||
|
|
||||||
|
|||||||
2
main.py
2
main.py
@@ -7,9 +7,9 @@ from olgram.settings import TORTOISE_ORM, OlgramSettings
|
|||||||
from olgram.utils.permissions import AccessMiddleware
|
from olgram.utils.permissions import AccessMiddleware
|
||||||
from server.custom import init_redis
|
from server.custom import init_redis
|
||||||
|
|
||||||
|
import olgram.commands.menu # noqa: F401
|
||||||
import olgram.commands.bots # noqa: F401
|
import olgram.commands.bots # noqa: F401
|
||||||
import olgram.commands.start # noqa: F401
|
import olgram.commands.start # noqa: F401
|
||||||
import olgram.commands.menu # noqa: F401
|
|
||||||
import olgram.commands.bot_actions # noqa: F401
|
import olgram.commands.bot_actions # noqa: F401
|
||||||
import olgram.commands.info # noqa: F401
|
import olgram.commands.info # noqa: F401
|
||||||
import olgram.commands.promo # noqa: F401
|
import olgram.commands.promo # noqa: F401
|
||||||
|
|||||||
@@ -1,10 +1,15 @@
|
|||||||
"""
|
"""
|
||||||
Здесь работа с конкретным ботом
|
Здесь работа с конкретным ботом
|
||||||
"""
|
"""
|
||||||
|
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
|
from olgram.models.models import Bot, BotStartMessage, BotSecondMessage
|
||||||
from server.server import unregister_token
|
from server.server import unregister_token
|
||||||
from locales.locale import _
|
from locales.locale import _
|
||||||
|
|
||||||
@@ -15,38 +20,50 @@ 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
|
||||||
|
|
||||||
|
|
||||||
async def reset_bot_text(bot: Bot, call: types.CallbackQuery):
|
async def reset_bot_text(bot: Bot, call: types.CallbackQuery, state):
|
||||||
"""
|
"""
|
||||||
Пользователь решил сбросить текст бота к default
|
Пользователь решил сбросить текст бота к default
|
||||||
:param bot:
|
:param bot:
|
||||||
:param call:
|
:param call:
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
bot.start_text = bot._meta.fields_map['start_text'].default
|
async with state.proxy() as proxy:
|
||||||
await bot.save()
|
lang = proxy.get("lang", "none")
|
||||||
|
if lang == "none":
|
||||||
|
await BotStartMessage.filter(bot=bot).delete()
|
||||||
|
bot.start_text = bot._meta.fields_map['start_text'].default
|
||||||
|
await bot.save(update_fields=["start_text"])
|
||||||
|
else:
|
||||||
|
await BotStartMessage.filter(bot=bot, locale=lang).delete()
|
||||||
await call.answer(_("Текст сброшен"))
|
await call.answer(_("Текст сброшен"))
|
||||||
|
|
||||||
|
|
||||||
async def reset_bot_second_text(bot: Bot, call: types.CallbackQuery):
|
async def reset_bot_second_text(bot: Bot, call: types.CallbackQuery, state):
|
||||||
"""
|
"""
|
||||||
Пользователь решил сбросить second text бота
|
Пользователь решил сбросить second text бота
|
||||||
:param bot:
|
:param bot:
|
||||||
:param call:
|
:param call:
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
bot.second_text = bot._meta.fields_map['second_text'].default
|
async with state.proxy() as proxy:
|
||||||
await bot.save()
|
lang = proxy.get("lang", "none")
|
||||||
|
if lang == "none":
|
||||||
|
await BotSecondMessage.filter(bot=bot).delete()
|
||||||
|
bot.second_text = bot._meta.fields_map['second_text'].default
|
||||||
|
await bot.save(update_fields=["second_text"])
|
||||||
|
else:
|
||||||
|
await BotSecondMessage.filter(bot=bot, locale=lang).delete()
|
||||||
await call.answer(_("Текст сброшен"))
|
await call.answer(_("Текст сброшен"))
|
||||||
|
|
||||||
|
|
||||||
@@ -72,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()
|
||||||
@@ -97,6 +114,16 @@ async def additional_info(bot: Bot, call: types.CallbackQuery):
|
|||||||
await bot.save(update_fields=["enable_additional_info"])
|
await bot.save(update_fields=["enable_additional_info"])
|
||||||
|
|
||||||
|
|
||||||
|
async def always_second_message(bot: Bot, call: types.CallbackQuery):
|
||||||
|
bot.enable_always_second_message = not bot.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
|
||||||
@@ -106,3 +133,43 @@ 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 tags(bot: Bot, call: types.CallbackQuery):
|
||||||
|
bot.enable_tags = not bot.enable_tags
|
||||||
|
await bot.save(update_fields=["enable_tags"])
|
||||||
|
|
||||||
|
|
||||||
|
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
|
||||||
|
|||||||
@@ -37,4 +37,4 @@ async def info(message: types.Message, state: FSMContext):
|
|||||||
_("Входящих сообщений у всех ботов: {0}\n").format(income_messages) +
|
_("Входящих сообщений у всех ботов: {0}\n").format(income_messages) +
|
||||||
_("Исходящих сообщений у всех ботов: {0}\n").format(outgoing_messages) +
|
_("Исходящих сообщений у всех ботов: {0}\n").format(outgoing_messages) +
|
||||||
_("Промо-кодов выдано: {0}\n").format(promo_count) +
|
_("Промо-кодов выдано: {0}\n").format(promo_count) +
|
||||||
_("Рекламную плашку выключили: {0}\n".format(olgram_text_disabled)))
|
_("Рекламную плашку выключили: {0}\n").format(olgram_text_disabled))
|
||||||
|
|||||||
@@ -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
|
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}.
|
||||||
@@ -172,6 +180,29 @@ async def send_bot_settings_menu(bot: Bot, call: types.CallbackQuery):
|
|||||||
callback_data=menu_callback.new(level=3, bot_id=bot.id, operation="antiflood",
|
callback_data=menu_callback.new(level=3, bot_id=bot.id, operation="antiflood",
|
||||||
chat=empty))
|
chat=empty))
|
||||||
)
|
)
|
||||||
|
keyboard.insert(
|
||||||
|
types.InlineKeyboardButton(text=_("Автоответчик всегда"),
|
||||||
|
callback_data=menu_callback.new(level=3, bot_id=bot.id,
|
||||||
|
operation="always_second_message",
|
||||||
|
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))
|
||||||
|
)
|
||||||
|
keyboard.insert(
|
||||||
|
types.InlineKeyboardButton(text=_("Теги"),
|
||||||
|
callback_data=menu_callback.new(level=3, bot_id=bot.id,
|
||||||
|
operation="tags",
|
||||||
|
chat=empty))
|
||||||
|
)
|
||||||
is_promo = await bot.is_promo()
|
is_promo = await bot.is_promo()
|
||||||
if is_promo:
|
if is_promo:
|
||||||
keyboard.insert(
|
keyboard.insert(
|
||||||
@@ -189,11 +220,20 @@ async def send_bot_settings_menu(bot: Bot, call: types.CallbackQuery):
|
|||||||
thread_turn = _("включены") if bot.enable_threads else _("выключены")
|
thread_turn = _("включены") if bot.enable_threads else _("выключены")
|
||||||
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 _("выключен")
|
||||||
|
thread_interrupt = _("да") if bot.enable_thread_interrupt else _("нет")
|
||||||
|
mailing_turn = _("включена") if bot.enable_mailing else _("выключена")
|
||||||
|
tags_turn = _("включены") if bot.enable_tags 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>
|
||||||
""")).format(thread_turn, info_turn, antiflood_turn)
|
<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#thread_interrupt">Прерывать поток</a>: <b>{4}</b>
|
||||||
|
<a href="https://olgram.readthedocs.io/ru/latest/options.html#mailing">Рассылка</a>: <b>{5}</b>
|
||||||
|
Теги: <b>{6}</b>
|
||||||
|
""")).format(thread_turn, info_turn, antiflood_turn, enable_always_second_message, thread_interrupt,
|
||||||
|
mailing_turn, tags_turn)
|
||||||
|
|
||||||
if is_promo:
|
if is_promo:
|
||||||
olgram_turn = _("включена") if bot.enable_olgram_text else _("выключена")
|
olgram_turn = _("включена") if bot.enable_olgram_text else _("выключена")
|
||||||
@@ -202,9 +242,26 @@ async def send_bot_settings_menu(bot: Bot, call: types.CallbackQuery):
|
|||||||
await edit_or_create(call, text, reply_markup=keyboard, parse_mode="HTML")
|
await edit_or_create(call, text, reply_markup=keyboard, parse_mode="HTML")
|
||||||
|
|
||||||
|
|
||||||
async def send_bot_text_menu(bot: Bot, call: ty.Optional[types.CallbackQuery] = None, chat_id: ty.Optional[int] = None):
|
languages = {
|
||||||
|
"en": "English 🇺🇸",
|
||||||
|
"ru": "Русский 🇷🇺",
|
||||||
|
"uk": "Український 🇺🇦",
|
||||||
|
"tr": "Türkçe 🇹🇷",
|
||||||
|
"hy": "հայերեն 🇦🇲",
|
||||||
|
"ka": "ქართული ენა 🇬🇪"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async def send_bot_text_menu(bot: Bot, call: ty.Optional[types.CallbackQuery] = None, chat_id: ty.Optional[int] = None,
|
||||||
|
state=None):
|
||||||
if call:
|
if call:
|
||||||
await call.answer()
|
await call.answer()
|
||||||
|
|
||||||
|
async with state.proxy() as proxy:
|
||||||
|
lang = proxy.get("lang", "none")
|
||||||
|
|
||||||
|
prepared_languages = {ln.locale: ln.text for ln in await bot.start_texts}
|
||||||
|
|
||||||
keyboard = types.InlineKeyboardMarkup(row_width=2)
|
keyboard = types.InlineKeyboardMarkup(row_width=2)
|
||||||
keyboard.insert(
|
keyboard.insert(
|
||||||
types.InlineKeyboardButton(text=_("<< Завершить редактирование"),
|
types.InlineKeyboardButton(text=_("<< Завершить редактирование"),
|
||||||
@@ -215,29 +272,129 @@ async def send_bot_text_menu(bot: Bot, call: ty.Optional[types.CallbackQuery] =
|
|||||||
callback_data=menu_callback.new(level=3, bot_id=bot.id, operation="next_text",
|
callback_data=menu_callback.new(level=3, bot_id=bot.id, operation="next_text",
|
||||||
chat=empty))
|
chat=empty))
|
||||||
)
|
)
|
||||||
keyboard.insert(
|
keyboard.row(
|
||||||
types.InlineKeyboardButton(text=_("Сбросить текст"),
|
types.InlineKeyboardButton(text=_("Сбросить текст"),
|
||||||
callback_data=menu_callback.new(level=3, bot_id=bot.id, operation="reset_text",
|
callback_data=menu_callback.new(level=3, bot_id=bot.id, operation="reset_text",
|
||||||
chat=empty))
|
chat=empty))
|
||||||
)
|
)
|
||||||
|
keyboard.add(
|
||||||
|
types.InlineKeyboardButton(text=("🟢 " if lang == "none" else "") + _("[все языки]"),
|
||||||
|
callback_data=menu_callback.new(level=3, bot_id=bot.id,
|
||||||
|
operation="slang_none", chat=empty))
|
||||||
|
)
|
||||||
|
for code, name in languages.items():
|
||||||
|
prefix = ""
|
||||||
|
if code == lang:
|
||||||
|
prefix = "🟢 "
|
||||||
|
elif code in prepared_languages:
|
||||||
|
prefix = "✔️ "
|
||||||
|
keyboard.insert(
|
||||||
|
types.InlineKeyboardButton(text=prefix + name,
|
||||||
|
callback_data=menu_callback.new(level=3, bot_id=bot.id,
|
||||||
|
operation=f"slang_{code}",
|
||||||
|
chat=empty))
|
||||||
|
)
|
||||||
|
|
||||||
text = dedent(_("""
|
text = dedent(_("""
|
||||||
Сейчас вы редактируете текст, который отправляется после того, как пользователь отправит вашему боту @{0}
|
Сейчас вы редактируете текст, который отправляется после того, как пользователь отправит вашему боту @{0}
|
||||||
команду /start
|
команду /start
|
||||||
|
|
||||||
Текущий текст:
|
Текущий текст{2}:
|
||||||
<pre>
|
<pre>{1}</pre>
|
||||||
{1}
|
|
||||||
</pre>
|
|
||||||
Отправьте сообщение, чтобы изменить текст.
|
Отправьте сообщение, чтобы изменить текст.
|
||||||
"""))
|
"""))
|
||||||
text = text.format(bot.name, bot.start_text)
|
text = text.format(bot.name,
|
||||||
|
prepared_languages.get(lang, bot.start_text),
|
||||||
|
_(" (для языка {0})").format(languages[lang]) if lang != "none" else "")
|
||||||
if call:
|
if call:
|
||||||
await edit_or_create(call, text, keyboard, parse_mode="HTML")
|
await edit_or_create(call, text, keyboard, parse_mode="HTML")
|
||||||
else:
|
else:
|
||||||
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
|
||||||
|
if obj.file_size and obj.file_size > 4194304:
|
||||||
|
return await message.answer(_("Слишком большой файл (4 Мб максимум)"))
|
||||||
|
|
||||||
|
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", None)
|
||||||
|
_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=1, bot_id=bot_id, operation=empty, chat=empty))
|
||||||
|
)
|
||||||
|
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:
|
||||||
@@ -264,9 +421,15 @@ async def send_bot_statistic_menu(bot: Bot, call: ty.Optional[types.CallbackQuer
|
|||||||
|
|
||||||
|
|
||||||
async def send_bot_second_text_menu(bot: Bot, call: ty.Optional[types.CallbackQuery] = None,
|
async def send_bot_second_text_menu(bot: Bot, call: ty.Optional[types.CallbackQuery] = None,
|
||||||
chat_id: ty.Optional[int] = None):
|
chat_id: ty.Optional[int] = None, state=None):
|
||||||
if call:
|
if call:
|
||||||
await call.answer()
|
await call.answer()
|
||||||
|
|
||||||
|
async with state.proxy() as proxy:
|
||||||
|
lang = proxy.get("lang", "none")
|
||||||
|
|
||||||
|
prepared_languages = {ln.locale: ln.text for ln in await bot.second_texts}
|
||||||
|
|
||||||
keyboard = types.InlineKeyboardMarkup(row_width=2)
|
keyboard = types.InlineKeyboardMarkup(row_width=2)
|
||||||
keyboard.insert(
|
keyboard.insert(
|
||||||
types.InlineKeyboardButton(text=_("<< Завершить редактирование"),
|
types.InlineKeyboardButton(text=_("<< Завершить редактирование"),
|
||||||
@@ -287,18 +450,35 @@ async def send_bot_second_text_menu(bot: Bot, call: ty.Optional[types.CallbackQu
|
|||||||
callback_data=menu_callback.new(level=3, bot_id=bot.id,
|
callback_data=menu_callback.new(level=3, bot_id=bot.id,
|
||||||
operation="reset_second_text", chat=empty))
|
operation="reset_second_text", chat=empty))
|
||||||
)
|
)
|
||||||
|
keyboard.add(
|
||||||
|
types.InlineKeyboardButton(text=("🟢 " if lang == "none" else "") + _("[все языки]"),
|
||||||
|
callback_data=menu_callback.new(level=3, bot_id=bot.id,
|
||||||
|
operation="alang_none", chat=empty))
|
||||||
|
)
|
||||||
|
for code, name in languages.items():
|
||||||
|
prefix = ""
|
||||||
|
if code == lang:
|
||||||
|
prefix = "🟢 "
|
||||||
|
elif code in prepared_languages:
|
||||||
|
prefix = "✔️ "
|
||||||
|
keyboard.insert(
|
||||||
|
types.InlineKeyboardButton(text=prefix + name,
|
||||||
|
callback_data=menu_callback.new(level=3, bot_id=bot.id,
|
||||||
|
operation=f"alang_{code}",
|
||||||
|
chat=empty))
|
||||||
|
)
|
||||||
|
|
||||||
text = dedent(_("""
|
text = dedent(_("""
|
||||||
Сейчас вы редактируете текст автоответчика. Это сообщение отправляется в ответ на все входящие сообщения @{0} \
|
Сейчас вы редактируете текст автоответчика. Это сообщение отправляется в ответ на все входящие сообщения @{0} \
|
||||||
автоматически. По умолчанию оно отключено.
|
автоматически. По умолчанию оно отключено.
|
||||||
|
|
||||||
Текущий текст:
|
Текущий текст{2}:
|
||||||
<pre>
|
<pre>{1}</pre>
|
||||||
{1}
|
|
||||||
</pre>
|
|
||||||
Отправьте сообщение, чтобы изменить текст.
|
Отправьте сообщение, чтобы изменить текст.
|
||||||
"""))
|
"""))
|
||||||
text = text.format(bot.name, bot.second_text if bot.second_text else _("(отключено)"))
|
text = text.format(bot.name,
|
||||||
|
prepared_languages.get(lang, bot.second_text or _("отключено")),
|
||||||
|
_(" (для языка {0})").format(languages[lang]) if lang != "none" else "")
|
||||||
if call:
|
if call:
|
||||||
await edit_or_create(call, text, keyboard, parse_mode="HTML")
|
await edit_or_create(call, text, keyboard, parse_mode="HTML")
|
||||||
else:
|
else:
|
||||||
@@ -346,20 +526,43 @@ async def send_bot_templates_menu(bot: Bot, call: ty.Optional[types.CallbackQuer
|
|||||||
async def start_text_received(message: types.Message, state: FSMContext):
|
async def start_text_received(message: types.Message, state: FSMContext):
|
||||||
async with state.proxy() as proxy:
|
async with state.proxy() as proxy:
|
||||||
bot_id = proxy.get("bot_id")
|
bot_id = proxy.get("bot_id")
|
||||||
|
lang = proxy.get("lang", "none")
|
||||||
|
|
||||||
bot = await Bot.get_or_none(pk=bot_id)
|
bot = await Bot.get_or_none(pk=bot_id)
|
||||||
bot.start_text = message.html_text
|
if lang == "none":
|
||||||
await bot.save()
|
bot.start_text = message.html_text
|
||||||
await send_bot_text_menu(bot, chat_id=message.chat.id)
|
await bot.save(update_fields=["start_text"])
|
||||||
|
else:
|
||||||
|
obj, created = await BotStartMessage.get_or_create(bot=bot,
|
||||||
|
locale=lang,
|
||||||
|
defaults={"text": message.html_text})
|
||||||
|
if not created:
|
||||||
|
obj.text = message.html_text
|
||||||
|
await obj.save(update_fields=["text"])
|
||||||
|
await send_bot_text_menu(bot, chat_id=message.chat.id, state=state)
|
||||||
|
|
||||||
|
|
||||||
@dp.message_handler(state="wait_second_text", content_types="text", regexp="^[^/].+") # Not command
|
@dp.message_handler(state="wait_second_text", content_types="text", regexp="^[^/].+") # Not command
|
||||||
async def second_text_received(message: types.Message, state: FSMContext):
|
async def second_text_received(message: types.Message, state: FSMContext):
|
||||||
async with state.proxy() as proxy:
|
async with state.proxy() as proxy:
|
||||||
bot_id = proxy.get("bot_id")
|
bot_id = proxy.get("bot_id")
|
||||||
|
lang = proxy.get("lang", "none")
|
||||||
|
|
||||||
bot = await Bot.get_or_none(pk=bot_id)
|
bot = await Bot.get_or_none(pk=bot_id)
|
||||||
bot.second_text = message.html_text
|
if lang == "none":
|
||||||
await bot.save()
|
bot.second_text = message.html_text
|
||||||
await send_bot_second_text_menu(bot, chat_id=message.chat.id)
|
await bot.save(update_fields=["second_text"])
|
||||||
|
else:
|
||||||
|
obj, created = await BotSecondMessage.get_or_create(bot=bot,
|
||||||
|
locale=lang,
|
||||||
|
defaults={"text": message.html_text})
|
||||||
|
if not created:
|
||||||
|
obj.text = message.html_text
|
||||||
|
await obj.save(update_fields=["text"])
|
||||||
|
if not bot.second_text:
|
||||||
|
bot.second_text = message.html_text
|
||||||
|
await bot.save(update_fields=["second_text"])
|
||||||
|
await send_bot_second_text_menu(bot, chat_id=message.chat.id, state=state)
|
||||||
|
|
||||||
|
|
||||||
@dp.message_handler(state="wait_template", content_types="text", regexp="^[^/](.+)?") # Not command
|
@dp.message_handler(state="wait_template", content_types="text", regexp="^[^/](.+)?") # Not command
|
||||||
@@ -423,15 +626,43 @@ 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:
|
||||||
proxy["bot_id"] = bot.id
|
proxy["bot_id"] = bot.id
|
||||||
return await send_bot_text_menu(bot, call)
|
return await send_bot_text_menu(bot, call, state=state)
|
||||||
|
|
||||||
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":
|
||||||
@@ -443,20 +674,44 @@ async def callback(call: types.CallbackQuery, callback_data: dict, state: FSMCon
|
|||||||
if operation == "additional_info":
|
if operation == "additional_info":
|
||||||
await bot_actions.additional_info(bot, call)
|
await bot_actions.additional_info(bot, call)
|
||||||
return await send_bot_settings_menu(bot, call)
|
return await send_bot_settings_menu(bot, call)
|
||||||
|
if operation == "always_second_message":
|
||||||
|
await bot_actions.always_second_message(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 == "tags":
|
||||||
|
await bot_actions.tags(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)
|
||||||
if operation == "reset_text":
|
if operation == "reset_text":
|
||||||
await bot_actions.reset_bot_text(bot, call)
|
await bot_actions.reset_bot_text(bot, call, state)
|
||||||
return await send_bot_text_menu(bot, call)
|
return await send_bot_text_menu(bot, call, state=state)
|
||||||
|
if operation.startswith("slang_"):
|
||||||
|
async with state.proxy() as proxy:
|
||||||
|
lang = operation.replace("slang_", "")
|
||||||
|
if lang == "none" or lang in languages:
|
||||||
|
proxy["lang"] = lang
|
||||||
|
return await send_bot_text_menu(bot, call, state=state)
|
||||||
if operation == "next_text":
|
if operation == "next_text":
|
||||||
await state.set_state("wait_second_text")
|
await state.set_state("wait_second_text")
|
||||||
async with state.proxy() as proxy:
|
async with state.proxy() as proxy:
|
||||||
proxy["bot_id"] = bot.id
|
proxy["bot_id"] = bot.id
|
||||||
return await send_bot_second_text_menu(bot, call)
|
return await send_bot_second_text_menu(bot, call, state=state)
|
||||||
|
if operation.startswith("alang_"):
|
||||||
|
async with state.proxy() as proxy:
|
||||||
|
lang = operation.replace("alang_", "")
|
||||||
|
if lang == "none" or lang in languages:
|
||||||
|
proxy["lang"] = lang
|
||||||
|
return await send_bot_second_text_menu(bot, call, state=state)
|
||||||
if operation == "reset_second_text":
|
if operation == "reset_second_text":
|
||||||
await bot_actions.reset_bot_second_text(bot, call)
|
await bot_actions.reset_bot_second_text(bot, call, state)
|
||||||
return await send_bot_second_text_menu(bot, call)
|
return await send_bot_second_text_menu(bot, call, state=state)
|
||||||
if operation == "templates":
|
if operation == "templates":
|
||||||
await state.set_state("wait_template")
|
await state.set_state("wait_template")
|
||||||
async with state.proxy() as proxy:
|
async with state.proxy() as proxy:
|
||||||
|
|||||||
9
olgram/migrations/models/15_20240112035625_update.sql
Normal file
9
olgram/migrations/models/15_20240112035625_update.sql
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
-- upgrade --
|
||||||
|
CREATE TABLE IF NOT EXISTS "bot_start_message" (
|
||||||
|
"id" SERIAL NOT NULL PRIMARY KEY,
|
||||||
|
"locale" VARCHAR(5) NOT NULL,
|
||||||
|
"bot_id" INT NOT NULL REFERENCES "bot" ("id") ON DELETE CASCADE,
|
||||||
|
CONSTRAINT "uid_bot_start_m_bot_id_871cd1" UNIQUE ("bot_id", "locale")
|
||||||
|
);
|
||||||
|
-- downgrade --
|
||||||
|
DROP TABLE IF EXISTS "bot_start_message";
|
||||||
4
olgram/migrations/models/16_20240112040146_update.sql
Normal file
4
olgram/migrations/models/16_20240112040146_update.sql
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
-- upgrade --
|
||||||
|
ALTER TABLE "bot_start_message" ADD "text" TEXT NOT NULL;
|
||||||
|
-- downgrade --
|
||||||
|
ALTER TABLE "bot_start_message" DROP COLUMN "text";
|
||||||
10
olgram/migrations/models/17_20240112045126_update.sql
Normal file
10
olgram/migrations/models/17_20240112045126_update.sql
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
-- upgrade --
|
||||||
|
CREATE TABLE IF NOT EXISTS "bot_second_message" (
|
||||||
|
"id" SERIAL NOT NULL PRIMARY KEY,
|
||||||
|
"locale" VARCHAR(5) NOT NULL,
|
||||||
|
"text" TEXT NOT NULL,
|
||||||
|
"bot_id" INT NOT NULL REFERENCES "bot" ("id") ON DELETE CASCADE,
|
||||||
|
CONSTRAINT "uid_bot_second__bot_id_432892" UNIQUE ("bot_id", "locale")
|
||||||
|
);
|
||||||
|
-- downgrade --
|
||||||
|
DROP TABLE IF EXISTS "bot_second_message";
|
||||||
4
olgram/migrations/models/18_20240217035146_update.sql
Normal file
4
olgram/migrations/models/18_20240217035146_update.sql
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
-- upgrade --
|
||||||
|
ALTER TABLE "bot" ADD "enable_always_second_message" BOOL NOT NULL DEFAULT False;
|
||||||
|
-- downgrade --
|
||||||
|
ALTER TABLE "bot" DROP COLUMN "enable_always_second_message";
|
||||||
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";
|
||||||
4
olgram/migrations/models/22_20240317143246_update.sql
Normal file
4
olgram/migrations/models/22_20240317143246_update.sql
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
-- upgrade --
|
||||||
|
ALTER TABLE "bot_start_message" ALTER COLUMN "locale" TYPE VARCHAR(15) USING "locale"::VARCHAR(15);
|
||||||
|
-- downgrade --
|
||||||
|
ALTER TABLE "bot_start_message" ALTER COLUMN "locale" TYPE VARCHAR(5) USING "locale"::VARCHAR(5);
|
||||||
4
olgram/migrations/models/24_20240322034823_update.sql
Normal file
4
olgram/migrations/models/24_20240322034823_update.sql
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
-- upgrade --
|
||||||
|
ALTER TABLE "bot" ADD "enable_tags" BOOL NOT NULL DEFAULT False;
|
||||||
|
-- downgrade --
|
||||||
|
ALTER TABLE "bot" DROP COLUMN "enable_tags";
|
||||||
@@ -46,6 +46,11 @@ class Bot(Model):
|
|||||||
enable_additional_info = fields.BooleanField(default=False)
|
enable_additional_info = fields.BooleanField(default=False)
|
||||||
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_thread_interrupt = fields.BooleanField(default=True)
|
||||||
|
enable_mailing = fields.BooleanField(default=False)
|
||||||
|
enable_tags = 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()
|
||||||
@@ -70,6 +75,28 @@ class Bot(Model):
|
|||||||
table = 'bot'
|
table = 'bot'
|
||||||
|
|
||||||
|
|
||||||
|
class BotStartMessage(Model):
|
||||||
|
id = fields.IntField(pk=True)
|
||||||
|
bot = fields.ForeignKeyField("models.Bot", related_name="start_texts", on_delete=fields.CASCADE)
|
||||||
|
locale = fields.CharField(max_length=15)
|
||||||
|
text = fields.TextField()
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
unique_together = ("bot", "locale")
|
||||||
|
table = 'bot_start_message'
|
||||||
|
|
||||||
|
|
||||||
|
class BotSecondMessage(Model):
|
||||||
|
id = fields.IntField(pk=True)
|
||||||
|
bot = fields.ForeignKeyField("models.Bot", related_name="second_texts", on_delete=fields.CASCADE)
|
||||||
|
locale = fields.CharField(max_length=5)
|
||||||
|
text = fields.TextField()
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
unique_together = ("bot", "locale")
|
||||||
|
table = 'bot_second_message'
|
||||||
|
|
||||||
|
|
||||||
class User(Model):
|
class User(Model):
|
||||||
id = fields.IntField(pk=True)
|
id = fields.IntField(pk=True)
|
||||||
telegram_id = fields.BigIntField(index=True, unique=True)
|
telegram_id = fields.BigIntField(index=True, unique=True)
|
||||||
@@ -82,6 +109,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.5.0"
|
return "0.7.3"
|
||||||
|
|
||||||
@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/
|
||||||
|
|||||||
133
server/custom.py
133
server/custom.py
@@ -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
|
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
|
||||||
|
|
||||||
@@ -38,7 +40,11 @@ def _message_unique_id(bot_id: int, message_id: int) -> str:
|
|||||||
return f"{bot_id}_{message_id}"
|
return f"{bot_id}_{message_id}"
|
||||||
|
|
||||||
|
|
||||||
def _thread_uniqie_id(bot_id: int, chat_id: int) -> str:
|
def _tag_uid(bot_id: int, user_id: int) -> str:
|
||||||
|
return f"tag_{bot_id}_{user_id}"
|
||||||
|
|
||||||
|
|
||||||
|
def _thread_unique_id(bot_id: int, chat_id: int) -> str:
|
||||||
return f"thread_{bot_id}_{chat_id}"
|
return f"thread_{bot_id}_{chat_id}"
|
||||||
|
|
||||||
|
|
||||||
@@ -55,22 +61,27 @@ 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,
|
||||||
parse_mode="HTML")
|
parse_mode="HTML")
|
||||||
|
|
||||||
|
|
||||||
async def send_user_message(message: types.Message, super_chat_id: int, bot):
|
async def send_user_message(message: types.Message, super_chat_id: int, bot, tag: str = ""):
|
||||||
"""Переслать сообщение от пользователя, добавлять к нему user info при необходимости"""
|
"""Переслать сообщение от пользователя, добавлять к нему user info при необходимости"""
|
||||||
if bot.enable_additional_info:
|
if bot.enable_additional_info:
|
||||||
user_info = _("Сообщение от пользователя ")
|
user_info = _("Сообщение от пользователя ")
|
||||||
@@ -78,49 +89,94 @@ async def send_user_message(message: types.Message, super_chat_id: int, bot):
|
|||||||
if message.from_user.username:
|
if message.from_user.username:
|
||||||
user_info += " | @" + message.from_user.username
|
user_info += " | @" + message.from_user.username
|
||||||
user_info += f" | #ID{message.from_user.id}"
|
user_info += f" | #ID{message.from_user.id}"
|
||||||
|
if message.from_user.locale:
|
||||||
|
user_info += f" | lang: {message.from_user.locale}"
|
||||||
|
if message.forward_sender_name:
|
||||||
|
user_info += f" | fwd: {message.forward_sender_name}"
|
||||||
|
tag = await _redis.get(_tag_uid(bot.pk, message.from_user.id), encoding="utf-8")
|
||||||
|
if tag:
|
||||||
|
user_info += f" | tag: {tag}"
|
||||||
|
|
||||||
# Добавлять информацию в конец текста
|
# Добавлять информацию в конец текста
|
||||||
if message.content_type == types.ContentType.TEXT and len(message.text) + len(user_info) < 4093: # noqa:E721
|
if message.content_type == types.ContentType.TEXT \
|
||||||
|
and len(message.text) + len(user_info) < 4093: # noqa:E721
|
||||||
new_message = await message.bot.send_message(super_chat_id, message.text + "\n\n" + user_info)
|
new_message = await message.bot.send_message(super_chat_id, message.text + "\n\n" + user_info)
|
||||||
else: # Не добавлять информацию в конец текста, информация отдельным сообщением
|
else: # Не добавлять информацию в конец текста, информация отдельным сообщением
|
||||||
new_message = await message.bot.send_message(super_chat_id, text=user_info)
|
new_message = await message.bot.send_message(super_chat_id, text=user_info)
|
||||||
new_message_2 = await message.copy_to(super_chat_id, reply_to_message_id=new_message.message_id)
|
new_message_2 = await message.copy_to(super_chat_id, reply_to_message_id=new_message.message_id)
|
||||||
await _redis.set(_message_unique_id(bot.pk, new_message_2.message_id), message.chat.id,
|
await _redis.set(_message_unique_id(bot.pk, new_message_2.message_id), message.chat.id,
|
||||||
pexpire=ServerSettings.redis_timeout_ms())
|
pexpire=ServerSettings.redis_timeout_ms())
|
||||||
await _redis.set(_message_unique_id(bot.pk, new_message.message_id), message.chat.id,
|
elif tag:
|
||||||
pexpire=ServerSettings.redis_timeout_ms())
|
# добавлять тег в конец текста
|
||||||
return new_message
|
if message.content_type == types.ContentType.TEXT and len(message.text) + len(tag) < 4093:
|
||||||
|
new_message = await message.bot.send_message(super_chat_id, message.text + "\n\n" + tag)
|
||||||
|
else:
|
||||||
|
new_message = await message.bot.send_message(super_chat_id, text=tag)
|
||||||
|
new_message_2 = await message.copy_to(super_chat_id, reply_to_message_id=new_message.message_id)
|
||||||
|
await _redis.set(_message_unique_id(bot.pk, new_message_2.message_id), message.chat.id,
|
||||||
|
pexpire=ServerSettings.redis_timeout_ms())
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
new_message = await message.forward(super_chat_id)
|
new_message = await message.forward(super_chat_id)
|
||||||
except exceptions.MessageCantBeForwarded:
|
except exceptions.MessageCantBeForwarded:
|
||||||
new_message = await message.copy_to(super_chat_id)
|
new_message = await message.copy_to(super_chat_id)
|
||||||
await _redis.set(_message_unique_id(bot.pk, new_message.message_id), message.chat.id,
|
|
||||||
pexpire=ServerSettings.redis_timeout_ms())
|
await _redis.set(_message_unique_id(bot.pk, new_message.message_id), message.chat.id,
|
||||||
return new_message
|
pexpire=ServerSettings.redis_timeout_ms())
|
||||||
|
return new_message
|
||||||
|
|
||||||
|
|
||||||
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 bot.enable_tags:
|
||||||
|
tag = await _redis.get(_tag_uid(bot.pk, message.chat.id), encoding="utf-8")
|
||||||
|
else:
|
||||||
|
tag = ""
|
||||||
|
if tag:
|
||||||
|
tag = str(tag)
|
||||||
|
|
||||||
if is_super_group and bot.enable_threads:
|
if is_super_group and bot.enable_threads:
|
||||||
thread_first_message = await _redis.get(_thread_uniqie_id(bot.pk, message.chat.id))
|
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_unique_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))
|
if tag:
|
||||||
|
if message.content_type == types.ContentType.TEXT and len(message.text) + len(tag) < 4093:
|
||||||
|
new_message = await message.bot.send_message(
|
||||||
|
super_chat_id,
|
||||||
|
message.text + "\n\n" + tag,
|
||||||
|
reply_to_message_id=int(thread_first_message))
|
||||||
|
else:
|
||||||
|
new_message = await message.copy_to(super_chat_id,
|
||||||
|
reply_to_message_id=int(thread_first_message))
|
||||||
|
new_message_2 = await message.bot.send_message(
|
||||||
|
super_chat_id, reply_to_message_id=new_message.message_id, text=tag)
|
||||||
|
await _redis.set(_message_unique_id(bot.pk, new_message_2.message_id), message.chat.id,
|
||||||
|
pexpire=thread_timeout)
|
||||||
|
else:
|
||||||
|
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, tag)
|
||||||
await _redis.set(_thread_uniqie_id(bot.pk, message.chat.id), new_message.message_id,
|
await _redis.set(
|
||||||
pexpire=ServerSettings.thread_timeout_ms())
|
_thread_unique_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, tag)
|
||||||
await _redis.set(_thread_uniqie_id(bot.pk, message.chat.id), new_message.message_id,
|
await _redis.set(_thread_unique_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, tag)
|
||||||
|
|
||||||
|
|
||||||
|
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):
|
||||||
@@ -128,6 +184,9 @@ 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:
|
||||||
@@ -146,19 +205,23 @@ async def handle_user_message(message: types.Message, super_chat_id: int, bot):
|
|||||||
await send_to_superchat(is_super_group, message, super_chat_id, bot)
|
await send_to_superchat(is_super_group, message, super_chat_id, bot)
|
||||||
except (exceptions.Unauthorized, exceptions.ChatNotFound):
|
except (exceptions.Unauthorized, exceptions.ChatNotFound):
|
||||||
return SendMessage(chat_id=message.chat.id, text=_("Не удаётся связаться с владельцем бота"))
|
return SendMessage(chat_id=message.chat.id, text=_("Не удаётся связаться с владельцем бота"))
|
||||||
|
except exceptions.RetryAfter:
|
||||||
|
return SendMessage(chat_id=message.chat.id, text=_("Слишком много сообщений, подождите одну минуту"),
|
||||||
|
reply_to_message_id=message.message_id)
|
||||||
except exceptions.TelegramAPIError as err:
|
except exceptions.TelegramAPIError as err:
|
||||||
_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:
|
||||||
send_auto = not await _redis.get(_last_message_uid(bot.pk, message.chat.id))
|
send_auto = not await _redis.get(_last_message_uid(bot.pk, message.chat.id))
|
||||||
await _redis.setex(_last_message_uid(bot.pk, message.chat.id), 60 * 60 * 3, 1)
|
await _redis.setex(_last_message_uid(bot.pk, message.chat.id), 60 * 60 * 3, 1)
|
||||||
if send_auto:
|
if send_auto or bot.enable_always_second_message:
|
||||||
return SendMessage(chat_id=message.chat.id, text=bot.second_text, parse_mode="HTML")
|
text_obj = await BotSecondMessage.get_or_none(bot=bot, locale=str(message.from_user.locale))
|
||||||
|
return SendMessage(chat_id=message.chat.id, text=text_obj.text if text_obj else bot.second_text,
|
||||||
|
parse_mode="HTML")
|
||||||
|
|
||||||
|
|
||||||
async def handle_operator_message(message: types.Message, super_chat_id: int, bot):
|
async def handle_operator_message(message: types.Message, super_chat_id: int, bot):
|
||||||
@@ -193,6 +256,15 @@ async def handle_operator_message(message: types.Message, super_chat_id: int, bo
|
|||||||
else:
|
else:
|
||||||
await banned_user.delete()
|
await banned_user.delete()
|
||||||
return SendMessage(chat_id=message.chat.id, text=_("Пользователь разбанен"))
|
return SendMessage(chat_id=message.chat.id, text=_("Пользователь разбанен"))
|
||||||
|
if bot.enable_tags:
|
||||||
|
if message.text and message.text.startswith("/tag "):
|
||||||
|
tag = message.text.replace("/tag ", "")[:20].strip()
|
||||||
|
if tag:
|
||||||
|
await _redis.set(_tag_uid(bot.pk, chat_id), tag, pexpire=ServerSettings.redis_timeout_ms())
|
||||||
|
return SendMessage(chat_id=message.chat.id, text=_("Тег выставлен"))
|
||||||
|
else:
|
||||||
|
await _redis.delete(_tag_uid(bot.pk, chat_id))
|
||||||
|
return SendMessage(chat_id=message.chat.id, text=_("Тег убран"))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
await message.copy_to(chat_id)
|
await message.copy_to(chat_id)
|
||||||
@@ -206,6 +278,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:
|
||||||
@@ -218,7 +292,8 @@ async def message_handler(message: types.Message, *args, **kwargs):
|
|||||||
|
|
||||||
if message.text and message.text == "/start":
|
if message.text and message.text == "/start":
|
||||||
# На команду start нужно ответить, не пересылая сообщение никуда
|
# На команду start нужно ответить, не пересылая сообщение никуда
|
||||||
text = bot.start_text
|
text_obj = await BotStartMessage.get_or_none(bot=bot, locale=str(message.from_user.locale))
|
||||||
|
text = text_obj.text if text_obj else bot.start_text
|
||||||
if bot.enable_olgram_text:
|
if bot.enable_olgram_text:
|
||||||
text += _(ServerSettings.append_text())
|
text += _(ServerSettings.append_text())
|
||||||
return SendMessage(chat_id=message.chat.id, text=text, parse_mode="HTML")
|
return SendMessage(chat_id=message.chat.id, text=text, parse_mode="HTML")
|
||||||
|
|||||||
Reference in New Issue
Block a user