big update

This commit is contained in:
dan63047 2020-07-01 18:09:54 +03:00
parent 5bd82e9090
commit 61ac44f1ee
3 changed files with 189 additions and 272 deletions

View File

@ -16,21 +16,18 @@
* **!echo** — бот начинает повторять за вами, чтобы это остановить, надо написать *!echo off* * **!echo** — бот начинает повторять за вами, чтобы это остановить, надо написать *!echo off*
* **!game *камень/ножницы/бумага/статистика*** — бот играет с вами в "Камень, ножницы, бумага" и ведет статискику игр, которую записывает в файл БД * **!game *камень/ножницы/бумага/статистика*** — бот играет с вами в "Камень, ножницы, бумага" и ведет статискику игр, которую записывает в файл БД
* **!midnight** — бот будет уведомлять о каждом миднайте по Московскому времени. Введите ещё раз, чтобы отменить это * **!midnight** — бот будет уведомлять о каждом миднайте по Московскому времени. Введите ещё раз, чтобы отменить это
* **!reminder *set/list/delete*** — напоминалка. С агрументом *set* бот запускает установку напоминания, с аргументом *list* отправляет вам все ваши запланированные напоминания, с аргументом *delete* запускает удаление напоминания
* **!subscribe** — бот будет уведомлять вас о каждом новом посте. Введите ещё раз, чтобы отменить это * **!subscribe** — бот будет уведомлять вас о каждом новом посте. Введите ещё раз, чтобы отменить это
* **!debug** — бот отправляет информацию о своём состоянии * **!debug** — бот отправляет информацию о своём состоянии
* **!debug *log*** — бот отправляет последние 10 строк из своего лога. Доступно только вам * **!debug *log*** — бот отправляет последние 10 строк из своего лога. Доступно только вам
* **!debug *bots*** — бот отправляет информацию о обьектах бота в памяти. Доступно только вам * **!debug *bots*** — бот отправляет информацию о обьектах бота в памяти. Доступно только вам
* **!debug *game*** — бот отправляет всю статистику по игре !game * **!debug *game*** — бот отправляет всю статистику по игре !game
* **!debug *tasks*** — бот отправляет вам все напоминания из !reminder. Доступно только вам
* **!access *all/owner*** — позволяет в беседе установить уровень доступа к командам *!midnight*, *!subscribe* и *!debug*. *all* - все могут пользоваться. *owner* - только вы. Доступно только вам * **!access *all/owner*** — позволяет в беседе установить уровень доступа к командам *!midnight*, *!subscribe* и *!debug*. *all* - все могут пользоваться. *owner* - только вы. Доступно только вам
* **!turnoff** — даёт боту команду на выключение. Доступно только вам * **!turnoff** — даёт боту команду на выключение. Доступно только вам
* **!admin_mode** — если чат, в которой активируется команда, является беседой и в ней у бота есть полномочия администратора, то бот переходит в режим модерации. Пока что он может только кикать людей за @all и @online. Введите ещё раз, чтобы выключить режим модерации. Доступно только вам * **!admin_mode** — если чат, в которой активируется команда, является беседой и в ней у бота есть полномочия администратора, то бот переходит в режим модерации. Пока что он может только кикать людей за @all и @online. Введите ещё раз, чтобы выключить режим модерации. Доступно только вам
# Установка и запуск бота # Установка и запуск бота
## Как это делал я Лучшим решением будет иметь платный аккаунт на [pythonanywhere](https://www.pythonanywhere.com/) чтобы запускать бота, как Always-on task и использовать MySQL базу данных. Можно, конечно, не использовать БД и запускать бота в консоли, но pythonanywhere может выключить вашу консоль, если вы долго не будете посещать её.
Здесь я расскажу каким образом я запустил этого бота. Работает он у меня на [pythonanywhere](https://www.pythonanywhere.com/), причём аккаунт платный, ибо он использует MySQL базу данных, а также работает как Always-on task. Можно, конечно, не использовать БД и запускать бота в консоли, но он будет сыпать ошибками из-за тесной связи с этой самой БД, не будет сохранять данные о своей работе, да ещё и pythonanywhere выключит вашу консоль, если вы долго не будете посещать её. ## Основа
Итак, заходим на pythonanywhere, входим или регистрируемся.
Итак, заходим на pythonanywhere, входим или регистрируемся и покупаем самый дешёвый тариф Hacker за 5 баксов в месяц, этого должно хватить.
Создаём консоль на bash и прописываем: Создаём консоль на bash и прописываем:
@ -44,33 +41,42 @@
Эта команда установит все необходимые библиотеки для работы бота. Эта команда установит все необходимые библиотеки для работы бота.
Теперь создадим базу данных, с которой бот будет работать. На том же pythonanywhere тыкаем на *Databases* в шапке сайта. Создаём пароль для вашей базы данных. По умолчанию будет создана база данных с названием `your_nickname$default`, но вы можете создать БД со своим названием. Настроим ваше сообщество для работы с ботом: заходим в *Управление -> Работа с API*. Здесь создаём токен сообщества с правами доступа к сообщениям, фотографиям и стене. Идем в *Long Poll API*, включаем его и ставим последнюю доступную версию (на момент написания этой версии README это 5.120). В *Типы событий* должны стоять галочки на следующих событиях: Входящее сообщение, Запрет на получение, Добавление записи на стене.
Настроим ваше сообщество для работы с ботом: заходим в *Управление -> Работа с API*. Здесь создаём токен сообщества с правами доступа к сообщениям, фотографиям и стене. Идем в *Long Poll API*, включаем его и ставим последнюю доступную версию (на момент написания этой версии README это 5.108). В *Типы событий* должны стоять галочки на следующих событиях: Входящее сообщение, Запрет на получение, Добавление записи на стене.
Разберёмся с костылём для метода `photos.get`: Идем на `vk.com/dev`, нажимаем на *Мои приложения* и кликаем по *Создать приложение*. Новое приложение может называться как угодно, от него нам необходимо всего лишь сервисный ключ доступа, который можно найти, если нажать на *Настройки*
Если вы планируете использовать команду !weather, сделайте следующее:
Перейдите по `openweathermap.org`, пройдите там регистрацию и создайте API ключ
Создадим файл конфигурации для бота: В pythonanywhere тыкаем на *Files*, переходим в директорию *dan63047pythonbot* и создаём там новый фаил с названием `config.py`. В нём должно быть написано следующее: Создадим файл конфигурации для бота: В pythonanywhere тыкаем на *Files*, переходим в директорию *dan63047pythonbot* и создаём там новый фаил с названием `config.py`. В нём должно быть написано следующее:
```python ```python
import vk_api import vk_api
import pyowm import pyowm
from pyowm.utils.config import get_default_config
vk = vk_api.VkApi(token="vk_group_token") # Токен сообщества vk = vk_api.VkApi(token="vk_group_token") # Токен сообщества
vk_mda = vk_api.VkApi(token="vk_service_token") # Сервисный ключ доступа
group_id = 190322075 # Цифровой ид группы group_id = 190322075 # Цифровой ид группы
album_for_command = 269199619 # Цифровой ид альбома для команды !image
owner_id = 276193568 # Цифровой ид вашей страницы вк, чтобы вы могли управлять ботом в переписке owner_id = 276193568 # Цифровой ид вашей страницы вк, чтобы вы могли управлять ботом в переписке
random_image_command = True # False, если вам не нужна команда !image, иначе следующие 2 строки обязательны
vk_mda = vk_api.VkApi(token="vk_service_token") # Сервисный ключ доступа
album_for_command = 269199619 # Цифровой ид альбома для команды !image
weather_command = True # False, если вам не нужна команда !weather, иначе следующие 4 строки обязательны
owm_dict = get_default_config()
owm_dict['language'] = 'ru'
owm = pyowm.OWM('openweathermap_api_key', language='ru') # Ключ OpenWeather API owm = pyowm.OWM('openweathermap_api_key', language='ru') # Ключ OpenWeather API
mgr = owm.weather_manager()
use_database = True # False, если вы не планируете использовать MySQL базу данных, иначе следующие 4 строки обязательны
mysql_host = 'pythonanywhere_nickname.mysql.pythonanywhere-services.com' # ссылка на хост БД. Вместо pythonanywhere_nickname должен быть ваш никнейм на pythonanywhere mysql_host = 'pythonanywhere_nickname.mysql.pythonanywhere-services.com' # ссылка на хост БД. Вместо pythonanywhere_nickname должен быть ваш никнейм на pythonanywhere
mysql_user = 'pythonanywhere_nickname' # Ваш никнейм на pythonanywhere mysql_user = 'pythonanywhere_nickname' # Ваш никнейм на pythonanywhere
mysql_pass = 'qwerty123' # Пароль, созданный вами для БД mysql_pass = 'qwerty123' # Пароль, созданный вами для БД
mysql_db = 'pythonanywhere_nickname$default' # Название вашей БД. Вместо pythonanywhere_nickname должен быть ваш никнейм на pythonanywhere. Так же вместо default может быть ваше название БД mysql_db = 'pythonanywhere_nickname$default' # Название вашей БД. Вместо pythonanywhere_nickname должен быть ваш никнейм на pythonanywhere. Так же вместо default может быть ваше название БД
``` ```
И, наконец, запуск бота: в pythonanywhere тыкаем на *Tasks*, создаём и запускаем в *Always-on tasks* задачу `python3.8 /home/pythonanywhere_nickname/dan63047pythonbot/dan63047bot.py`, где вместо pythonanywhere_nickname должен быть ваш никнейм на pythonanywhere. После небольшого тупления pythonanywhere запустит вашего бота и он будет работать долго и счастливо. ## Если вы будете использовать команду !image
Разберёмся с костылём для метода `photos.get`: Идем на `vk.com/dev`, нажимаем на *Мои приложения* и кликаем по *Создать приложение*. Новое приложение может называться как угодно, от него нам необходимо всего лишь сервисный ключ доступа, который можно найти, если нажать на *Настройки*
## Если вы будете использовать команду !weather
Перейдите по `openweathermap.org`, пройдите там регистрацию и создайте API ключ
## Если вы решите использовать MySQL БД
Вам необходимо будет купить тариф на pythonanywhere, где есть поддержка MySQL базы данных, с которой бот будет работать. Тыкаем на *Databases* в шапке сайта. Создаём пароль для вашей базы данных. По умолчанию будет создана база данных с названием `your_nickname$default`, но вы можете создать БД со своим названием.
## Запуск бота
Если аккаунт платный: в pythonanywhere тыкаем на *Tasks*, создаём и запускаем в *Always-on tasks* задачу `python3.8 /home/pythonanywhere_nickname/dan63047pythonbot/dan63047bot.py`, где вместо pythonanywhere_nickname должен быть ваш никнейм на pythonanywhere. После небольшого тупления pythonanywhere запустит вашего бота.
Если аккаунт бесплатный: в bash консоли переходим в директорию бота и прописываем `python3 dan63047.py`. Консоль можно оставить в покое, но лучше раз в день проверять её чтобы консоль не отключили
## Другие варианты запуска бота ## Другие варианты запуска бота
Скорее всего, вы можете найти где-нибудь VPS с базами данных или огранизовать всё на своём компьютере, но об этом я ничего не знаю. Напишите мне, чтобы рассказать, как у вас полностью получилось заставить работать бота. Скорее всего, вы можете найти где-нибудь VPS или огранизовать всё на своём компьютере. Там вы просто скачиваете и устанавливаете Python последней версии, настраиваете конфиг бота и запускаете его.
# Использованные библиотеки # Использованные библиотеки
* [vk_api](https://github.com/python273/vk_api) — модуль для создания скриптов для социальной сети Вконтакте * [vk_api](https://github.com/python273/vk_api) — модуль для создания скриптов для социальной сети Вконтакте
* [pyowm](https://github.com/csparpa/pyowm) — модуль для получения погоды через OpenWeather API * [pyowm](https://github.com/csparpa/pyowm) — модуль для получения погоды через OpenWeather API

View File

@ -11,7 +11,7 @@ import pymysql
from pymysql.cursors import DictCursor from pymysql.cursors import DictCursor
import wikipediaapi as wiki import wikipediaapi as wiki
from collections import deque from collections import deque
from config import vk, owm, vk_mda, group_id, album_for_command, owner_id, mysql_host, mysql_pass, mysql_user, mysql_db import config
from vk_api.bot_longpoll import VkBotLongPoll, VkBotEventType from vk_api.bot_longpoll import VkBotLongPoll, VkBotEventType
root_logger = logging.getLogger() root_logger = logging.getLogger()
@ -40,154 +40,144 @@ log(False, "Script started")
bot = {} bot = {}
debug_array = {'vk_warnings': 0, 'db_warnings': 0, 'bot_warnings': 0, 'logger_warnings': 0, 'start_time': 0, 'messages_get': 0, 'messages_answered': 0} debug_array = {'vk_warnings': 0, 'db_warnings': 0, 'bot_warnings': 0, 'logger_warnings': 0, 'start_time': 0, 'messages_get': 0, 'messages_answered': 0}
errors_array = {"access": "Отказано в доступе", "miss_argument": "Отсуствует аргумент"} errors_array = {"access": "Отказано в доступе", "miss_argument": "Отсуствует аргумент", "command_off": "Команда отключена"}
longpoll = VkBotLongPoll(vk, group_id) longpoll = VkBotLongPoll(config.vk, config.group_id)
class MySQL_worker(): class Database_worker():
def __init__(self): def __init__(self):
try: if(config.use_database):
self._CON = pymysql.connect( log(False, "Trying to connect to database")
host= mysql_host, try:
user= mysql_user, self._CON = pymysql.connect(
password= mysql_pass, host= config.mysql_host,
db= mysql_db, user= config.mysql_user,
charset='utf8mb4', password= config.mysql_pass,
cursorclass=DictCursor db= config.mysql_db,
) charset='utf8mb4',
cur = self._CON.cursor() cursorclass=DictCursor
)
cur = self._CON.cursor()
except Exception as e:
debug_array['db_warnings'] += 1
log(True, f"Unable to connect to database: {str(e)}")
try: try:
cur.execute("SELECT * FROM bot_users") cur.execute("SELECT * FROM bot_users")
except: except:
cur.execute("CREATE TABLE bot_users ( id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, chat_id INT UNSIGNED, awaiting VARCHAR(128), access TINYINT, midnight BOOL, new_post BOOL, admin_mode BOOL, game_wins INT UNSIGNED, game_defeats INT UNSIGNED, game_draws INT UNSIGNED)") cur.execute("CREATE TABLE bot_users ( id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, chat_id INT UNSIGNED, awaiting VARCHAR(128), access TINYINT, midnight BOOL, new_post BOOL, admin_mode BOOL, game_wins INT UNSIGNED, game_defeats INT UNSIGNED, game_draws INT UNSIGNED)")
try:
cur.execute("SELECT * FROM tasks")
except:
cur.execute("CREATE TABLE tasks (id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY, chat_id INT UNSIGNED, time INT UNSIGNED, task TEXT)")
cur.close() cur.close()
log(False, f"Database connection established") log(False, f"Database connection established")
except Exception as e: else:
debug_array['db_warnings'] += 1 log(False, "Bot will use JSON file as database")
log(True, f"Unable to connect to database: {str(e)}") try:
with open("data.json", "r") as data:
self._DATA_DIST = json.load(data)
data.close()
except Exception:
log(True, "data.json is not exist, it will be created soon")
self._DATA_DIST = {"users": {}}
def set_new_user(self, peer_id, midnight=False, awaiting=None, access=1, new_post=False, admin_mode=False, game_wins=0, game_defeats=0, game_draws=0): def set_new_user(self, peer_id, midnight=False, awaiting=None, access=1, new_post=False, admin_mode=False, game_wins=0, game_defeats=0, game_draws=0):
try: if(config.use_database):
cur = self._CON.cursor() try:
cur.execute("INSERT INTO bot_users (chat_id, awaiting, access, midnight, new_post, admin_mode, game_wins, game_defeats, game_draws) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s)", (peer_id, awaiting, access, midnight, new_post, admin_mode, game_wins, game_defeats, game_draws)) cur = self._CON.cursor()
self._CON.commit() cur.execute("INSERT INTO bot_users (chat_id, awaiting, access, midnight, new_post, admin_mode, game_wins, game_defeats, game_draws) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s)", (peer_id, awaiting, access, midnight, new_post, admin_mode, game_wins, game_defeats, game_draws))
cur.close() self._CON.commit()
except Exception as e: cur.close()
debug_array['db_warnings'] += 1 except Exception as e:
log(True, f"Unable to add new user in database: {str(e)}") debug_array['db_warnings'] += 1
log(True, f"Unable to add new user in database: {str(e)}")
else:
self._DATA_DIST['users'][peer_id] = {"awaiting": awaiting, "access": access, "midnight": midnight, "new_post": new_post, "admin_mode": admin_mode, "game_wins": game_wins, "game_defeats": game_defeats, "game_draws": game_draws}
open("data.json", "w").write(json.dumps(self._DATA_DIST))
def get_all_users(self): def get_all_users(self):
try: if(config.use_database):
cur = self._CON.cursor() try:
cur.execute("SELECT * FROM bot_users") cur = self._CON.cursor()
result = cur.fetchall() cur.execute("SELECT * FROM bot_users")
cur.close() result = cur.fetchall()
return result cur.close()
except Exception as e: return result
debug_array['db_warnings'] += 1 except Exception as e:
log(True, f"Unable to load user from database: {str(e)}") debug_array['db_warnings'] += 1
log(True, f"Unable to load user from database: {str(e)}")
else:
return self._DATA_DIST['users']
def get_from_users(self, from_id): def get_from_users(self, from_id):
try: if(config.use_database):
cur = self._CON.cursor() try:
cur.execute("SELECT * FROM bot_users WHERE chat_id = %s", (from_id)) cur = self._CON.cursor()
result = cur.fetchall() cur.execute("SELECT * FROM bot_users WHERE chat_id = %s", (from_id))
cur.close() result = cur.fetchall()
return result cur.close()
except Exception as e: return result
debug_array['db_warnings'] += 1 except Exception as e:
log(True, f"Unable to load user from database: {str(e)}") debug_array['db_warnings'] += 1
log(True, f"Unable to load user from database: {str(e)}")
else:
return self._DATA_DIST['users'][str(from_id)]
def get_game_stat(self): def get_game_stat(self):
try: if(config.use_database):
cur = self._CON.cursor() try:
cur.execute("SELECT chat_id, game_wins, game_draws, game_defeats FROM bot_users WHERE game_wins > 0 OR game_draws > 0 OR game_defeats > 0") cur = self._CON.cursor()
result = cur.fetchall() cur.execute("SELECT chat_id, game_wins, game_draws, game_defeats FROM bot_users WHERE game_wins > 0 OR game_draws > 0 OR game_defeats > 0")
cur.close() result = cur.fetchall()
return result cur.close()
except Exception as e: return result
debug_array['db_warnings'] += 1 except Exception as e:
log(True, f"Unable to load stats from database: {str(e)}") debug_array['db_warnings'] += 1
log(True, f"Unable to load stats from database: {str(e)}")
else:
return self._DATA_DIST['users']
# Info: dist cannot return only the necessary keys
def update_user(self, chat_id, thing, new_value): def update_user(self, chat_id, thing, new_value):
try: if(config.use_database):
cur = self._CON.cursor() try:
cur.execute(f"UPDATE bot_users SET {thing} = %s WHERE bot_users.chat_id = %s;", (new_value, chat_id)) cur = self._CON.cursor()
self._CON.commit() cur.execute(f"UPDATE bot_users SET {thing} = %s WHERE bot_users.chat_id = %s;", (new_value, chat_id))
cur.close() self._CON.commit()
except Exception as e: cur.close()
debug_array['db_warnings'] += 1 except Exception as e:
log(True, f"Unable to update info about user in database: {str(e)}") debug_array['db_warnings'] += 1
log(True, f"Unable to update info about user in database: {str(e)}")
else:
self._DATA_DIST['users'][str(chat_id)][thing] = new_value
open("data.json", "w").write(json.dumps(self._DATA_DIST))
def delete_user(self, chat_id): def delete_user(self, chat_id):
try: if(config.use_database):
cur = self._CON.cursor() try:
cur.execute("DELETE FROM bot_users, game_defeats WHERE chat_id = %s", (chat_id)) cur = self._CON.cursor()
self._CON.commit() cur.execute("DELETE FROM bot_users, game_defeats WHERE chat_id = %s", (chat_id))
cur.close() self._CON.commit()
return True cur.close()
except Exception as e: return True
debug_array['db_warnings'] += 1 except Exception as e:
log(True, f"Unable to delete user from database: {str(e)}") debug_array['db_warnings'] += 1
return False log(True, f"Unable to delete user from database: {str(e)}")
return False
else:
self._DATA_DIST['users'].pop(str(chat_id))
open("data.json", "w").write(json.dumps(self._DATA_DIST))
def get_all_tasks(self): db = Database_worker()
try:
cur = self._CON.cursor()
cur.execute("SELECT * FROM tasks")
result = cur.fetchall()
cur.close()
return result
except Exception as e:
debug_array['db_warnings'] += 1
log(True, f"Unable to load tasks from database: {str(e)}")
def set_new_task(self, chat_id, time, task):
try:
cur = self._CON.cursor()
cur.execute("INSERT INTO tasks (chat_id, time, task) VALUES (%s, %s, %s)", (chat_id, time, task))
self._CON.commit()
cur.close()
except Exception as e:
debug_array['db_warnings'] += 1
log(True, f"Unable to add new task in database: {str(e)}")
def get_from_tasks(self, from_id):
try:
cur = self._CON.cursor()
cur.execute("SELECT * FROM tasks WHERE chat_id = %s", (from_id))
result = cur.fetchall()
cur.close()
return result
except Exception as e:
debug_array['db_warnings'] += 1
log(True, f"Unable to load tasks from database: {str(e)}")
def delete_task(self, from_id, task):
try:
cur = self._CON.cursor()
cur.execute("DELETE FROM tasks WHERE chat_id = %s AND task = %s", (from_id, task))
self._CON.commit()
cur.close()
return True
except Exception as e:
debug_array['db_warnings'] += 1
log(True, f"Unable to delete task from database: {str(e)}")
return False
db = MySQL_worker()
def load_users(): def load_users():
try: try:
log(False, "Reading database") log(False, "Reading database")
get_info = db.get_all_users() get_info = db.get_all_users()
for i in get_info: if(config.use_database):
bot[int(i['chat_id'])] = VkBot(i['chat_id'], i['midnight'], i['awaiting'], int(i['access']), i['new_post'], i['admin_mode']) for i in get_info:
bot[int(i['chat_id'])] = VkBot(int(i['chat_id']), bool(i['midnight']), i['awaiting'], int(i['access']), bool(i['new_post']), bool(i['admin_mode']))
else:
for i in get_info:
bot[int(i)] = VkBot(int(i), bool(get_info[i]['midnight']), get_info[i]['awaiting'], int(get_info[i]['access']), bool(get_info[i]['new_post']), bool(get_info[i]['admin_mode']))
except Exception as lol: except Exception as lol:
debug_array['bot_warnings'] += 1 debug_array['bot_warnings'] += 1
log(True, f"Problem with creating objects: {str(lol)}") log(True, f"Problem with creating objects: {str(lol)}")
@ -216,16 +206,16 @@ def create_new_bot_object(chat_id):
def get_weather(place): def get_weather(place):
try: try:
weather_request = owm.weather_at_place(place) weather_request = config.mgr.weather_at_place(place)
except pyowm.exceptions.api_response_error.NotFoundError as i: except Exception as i:
err = "A problem with OpenWeather API: " + str(i) err = "A problem with OpenWeather API: " + str(i)
log(True, err) log(True, err)
return "Такого города нет, либо данных о погоде нет" return "Такого города нет, либо данных о погоде нет"
weather_answer = weather_request.get_weather() weather_status = weather_request.weather.detailed_status
info = "OpenWeather API: " + str(weather_answer) weather_temp = weather_request.weather.temperature('celsius')
log(False, info) weather_humidity = weather_request.weather.humidity
return "В городе " + place + " сейчас " + weather_answer.get_detailed_status() + ", " + str( weather_wing = weather_request.weather.wind()
round(weather_answer.get_temperature('celsius')['temp'])) + "°C" return f"Погода в городе {place}<br> {str(round(weather_temp['temp']))}°C, {weather_status}<br>Влажность: {weather_humidity}%<br>Ветер: {weather_wing['speed']} м/с"
class VkBot: class VkBot:
@ -241,7 +231,7 @@ class VkBot:
self._NEW_POST = new_post self._NEW_POST = new_post
self._ADMIN_MODE = admin_mode self._ADMIN_MODE = admin_mode
if int(self._CHAT_ID) == int(owner_id): if int(self._CHAT_ID) == int(config.owner_id):
self._OWNER = True self._OWNER = True
else: else:
self._OWNER = False self._OWNER = False
@ -259,12 +249,7 @@ class VkBot:
if event == "midnight" and self._MIDNIGHT_EVENT: if event == "midnight" and self._MIDNIGHT_EVENT:
current_time = datetime.datetime.fromtimestamp(time.time() + 10800) current_time = datetime.datetime.fromtimestamp(time.time() + 10800)
midnight_text = ["Миднайт!", "Полночь!", "Midnight!", "миднигхт", "Середина ночи", "Смена даты!"] midnight_text = ["Миднайт!", "Полночь!", "Midnight!", "миднигхт", "Середина ночи", "Смена даты!", "00:00"]
# midnight_after = ["Ложись спать!", "P E A C E A N D T R A N Q U I L I T Y", "Поиграй в майнкрафт",
# "Втыкай в ВК дальше", "hat in time is gay", "RIP 2013-2019 Gears for Breakfast", "Egg",
# "вещ или бан", "Мой ник в игре _ичё", "Я жил, но что-то пошло не так",
# "Когда тебе похуй, ты неувязвим", "Who's Afraid Of 138?!"]
self.send(f"{random.choice(midnight_text)}<br>Наступило {current_time.strftime('%d.%m.%Y')}<br>Картинка дня:", self.random_image()) self.send(f"{random.choice(midnight_text)}<br>Наступило {current_time.strftime('%d.%m.%Y')}<br>Картинка дня:", self.random_image())
log(False, f"[BOT_{self._CHAT_ID}] Notified about midnight") log(False, f"[BOT_{self._CHAT_ID}] Notified about midnight")
elif event == "post" and self._NEW_POST: elif event == "post" and self._NEW_POST:
@ -279,45 +264,30 @@ class VkBot:
if message.find("@all") != -1 or message.find("@online") != -1 or message.find("@here") != -1 or message.find("@everyone") != -1 or message.find("@здесь") != -1 or message.find("@все") != -1: if message.find("@all") != -1 or message.find("@online") != -1 or message.find("@here") != -1 or message.find("@everyone") != -1 or message.find("@здесь") != -1 or message.find("@все") != -1:
self.send(f"[@id{user_id}|Дебил]") self.send(f"[@id{user_id}|Дебил]")
try: try:
if int(user_id) != int(owner_id): if int(user_id) != int(config.owner_id):
vk.method("messages.removeChatUser", {"chat_id": int(self._CHAT_ID)-2000000000, "member_id": user_id}) config.vk.method("messages.removeChatUser", {"chat_id": int(self._CHAT_ID)-2000000000, "member_id": user_id})
log(False, f"[BOT_{self._CHAT_ID}] user id{user_id} has been kicked") log(False, f"[BOT_{self._CHAT_ID}] user id{user_id} has been kicked")
else: else:
log(False, f"[BOT_{self._CHAT_ID}] can't kick owner") log(False, f"[BOT_{self._CHAT_ID}] can't kick owner")
except Exception as e: except Exception as e:
log(True, f"[BOT_{self._CHAT_ID}] can't kick user id{user_id} - {str(e)}") log(True, f"[BOT_{self._CHAT_ID}] can't kick user id{user_id} - {str(e)}")
with open('bad_words.txt', 'r') as filter: with open('bad_words.txt', 'r', encoding="utf-8", newline='') as filter:
flag = False flag = False
forcheck = message.lower()
for word in filter: for word in filter:
if flag: if flag:
log(False, f"[BOT_{self._CHAT_ID}] bad word detected") if random.randint(0, 5) == 1:
if random.randint(1, 5) == 1:
self.send("За м*т извенись") self.send("За м*т извенись")
break break
if message.lower().find(word) != -1: else:
flag = True if forcheck.find(word[:-1]) != -1:
flag = True
if self._AWAITING_INPUT_MODE: if self._AWAITING_INPUT_MODE:
if message == "Назад": if message == "Назад":
self.change_await() self.change_await()
self.send("Отменено") self.send("Отменено")
else: else:
if self._AWAITING_INPUT_MODE == "reminder task": if self._AWAITING_INPUT_MODE == "echo":
self.reminder(message, "task")
self.send('Когда напомнить? (время в формате дд.мм.гг чч:мм)')
self.change_await('reminder time')
elif self._AWAITING_INPUT_MODE == 'reminder time':
if self.reminder(message, "time"):
self.send("Напоминание установлено<br>Внимание: напоминание не сработает, если бот будет перезагружен")
self.change_await()
else:
self.send("Неверный формат времени, введите время в формате дд.мм.гг чч:мм")
elif self._AWAITING_INPUT_MODE == "reminder delete":
if self.reminder(message, "delete"):
self.send("Напоминание удалено")
self.change_await()
else:
self.send("Нет такого напоминания")
elif self._AWAITING_INPUT_MODE == "echo":
if message == "!echo off": if message == "!echo off":
self.send("Эхо режим выключен") self.send("Эхо режим выключен")
self.change_await() self.change_await()
@ -326,10 +296,15 @@ class VkBot:
self.send(message) self.send(message)
log(False, f"[BOT_{self._CHAT_ID}] Answer in echo mode") log(False, f"[BOT_{self._CHAT_ID}] Answer in echo mode")
else: else:
if message.lower() == "бот дай денег":
self.send("Иди нахуй")
respond = {'attachment': None, 'text': None} respond = {'attachment': None, 'text': None}
message = message.split(' ', 1) message = message.split(' ', 1)
if message[0] == self._COMMANDS[0]: if message[0] == self._COMMANDS[0]:
respond['attachment'] = self.random_image() if(config.random_image_command):
respond['attachment'] = self.random_image()
else:
respond['text'] = errors_array["command_off"]
elif message[0] == self._COMMANDS[1]: elif message[0] == self._COMMANDS[1]:
respond['text'] = "Ваш ид: " + str(user_id) respond['text'] = "Ваш ид: " + str(user_id)
@ -353,10 +328,13 @@ class VkBot:
respond['text'] = errors_array["miss_argument"] respond['text'] = errors_array["miss_argument"]
elif message[0] == self._COMMANDS[6]: elif message[0] == self._COMMANDS[6]:
try: if(config.weather_command):
respond['text'] = get_weather(message[1]) try:
except IndexError: respond['text'] = get_weather(message[1])
respond['text'] = errors_array["miss_argument"] except IndexError:
respond['text'] = errors_array["miss_argument"]
else:
respond['text'] = errors_array["command_off"]
elif message[0] == self._COMMANDS[7]: elif message[0] == self._COMMANDS[7]:
try: try:
@ -380,7 +358,7 @@ class VkBot:
respond['text'] = errors_array["miss_argument"] respond['text'] = errors_array["miss_argument"]
elif message[0] == self._COMMANDS[11]: elif message[0] == self._COMMANDS[11]:
if self._ACCESS_LEVEL or int(user_id) == int(owner_id): if self._ACCESS_LEVEL or int(user_id) == int(config.owner_id):
try: try:
respond['text'] = self.debug(message[1]) respond['text'] = self.debug(message[1])
except IndexError: except IndexError:
@ -389,7 +367,7 @@ class VkBot:
respond["text"] = errors_array["access"] respond["text"] = errors_array["access"]
elif message[0] == self._COMMANDS[12]: elif message[0] == self._COMMANDS[12]:
if self._ACCESS_LEVEL or int(user_id) == int(owner_id): if self._ACCESS_LEVEL or int(user_id) == int(config.owner_id):
if self._MIDNIGHT_EVENT: if self._MIDNIGHT_EVENT:
self.change_midnight(False) self.change_midnight(False)
self.send("Уведомление о миднайте выключено") self.send("Уведомление о миднайте выключено")
@ -402,7 +380,7 @@ class VkBot:
respond['text'] = errors_array["access"] respond['text'] = errors_array["access"]
elif message[0] == self._COMMANDS[13]: elif message[0] == self._COMMANDS[13]:
if int(user_id) == int(owner_id): if int(user_id) == int(config.owner_id):
try: try:
if message[1] == "owner": if message[1] == "owner":
respond['text'] = "Теперь некоторыми командами может пользоваться только владелец бота" respond['text'] = "Теперь некоторыми командами может пользоваться только владелец бота"
@ -419,27 +397,15 @@ class VkBot:
respond['text'] = errors_array["access"] respond['text'] = errors_array["access"]
elif message[0] == self._COMMANDS[14]: elif message[0] == self._COMMANDS[14]:
if self._OWNER or int(user_id) == int(owner_id): if self._OWNER or int(user_id) == int(config.owner_id):
self.send("Бот выключается") self.send("Бот выключается")
exit(log(False, "[SHUTDOWN]")) exit(log(False, "[SHUTDOWN]"))
elif message[0] == self._COMMANDS[15]: elif message[0] == self._COMMANDS[15]:
try: respond['text'] = "Функция удалена за ненадобнастью"
if message[1] == "list":
respond['text'] = self.reminder(None, "list")
elif message[1] == "set":
self.send("О чём мне вам напомнить? (Введите \"Назад\", чтобы отменить установку)")
self.change_await("reminder task")
elif message[1] == "delete":
self.send(f"Введите название напоминания, которое необходимо удалить или \"Назад\", чтобы отменить удаление<br>{self.reminder(None, 'list')}")
self.change_await("reminder delete")
else:
respond['text'] = "Неверный аргумент"
except IndexError:
respond["text"] = errors_array['miss_argument']
elif message[0] == self._COMMANDS[16]: elif message[0] == self._COMMANDS[16]:
if self._ACCESS_LEVEL or int(user_id) == int(owner_id): if self._ACCESS_LEVEL or int(user_id) == int(config.owner_id):
if self._NEW_POST: if self._NEW_POST:
self.change_new_post(False) self.change_new_post(False)
self.send("Уведомление о новом посте выключено") self.send("Уведомление о новом посте выключено")
@ -463,11 +429,11 @@ class VkBot:
elif message[0] == self._COMMANDS[18]: elif message[0] == self._COMMANDS[18]:
if int(self._CHAT_ID) <= 2000000000: if int(self._CHAT_ID) <= 2000000000:
respond['text'] = "Данный чат не является беседой" respond['text'] = "Данный чат не является беседой"
elif int(user_id) != int(owner_id): elif int(user_id) != int(config.owner_id):
respond['text'] = errors_array["access"] respond['text'] = errors_array["access"]
else: else:
try: try:
vk.method("messages.getConversationMembers", {"peer_id": int(self._CHAT_ID), "group_id": group_id}) config.vk.method("messages.getConversationMembers", {"peer_id": int(self._CHAT_ID), "group_id": config.group_id})
if self._ADMIN_MODE: if self._ADMIN_MODE:
respond["text"] = "Режим модерирования выключен" respond["text"] = "Режим модерирования выключен"
self.change_admin_mode(False) self.change_admin_mode(False)
@ -515,16 +481,6 @@ class VkBot:
else: else:
answer = "Никто не пользуется !game" answer = "Никто не пользуется !game"
return answer return answer
elif arg == "tasks":
if self._OWNER:
tasks = db.get_all_tasks()
if len(tasks) > 0:
answer = "Напоминания в !reminder"
for i in tasks:
answer += f"<br>id{i['chat_id']} - {i['time']}: {i['task']}"
else:
answer = "Никто не пользуется !reminder"
return answer
else: else:
up_time = time.time() - debug_array['start_time'] up_time = time.time() - debug_array['start_time']
time_d = int(up_time) / (3600 * 24) time_d = int(up_time) / (3600 * 24)
@ -543,43 +499,15 @@ class VkBot:
len(bot)) + "<br>Запуск бота по часам сервера: " + datetime_time.strftime('%d.%m.%Y %H:%M:%S UTC') len(bot)) + "<br>Запуск бота по часам сервера: " + datetime_time.strftime('%d.%m.%Y %H:%M:%S UTC')
return answer return answer
def reminder(self, string, stage):
if stage == "task":
self._SET_UP_REMINDER['task'] = string
return True
elif stage == "time":
try:
datetime_object = time.strptime(string, '%d.%m.%y %H:%M')
self._SET_UP_REMINDER['time'] = int(time.mktime(datetime_object))
db.set_new_task(self._CHAT_ID, self._SET_UP_REMINDER['time'], self._SET_UP_REMINDER["task"])
log(False, f"[BOT_{self._CHAT_ID}] New reminder set")
return True
except ValueError:
return False
elif stage == "remind":
self.send(f"Пришло время вам напомнить: {string}")
log(False, f"[BOT_{self._CHAT_ID}] Reminder worked")
return True
elif stage == "list":
tasks = db.get_from_tasks(self._CHAT_ID)
print(tasks)
if len(tasks) == 0:
respond = "У вас не установлено ни одно напоминание"
else:
respond = 'Установленные напоминания:<br>'
for i in tasks:
datetime_time = datetime.datetime.fromtimestamp(int(i['time']))
respond += f"<br>{datetime_time.strftime('%d.%m.%y %H:%M')} - {i['task']}"
return respond
elif stage == "delete":
return db.delete_task(self._CHAT_ID, string)
def game(self, thing, user_id): def game(self, thing, user_id):
data = db.get_from_users(user_id) data = db.get_from_users(user_id)
if len(data) == 0: if (config.use_database):
create_new_bot_object(user_id) if len(data) == 0:
data = db.get_from_users(user_id) create_new_bot_object(user_id)
d = data[0] data = db.get_from_users(user_id)
d = data[0]
else:
d = data
if thing == "статистика": if thing == "статистика":
try: try:
winrate = (d['game_wins']/(d['game_wins']+d['game_defeats']+d['game_draws'])) * 100 winrate = (d['game_wins']/(d['game_wins']+d['game_defeats']+d['game_draws'])) * 100
@ -624,7 +552,7 @@ class VkBot:
def get_info_user(self, id): def get_info_user(self, id):
try: try:
user_info = vk.method('users.get', {'user_ids': id, 'fields': 'verified,last_seen,sex'}) user_info = config.vk.method('users.get', {'user_ids': id, 'fields': 'verified,last_seen,sex'})
except vk_api.exceptions.ApiError as lol: except vk_api.exceptions.ApiError as lol:
err = "Method users.get: " + str(lol) err = "Method users.get: " + str(lol)
log(True, err) log(True, err)
@ -675,7 +603,7 @@ class VkBot:
def get_info_group(self, id): def get_info_group(self, id):
try: try:
group_info = vk.method('groups.getById', {'group_id': id, 'fields': 'description,members_count'}) group_info = config.vk.method('groups.getById', {'group_id': id, 'fields': 'description,members_count'})
except vk_api.exceptions.ApiError as lol: except vk_api.exceptions.ApiError as lol:
err = "Method groups.getById: " + str(lol) err = "Method groups.getById: " + str(lol)
log(True, err) log(True, err)
@ -691,9 +619,9 @@ class VkBot:
return answer return answer
def random_image(self): def random_image(self):
group = "-" + str(group_id) group = "-" + str(config.group_id)
random_images_query = vk_mda.method('photos.get', random_images_query = config.vk_mda.method('photos.get',
{'owner_id': group, 'album_id': album_for_command, 'count': 1000}) {'owner_id': group, 'album_id': config.album_for_command, 'count': 1000})
info = "Method photos.get: " + str(random_images_query['count']) + " photos received" info = "Method photos.get: " + str(random_images_query['count']) + " photos received"
log(False, info) log(False, info)
random_number = random.randrange(random_images_query['count']) random_number = random.randrange(random_images_query['count'])
@ -756,7 +684,7 @@ class VkBot:
def send(self, message=None, attachment=None): def send(self, message=None, attachment=None):
try: try:
random_id = random.randint(-9223372036854775808, 9223372036854775807) random_id = random.randint(-9223372036854775808, 9223372036854775807)
message = vk.method('messages.send', message = config.vk.method('messages.send',
{'peer_id': self._CHAT_ID, 'message': message, 'random_id': random_id, {'peer_id': self._CHAT_ID, 'message': message, 'random_id': random_id,
'attachment': attachment}) 'attachment': attachment})
log(False, f'[BOT_{self._CHAT_ID}] id: {message}, random_id: {random_id}') log(False, f'[BOT_{self._CHAT_ID}] id: {message}, random_id: {random_id}')
@ -818,25 +746,10 @@ def midnight():
log(False, "[EVENT_ENDED] \"Midnight\"") log(False, "[EVENT_ENDED] \"Midnight\"")
time.sleep(1) time.sleep(1)
else: else:
time.sleep(0.50) time.sleep(0.50)
def check_tasks():
while True:
try:
tasks = db.get_all_tasks()
for i in tasks:
current_time = time.time()+10800
if i['time'] == int(current_time):
bot[i['chat_id']].reminder(i['task'], "remind")
db.delete_task(i["chat_id"], i['task'])
except RuntimeError:
continue
time.sleep(0.4)
load_users() load_users()
tread_bots = threading.Thread(target=bots) tread_bots = threading.Thread(target=bots)
tread_midnight = threading.Thread(target=midnight, daemon=True) tread_midnight = threading.Thread(target=midnight, daemon=True)
tread_tasks = threading.Thread(target=check_tasks, daemon=True)
tread_bots.start() tread_bots.start()
tread_midnight.start() tread_midnight.start()
tread_tasks.start()

View File

@ -23,11 +23,9 @@
!midnight - бот будет уведомлять вас о 00:00 по Москве. Отправьте ещё раз, чтобы бот больше вас не уведомлял !midnight - бот будет уведомлять вас о 00:00 по Москве. Отправьте ещё раз, чтобы бот больше вас не уведомлял
!reminder *set/list/delete* - напоминалка. set устанавливает напоминание, delete удаляет, list выдаёт список ваших напоминаний
!subscribe - бот будет уведомлять вас новых постах в группе. Отправьте ещё раз, чтобы бот больше вас не уведомлял !subscribe - бот будет уведомлять вас новых постах в группе. Отправьте ещё раз, чтобы бот больше вас не уведомлял
!h, !help - справка !h, !help - справка
Дата последнего обновления: 09.06.2020 (Бот стал реагировать на плохие слова) Дата последнего обновления: 01.07.2020 (Обновление алгоритмов работы)
Проект бота на GitHub: https://github.com/dan63047/dan63047pythonbot Проект бота на GitHub: https://github.com/dan63047/dan63047pythonbot