diff --git a/analyse_and_bot_functions.py b/analyse_and_bot_functions.py new file mode 100644 index 0000000..83683a4 --- /dev/null +++ b/analyse_and_bot_functions.py @@ -0,0 +1,443 @@ +import vk +import datetime +import requests +import json +# from new_main import vk_api2 as vk_api2 +# from new_main import month_length as month_length +import group_class as gc +import time +import random +import math + + +token = "65e6efa565e6efa565e6efa54f6593fb1f665e665e6efa53a5c6937a4636b3416a8bd92" +group_token = "17e681fbe171945431a04f1abc752d41ff888698288abf74124de4e782c67f36e76484601991870f56b7a" +analyse_group_id = 'memkn' +my_group_id = 'memkn_funclub' +my_number_group_id = 200698416 + +session1 = vk.AuthSession(access_token=token) +session2 = vk.AuthSession(access_token=group_token) +vk_api = vk.API(session1, v=5.92) +vk_api2 = vk.API(session2, v=5.92) + +month_length = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] +days_of_the_week = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"] + + +def get_message(group_id, server_, ts_, key_): + # gets the message from the user + response = requests.get('{server}?act=a_check&key={key}&ts={ts}&wait=25'.format + (server=server_, key=key_, ts=ts_)).json() + if 'updates' in response and len(response['updates']) > 0: + return response['updates'][0]['object']['body'], response['updates'][0]['object']['user_id'], response['ts'] + return "", -1, response['ts'] + + +def find_the_task(group_id, user_id, tasks): + for x in range(len(tasks)): + if tasks[x]['master'] == user_id and tasks[x]['group'].group_id == group_id: + return x + return -1 + + +def find_the_group(group_id, tasks): + for x in tasks: + if x['group'].group_id == group_id: + return 1 + return 0 + + +def process_input_message(message): + # gets the massage from the user and returns a code which depends on the message type. Also returns the group id + # and needed frequency. These fields will be used afterwards only if the message is: group_id: ...; period: ... + if message == "": + return 0, "" + if message[0] == '~': + if not check_recommend_time(message): + return -1, "" + if len(message) < 7 or not check_for_correct(message[6:].strip()): + return 5, "" + return 12, message + if message == "Начать": + return 14, "" + if message == "Что обрабатывается для меня?": + return 15, "" + if message == "Сколько свободных мест?": + return 13, "" + if message == "Текущий процент: ВКЛ": + return 17, "1" + if message == "Текущий процент: ВЫКЛ": + return 17, "0" + if message == "Set time": + return 11, "" + if message == "Want to give a task": + return 10, "" + if message.lower() == "help": + return 9, "" + if len(message) > 4 and (message[0: 4] == "stop" or message[0: 4] == "Stop") and message[4] == ':': + group_to_stop = message[5:].strip() + if not check_for_correct(group_to_stop): + return 5, group_to_stop + return 1, group_to_stop + if message == "lsr_memkn6": + return 2, "" + string1 = message[0: 6] + string2 = message[0: 5] + if string1 == "Привет" or string1 == "привет" or string2 == "Hello" or string2 == "hello": + return 4, "" + if len(message) > 13 and (message[0: 13] == "Recommend day" or + message[0: 13] == "recommend day") and message[13] == ':': + recommend_group = message[14:].strip() + if not check_for_correct(recommend_group): + return 5, recommend_group + return 7, recommend_group + if len(message) > 14 and (message[0: 14] == "Recommend week" or + message[0: 14] == "recommend week") and message[14] == ':': + recommend_group = message[15:].strip() + if not check_for_correct(recommend_group): + return 5, recommend_group + return 8, recommend_group + if message[0] == '$' and " " not in message[1:].strip(): + group = message[1:].strip() + if not check_for_correct(group): + return 5, "" + if not check_group_size(group): + return 16, "" + return 3, group + return -1, "" + + +def get_r_id(): + t = datetime.datetime.now() + random_id = t.minute * 60000000 + t.second * 1000000 + t.microsecond + return random_id + + +def switch_off(current_user_id, tasks): + # switches the bot off, the special password is needed + r_id = get_r_id() + vk_api2.messages.send(user_id=current_user_id, message="Я терпел, но сегодня я ухожу...", random_id=r_id) + value = vk_api2.users.get(user_ids=current_user_id, fields=['first_name', 'last_name']) + string = f"потому что меня выключил {value[0]['last_name']} {value[0]['first_name']}" + for x in tasks: + r_id = get_r_id() + vk_api2.messages.send( + user_id=x['master'], + message=f"Ваш запрос по группе '{x['group'].name}' отменён, {string}", + random_id=r_id) + return 0 + + +def incorrect_id(current_user_id): + # informs about the mistake + r_id = get_r_id() + vk_api2.messages.send(user_id=current_user_id, message="Группы с таким айдишником нету как бэ", random_id=r_id) + return + + +def cancel_the_task(have_a_task, index_to_delete, current_user_id): + # Cancels the current task, it is is asked by the user who gave the task earlier + r_id = get_r_id() + have_a_task.pop(index_to_delete) + vk_api2.messages.send(user_id=current_user_id, message="Штош, отменяю!", + random_id=r_id) + return + + +def say_hello(current_user_id): + # sends a message 'Ну привет, ....' + r_id = get_r_id() + string = "Ну привет, " + value = vk_api2.users.get(user_ids=current_user_id, fields='first_name') + string += value[0]['first_name'] + something = vk_api2.messages.send(user_id=current_user_id, message=string, random_id=r_id) + return + + +def instruction_message(current_user_id): + # sends the message if user did send us the message of an unknown format + r_id = get_r_id() + string = "Я вас не понимаю! Пожалуйста, прочитайте инструкцию! " + string += "Получить инструкцию можно, нажав на кнопочку 'help'" + + # attachment="photo-200698416_457239022" + vk_api2.messages.send( + user_id=current_user_id, message=string, random_id=r_id + ) + return + + +def check_recommend_time(time_string): + if time_string[3] != ':' or not time_string[1: 3].isdigit() or not time_string[4: 6].isdigit(): + return 0 + hours = int(time_string[1: 3]) + if 0 <= hours < 24: + return 1 + return 0 + + +def send_big_instruction(current_user_id): + # sends the instruction for the user + r_id = get_r_id() + + kb = \ + { + "one_time": False, + "buttons": [ + [ + { + "action": { + "type": "text", + "payload": "{\"button\": \"2\"}", + "label": "help" + }, + "color": "positive" + }, + { + "action": { + "type": "text", + "payload": "{\"button\": \"2\"}", + "label": "Сколько свободных мест?" + }, + "color": "primary" + } + ], + [ + { + "action": { + "type": "text", + "payload": "{\"button\": \"2\"}", + "label": "Что обрабатывается для меня?" + }, + "color": "secondary" + } + ], + [ + { + "action": { + "type": "text", + "payload": "{\"button\": \"2\"}", + "label": "Текущий процент: ВКЛ" + }, + "color": "positive" + }, + { + "action": { + "type": "text", + "payload": "{\"button\": \"2\"}", + "label": "Текущий процент: ВЫКЛ" + }, + "color": "negative" + } + ] + ] + } + + kb = json.dumps(kb, ensure_ascii=False).encode('utf-8') + kb = str(kb.decode('utf-8')) + + text = "Вот что я понимаю и умею:\n 1) $group_id - где вместо group_id айдишник нужной группы. " + \ + "Я приму группу на обаботку и буду писылать отчёты. \n\n" + \ + "2) recommend day: group_id - именно в таком фомате. Я пришлю лучшее время для постов за сегодня\n\n" + \ + "3) recommend week: group_id - именно в таком фомате." + \ + "Я пришлю лучшее время для постов за текущую неделю\n\n" + \ + "4) ~22:00 group_id - тут минуты значения не имеют, можно всегда писать 00, а вместо 22 - любое число" + \ + ", не большее 23, конечно. Тогда отчёты по группе group_id будут приходить в указанный час\n\n" + \ + "5) Stop: group_id - и я сразу перестану следить за группой group_id\n\n" + \ + "Можно здооваться - 'привет' или 'hello' а начале предложения\n\n" + + vk_api2.messages.send( + user_id=current_user_id, + message=text, + # attachment="photo-200698416_457239023", + random_id=r_id, + keyboard=kb + ) + return + + +def send_keyboard(current_user_id): + # sends the instruction for the user + r_id = get_r_id() + + kb = \ + { + "one_time": False, + "buttons": [ + [ + { + "action": { + "type": "text", + "payload": "{\"button\": \"2\"}", + "label": "help" + }, + "color": "positive" + }, + { + "action": { + "type": "text", + "payload": "{\"button\": \"2\"}", + "label": "Сколько свободных мест?" + }, + "color": "primary" + } + ], + [ + { + "action": { + "type": "text", + "payload": "{\"button\": \"2\"}", + "label": "Что обрабатывается для меня?" + }, + "color": "secondary" + } + ], + [ + { + "action": { + "type": "text", + "payload": "{\"button\": \"2\"}", + "label": "Текущий процент: ВКЛ" + }, + "color": "positive" + }, + { + "action": { + "type": "text", + "payload": "{\"button\": \"2\"}", + "label": "Текущий процент: ВЫКЛ" + }, + "color": "negative" + } + ] + ] + } + + kb = json.dumps(kb, ensure_ascii=False).encode('utf-8') + kb = str(kb.decode('utf-8')) + + vk_api2.messages.send( + user_id=current_user_id, + message="Лови клавиатуру)", + random_id=r_id, + keyboard=kb + ) + return + + +def check_for_correct(group_id_to_check): + your_group_info = vk_api2.groups.getById(group_id=group_id_to_check, fields='members_count', count=5) + if your_group_info[0]['id'] == my_number_group_id and group_id_to_check != 'memkn_funclub': + return 0 + return 1 + + +def not_available(current_user_id): + r_id = get_r_id() + vk_api2.messages.send(user_id=current_user_id, message="Временно недоступно!", random_id=r_id) + vk_api2.messages.send(user_id=current_user_id, sticker_id=4331, random_id=(r_id + 1)) + return + + +def cannot_receive_more_tasks(current_user_id): + r_id = get_r_id() + vk_api2.messages.send(user_id=current_user_id, message="Извини, я уже завален работой...", random_id=r_id) + vk_api2.messages.send(user_id=current_user_id, sticker_id=2, random_id=(r_id + 1)) + return + + +def have_such_a_task_already(current_user_id): + r_id = get_r_id() + vk_api2.messages.send(user_id=current_user_id, message="Чел, ты... уже давал мне такое задание...", random_id=r_id) + vk_api2.messages.send(user_id=current_user_id, sticker_id=6158, random_id=(r_id + 1)) + return + + +def no_such_a_task(current_user_id): + r_id = get_r_id() + vk_api2.messages.send( + user_id=current_user_id, message="Вы мне такой группы на обработку не давали...", random_id=r_id + ) + vk_api2.messages.send(user_id=current_user_id, sticker_id=6559, random_id=(r_id + 1)) + return + + +def free_places(current_user_id, number): + r_id = get_r_id() + number = 10 - number + if number > 4: + vk_api2.messages.send( + user_id=current_user_id, message=f"Могу принять ещё {number} запросов", random_id=r_id + ) + elif number == 1: + vk_api2.messages.send( + user_id=current_user_id, message="Могу принять ещё один запрос", random_id=r_id + ) + elif 1 < number < 5: + vk_api2.messages.send( + user_id=current_user_id, message=f"Могу принять {number} запроса", random_id=r_id + ) + else: + vk_api2.messages.send( + user_id=current_user_id, message="Мне жаль, но я загужен до отказа((", random_id=r_id + ) + return + + +def task_by_button(current_user_id): + r_id = get_r_id() + vk_api2.messages.send( + user_id=current_user_id, + message="Send the group_id and the period with a whitespace between them and '$' in the beginning", + random_id=r_id + ) + + +def user_groups(current_user_id, have_a_task): + r_id = get_r_id() + found_something = 0 + groups = "" + for x in have_a_task: + if x['master'] == current_user_id: + found_something = 1 + groups += x['group'].name + "\n" + if found_something: + vk_api2.messages.send( + user_id=current_user_id, message=("Вот ваши группы: \n" + groups), random_id=r_id + ) + else: + vk_api2.messages.send( + user_id=current_user_id, message="Вы ещё не давали заданий", random_id=r_id + ) + + +def check_group_size(group_id): + your_group_info = vk_api.groups.getById(group_id=group_id, fields='members_count') + number_of_members = your_group_info[0]['members_count'] + if number_of_members > 500000: + return 0 + return 1 + + +def too_big_group(current_user_id): + r_id = get_r_id() + vk_api2.messages.send( + user_id=current_user_id, + message="Ваша группа слишком большая, её обработка существенно меня затормозит, так что прошу простить", + random_id=r_id + ) + + +def change_recommend_time(begin_file, task_number, return_message): + file = open(begin_file, "r") + commands = list(file.read().split('\n')) + file.close() + file = open(begin_file, "w") + for cmd_number in range(len(commands)): + if cmd_number != task_number: + file.write(commands[cmd_number] + '\n') + else: + ind = commands[cmd_number].rfind(" ") + file.write(commands[cmd_number][:ind] + f" {int(return_message[1: 3])}" + '\n') + file.close() diff --git a/begin_task.txt b/begin_task.txt new file mode 100644 index 0000000..4a097bb --- /dev/null +++ b/begin_task.txt @@ -0,0 +1,8 @@ +192003983 427479334 0 +171934615 427479334 0 +200698416 427479334 0 +136245663 427479334 0 +52298374 427479334 0 +336 427479334 0 +171934615 151408129 0 +172053584 151408129 0 \ No newline at end of file diff --git a/group_class.py b/group_class.py new file mode 100644 index 0000000..b499f0a --- /dev/null +++ b/group_class.py @@ -0,0 +1,415 @@ +import vk +import datetime +import sqlite3 as sql +import requests +import time +import random +import analyse_and_bot_functions as func +import math + +# from new_main import vk_api2 as vk_api2 +# from new_main import days_of_the_week as days_of_the_week + +con = sql.connect('super_vk_bot3.db') +cur = con.cursor() + +token = "65e6efa565e6efa565e6efa54f6593fb1f665e665e6efa53a5c6937a4636b3416a8bd92" +group_token = "17e681fbe171945431a04f1abc752d41ff888698288abf74124de4e782c67f36e76484601991870f56b7a" +analyse_group_id = 'memkn' +my_group_id = 'memkn_funclub' +my_number_group_id = 200698416 + +session1 = vk.AuthSession(access_token=token) +session2 = vk.AuthSession(access_token=group_token) +vk_api = vk.API(session1, v=5.92) +vk_api2 = vk.API(session2, v=5.92) + +month_length = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] +days_of_the_week = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"] + + +class Group: + def __init__(self, group_id, master_id): + """ + group_id: the group to analyse + master_id: id of the user who gave the task + frequency: how many minutes should pass between two adjoining analyses + analyses_per_day: daily amount of analyses + percents: online percents in each 'moment' of the week (not more than 672 moments) + archive: old data, we need this to delete old info whe 4 weeks pass + number: technical moment. Actually, first three weeks are special: to count the average meaning we need not to + divide by 4, but to divide by the number - spacial for each array cell. + Just because we don't have enough information yet!! + index_to_date: in the storage we keep the moment of time as a code - gust an integer number. But the user + would prefer 'Mon, 00:00: 30%' to '0: 30%'. That's why we need this array + """ + self.recommend_hour = 0 + self.group_id = group_id + group_object = vk_api2.groups.getById(group_id=group_id, fields=["name"]) + self.name = str(group_object[0]['name']) + self.master_id = master_id + self.period = 15 + self.analyses_per_day = 96 + self.current_percents = 1 + + # con = sql.connect('vk_bot.db') + name = "stats" + str(self.group_id) + str(self.master_id) + with con: + # cur = con.cursor() + cur.execute(f"CREATE TABLE IF NOT EXISTS {name} (" + "'analyse_number' INTEGER PRIMARY KEY, " + "'average_percent' INTEGER, " + "'archive1' INTEGER, " + "'archive2' INTEGER, " + "'archive3' INTEGER, " + "'archive4' INTEGER, " + "'weeks_passed' INTEGER, " + "'time' STRING" + ")" + ) + sq = f"SELECT * FROM {name} WHERE analyse_number={0}" + cur.execute(sq) + table_existed = cur.fetchone() + con.commit() + if table_existed is None or table_existed == []: + for j in range(7): + for i in range(self.analyses_per_day * j, self.analyses_per_day * (j + 1)): + s = days_of_the_week[j] + ", " + hours = (i % self.analyses_per_day) * self.period // 60 + minutes = (i % self.analyses_per_day) * self.period % 60 + if hours < 10: + s += "0" + s += str(hours) + ":" + if minutes < 10: + s += "0" + s += str(minutes) + stats = (i, 0, 0, 0, 0, 0, 0, s) + cur.execute(f"""INSERT OR REPLACE INTO {name} VALUES (?, ?, ?, ?, ?, ?, ?, ?)""", stats) + con.commit() + + def del_table(self): + # con = sql.connect('vk_bot.db') + name = "stats" + str(self.group_id) + str(self.master_id) + # cur = con.cursor() + cur.execute(f"""DELETE FROM {name}""") + con.commit() + + def count_online_proportion(self): + """ + gets the number of members online, ant the total number of members, not counting those, + whose info is not is not available + :param self: the object of the class Group. We need the group id + :return: two integers - the number of members with available online-information and the number of members online + """ + online = 0 + your_group_info = vk_api.groups.getById(group_id=self.group_id, fields='members_count') + number_of_members = your_group_info[0]['members_count'] + number_of_members1 = number_of_members + already_count = 0 + while already_count < number_of_members: + group_members_ids = vk_api.groups.getMembers(group_id=self.group_id, offset=already_count, fields='online') + for x in group_members_ids['items']: + if 'online' in x: + online += x['online'] + else: + number_of_members1 -= 1 + already_count += 1000 + if number_of_members1 == 0: + return -1, -1 + else: + return number_of_members1, online + + def group_analyse(self): + """ + counts the online percent + :return: + """ + all_members, online_members = self.count_online_proportion() + percent = online_members / all_members * 100 + percent = math.ceil(percent) + + return percent + + def update_data(self, new_one, cell_to_update): + # con = sql.connect('vk_bot.db') + # cur = con.cursor() + name = "stats" + str(self.group_id) + str(self.master_id) + + sq = f"SELECT * FROM {name} WHERE analyse_number={cell_to_update}" + cur.execute(sq) + values_arr = cur.fetchall() + values_tuple = values_arr[0] + values = [] + for i in range(7): + values.append(values_tuple[i]) + print(values) + if values[6] >= 4: + values[1] *= 4 + values[1] = values[1] - values[2] + new_one + values[1] /= 4 + else: + values[1] *= values[6] + values[1] += new_one + values[6] += 1 + values[1] /= values[6] + for j in range(3): + values[2 + j] = values[3 + j] + values[5] = new_one + + stats = (values[0], values[1], values[2], values[3], values[4], values[5], values[6], values_tuple[7]) + cur.execute(f"""INSERT OR REPLACE INTO {name} VALUES (?, ?, ?, ?, ?, ?, ?, ?)""", stats) + con.commit() + + def recommendation_for_this_day_of_the_week(self): + """ + this function runs at about 00:00 daily and recommends: when it is going to be the best time for posts this day. + :return: returns nothing, just sends a message with recommendation + """ + # average stats and recommendation for this day of the week past 4 last weeks + + # con = sql.connect('vk_bot.db') + # cur = con.cursor() + name = "stats" + str(self.group_id) + str(self.master_id) + + r_id = func.get_r_id() + + today_or_tomorrow = "сегодня" + day = datetime.datetime.now().weekday() + if self.recommend_hour != 0: + day = (day + 1) % 7 + today_or_tomorrow = "завтра" + + start = day * self.analyses_per_day + finish = (day + 1) * self.analyses_per_day + check = 0 + + for t in range(start, finish): + sq = f"SELECT weeks_passed FROM {name} WHERE analyse_number={t}" + cur.execute(sq) + checker = cur.fetchone() + check += checker[0] + if check == 0: # Если за этот день недели вообще нет данных + day = (day - 1) % 7 # то возьмём данные за предыдущий день + start = day * self.analyses_per_day + finish = (day + 1) * self.analyses_per_day + + recommend_message = f"Вероятно, {today_or_tomorrow} лучше всего выкладывать посты в группе " + \ + f"'{self.name}' в " + max_online, best_time = 0, 0 + for i in range(start, finish): + sq = f"SELECT average_percent FROM {name} WHERE analyse_number={i}" + cur.execute(sq) + current_percent = cur.fetchone()[0] + if current_percent > max_online: + max_online = current_percent + best_time = i + + sq = f"SELECT time FROM {name} WHERE analyse_number={best_time}" + cur.execute(sq) + recommend_time = cur.fetchone()[0] + recommend_message += recommend_time[5:] + ": " + str(max_online) + "%" + vk_api2.messages.send(user_id=self.master_id, message=recommend_message, random_id=r_id) + return + + def get_one_day_information_v1( + self, day, max_summary_percent, day_with_the_highest_summary_percent, best_time, max_online + ): + """ + function to look for highest percents between average percents on a week + :param day: the number of the day to get information about + :param max_summary_percent: the day withe the highest summary online percent + (among those that we have already checked). So, it is the current highest percent for a day. + :param day_with_the_highest_summary_percent: Number of the day when the 'max_summary_percent' was fixed + :param best_time: the moment of time withe highest online percent during the week + :param max_online: that highest percent + :return: updated 'max_summary_percent', 'day_with_the_highest_summary_percent', 'best_time' and 'max_online' + """ + # needed for 'recommendation_for_this_week' + + # con = sql.connect('vk_bot.db') + # cur = con.cursor() + name = "stats" + str(self.group_id) + str(self.master_id) + + summary_percents = 0 + for i in range(self.analyses_per_day * day, self.analyses_per_day * (day + 1)): + sq = f"SELECT average_percent FROM {name} WHERE analyse_number={i}" + cur.execute(sq) + current_percent = cur.fetchone()[0] + summary_percents += current_percent + if current_percent > max_online: + max_online = current_percent + best_time = i + if summary_percents > max_summary_percent: + return summary_percents, day, best_time, max_online + return max_summary_percent, day_with_the_highest_summary_percent, best_time, max_online + + def get_one_day_information_v2( + self, day, max_summary_percent, day_with_the_highest_summary_percent, best_time, max_online + ): + # needed for 'give_this_week_stats' + """ + function to look for highest percents between certain percents on the current week + :param day: the number of the day to get information about + :param max_summary_percent: the day withe the highest summary online percent + (among those that we have already checked). So, it is the current highest percent for a day. + :param day_with_the_highest_summary_percent: Number of the day when the 'max_summary_percent' was fixed + :param best_time: the moment of time withe highest online percent during the week + :param max_online: that highest percent + :return: updated 'max_summary_percent', 'day_with_the_highest_summary_percent', 'best_time' and 'max_online' + """ + # needed for 'recommendation_for_this_week' + + # con = sql.connect('vk_bot.db') + # cur = con.cursor() + name = "stats" + str(self.group_id) + str(self.master_id) + + summary_percents = 0 + for i in range(self.analyses_per_day * day, self.analyses_per_day * (day + 1)): + sq = f"SELECT archive4 FROM {name} WHERE analyse_number={i}" + cur.execute(sq) + current_percent = cur.fetchone()[0] + summary_percents += current_percent + if current_percent > max_online: + max_online = current_percent + best_time = i + if summary_percents > max_summary_percent: + return summary_percents, day, best_time, max_online + return max_summary_percent, day_with_the_highest_summary_percent, best_time, max_online + + def recommendation_for_this_week(self): + """ + function that runs weekly at about 00:00 and sends two messages: day withe the highest average percent and + time(with a day) when the percent was highest + Takes average percents for last four weeks + :return: nothing + """ + # recommendation gives the day with the highest average percents past 4 last weeks + + # con = sql.connect('vk_bot.db') + # cur = con.cursor() + name = "stats" + str(self.group_id) + str(self.master_id) + + r_id = func.get_r_id() + recommend_message = f"Вероятно, на этой неделе лучшим временем для постов в группе '{self.name}' будет " + max_online, best_time, max_summary_during_the_day, best_day = 0, 0, 0, 0 + + for j in range(7): + max_summary_during_the_day, best_day, best_time, max_online = \ + self.get_one_day_information_v1(j, max_summary_during_the_day, best_day, best_time, max_online) + max_average_during_the_day = max_summary_during_the_day / self.analyses_per_day + + sq = f"SELECT time FROM {name} WHERE analyse_number={best_time}" + cur.execute(sq) + recommend_time = cur.fetchone()[0] + recommend_message += recommend_time + ": " + str(max_online) + "%" + + vk_api2.messages.send(user_id=self.master_id, message=recommend_message, random_id=r_id) + recommend_message = "This week, the day with the biggest average online percent was " + \ + days_of_the_week[best_day] + ": " + str(max_average_during_the_day) + "%" + vk_api2.messages.send(user_id=self.master_id, message=recommend_message, random_id=(r_id + 1)) + return + + def give_today_stats(self): + """ + Gives today's time with the highest online percent + :return: nothing + """ + # Just today's stats + + # con = sql.connect('vk_bot.db') + # cur = con.cursor() + name = "stats" + str(self.group_id) + str(self.master_id) + + r_id = func.get_r_id() + + day = datetime.datetime.now().weekday() + + start = day * self.analyses_per_day + finish = (day + 1) * self.analyses_per_day + + recommend_message = f"Сегодня лучшим для постов временем в группе '{self.name}' было " + + max_online, best_time = 0, 0 + for i in range(start, finish): + sq = f"SELECT archive4 FROM {name} WHERE analyse_number={i}" + cur.execute(sq) + current_percent = cur.fetchone()[0] + if current_percent > max_online: + max_online = current_percent + best_time = i + + sq = f"SELECT time FROM {name} WHERE analyse_number={best_time}" + cur.execute(sq) + recommend_time = cur.fetchone()[0] + recommend_message += recommend_time[5:] + ": " + str(max_online) + "%" + vk_api2.messages.send(user_id=self.master_id, message=recommend_message, random_id=r_id) + return + + def give_this_week_stats(self): + """ + does the same as the 'recommendation_for_this_week' but can be summoned by the user every moment. It also take + certain percents of the current week, not average + :return: nothing + """ + # Just this week stats + + # con = sql.connect('vk_bot.db') + # cur = con.cursor() + name = "stats" + str(self.group_id) + str(self.master_id) + + r_id = func.get_r_id() + recommend_message = f"На этой неделе лучшим для постов в группе '{self.name}' временем было " + max_online, best_time, max_summary_during_the_day, best_day = 0, 0, 0, 0 + + for j in range(7): + max_summary_during_the_day, best_day, best_time, max_online = \ + self.get_one_day_information_v2(j, max_summary_during_the_day, best_day, best_time, max_online) + max_average_during_the_day = max_summary_during_the_day // self.analyses_per_day + 1 + + sq = f"SELECT time FROM {name} WHERE analyse_number={best_time}" + cur.execute(sq) + recommend_time = cur.fetchone()[0] + recommend_message += recommend_time + ": " + str(max_online) + "%" + vk_api2.messages.send(user_id=self.master_id, message=recommend_message, random_id=r_id) + + recommend_message = "This week, the day with the biggest average online percent was " + \ + days_of_the_week[best_day] + ": " + str(max_average_during_the_day) + "%" + vk_api2.messages.send(user_id=self.master_id, message=recommend_message, random_id=(r_id + 1)) + return + + def work_and_print(self): + """ + updates data and sends current online percent + :return: + """ + r_id = func.get_r_id() + + week_day = datetime.datetime.now().weekday() + t = datetime.datetime.now() + + array_cell = week_day * self.analyses_per_day + (t.hour * 60 + t.minute) // self.period + percent = self.group_analyse() + + self.update_data(percent, array_cell) + + if self.current_percents: + string = f"В группе '{self.name}' сейчас онлайн {str(percent)}% участников" + vk_api2.messages.send(user_id=self.master_id, message=string, random_id=r_id) + return + + def calculate_new_analyse_time(self): + """ + This function runs in the very beginning. It counts when to start analysing and when to give recommendations + """ + r_id = func.get_r_id() + current_time = datetime.datetime.now().replace(second=0, microsecond=0) + current_minutes = current_time.minute + current_time.hour * 60 + minutes_to_wait = self.period - current_minutes % self.period + next_analyse_time = current_time + datetime.timedelta(0, 0, 0, minutes_to_wait // 60, minutes_to_wait % 60, 0, + 0) + next_recommend_time = current_time.replace(microsecond=0, second=0, minute=0, hour=0) + datetime.timedelta( + days=1 + ) + ok_message = f"Йес, май диар! Обработка '{self.name}' начата, результат через {minutes_to_wait} минут!" + vk_api2.messages.send(user_id=self.master_id, message=ok_message, random_id=r_id) + return next_analyse_time, next_recommend_time diff --git a/main.py b/main.py index dc51b8e..8c633a5 100644 --- a/main.py +++ b/main.py @@ -1,69 +1,219 @@ -import vk -import datetime - - -token = "65e6efa565e6efa565e6efa54f6593fb1f665e665e6efa53a5c6937a4636b3416a8bd92" -session1 = vk.AuthSession(access_token=token) -vk_api = vk.API(session1, v=5.92) - -group_id = 'memkn' - - -def get_user_last_seen(profile_id): - """ - gets when user was online - :param profile_id: - :return time: - """ - value = vk_api.users.get(user_ids=profile_id, fields='last_seen') - if 'last_seen' not in value[0]: - return None - online_time = datetime.datetime.fromtimestamp(value[0]['last_seen']['time']) - return online_time - - -def get_group_followers(group_page_id): - """ - getting group followers - :param group_page_id: - :return list of followers id: - """ - value = vk_api.groups.getMembers(group_id=group_page_id) - followers_id = [] - for user in value['items']: - followers_id.append(user) - return followers_id - - -def approximate_time(real_time): - approximated_online_time = real_time.replace(minute=(real_time.minute + 2) % 60) - return approximated_online_time - - -def is_online(online_time): - now_time = datetime.datetime.now() - now_time = now_time.replace(microsecond=0) - if online_time >= now_time: - return 1 - else: - return 0 - - -def online_proportion(group_page_id): - group_members_ids = get_group_followers(group_page_id) - group_amount = 0 - group_online = 0 - for profile in group_members_ids: - profile_last_seen = get_user_last_seen(str(profile)) - if profile_last_seen is not None: - group_amount += 1 - profile_last_seen = approximate_time(profile_last_seen) - group_online += is_online(profile_last_seen) - if group_amount == 0: - return -1 - else: - percent_online = group_online / group_amount * 100 - return percent_online - - -print(online_proportion(group_id)) +import vk +import datetime +import requests +import sqlite3 as sql +import group_class as gc +import analyse_and_bot_functions as func +import time +import random +import math + +begin_file = "begin_task.txt" + +token = "65e6efa565e6efa565e6efa54f6593fb1f665e665e6efa53a5c6937a4636b3416a8bd92" +group_token = "17e681fbe171945431a04f1abc752d41ff888698288abf74124de4e782c67f36e76484601991870f56b7a" +analyse_group_id = 'memkn' +my_group_id = 'memkn_funclub' +my_number_group_id = 200698416 + +session1 = vk.AuthSession(access_token=token) +session2 = vk.AuthSession(access_token=group_token) +vk_api = vk.API(session1, v=5.92) +vk_api2 = vk.API(session2, v=5.92) + +month_length = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31] +days_of_the_week = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"] + +# starts working, gives default values to some variables + +some = vk_api2.groups.getLongPollServer(group_id=my_number_group_id) +current_ts = some['ts'] +server = some['server'] +key = some['key'] +change_server = datetime.datetime.now().replace(microsecond=0, second=0) + datetime.timedelta(minutes=30) +message = "" +run = 1 +count = 10000 +master_id = -1 +have_a_task = [] +# next_recommend = datetime.datetime.now() +# next_time = datetime.datetime.now() + +file = open(begin_file, "r") +task_from_the_previous_session = list(file.read().split('\n')) +for the_task in task_from_the_previous_session: + task = list(the_task.split()) + if len(task) > 0 and task[0] != '-1': + this_task = {} + gr_id = task[0] + group_object = vk_api2.groups.getById(group_id=gr_id, fields=["id"]) + gr_id = str(group_object[0]['id']) + usr_id = int(task[1]) + this_task['master'] = usr_id + rec_hr = int(task[2]) + this_task['group'] = gc.Group(gr_id, usr_id) + this_task['group'].recommend_hour = rec_hr + this_task['next_time'], this_task['next_recommend'] = this_task['group'].calculate_new_analyse_time() + next_time = this_task['next_time'] + hrs = datetime.datetime.now().hour + if hrs > rec_hr: + this_task['next_recommend'] = this_task['next_recommend'].replace(hour=rec_hr) + else: + this_task['next_recommend'] = this_task['next_recommend'].replace(hour=rec_hr) - datetime.timedelta(days=1) + have_a_task.append(this_task) +file.close() + +# the end of 'initialization' block + +while run: + # wait for new requests + message, current_user_id, current_ts = func.get_message(my_number_group_id, server, current_ts, key) + + # if it is time to change LongPollServer + if datetime.datetime.now() >= change_server: + some = vk_api2.groups.getLongPollServer(group_id=my_number_group_id) + current_ts = some['ts'] + server = some['server'] + key = some['key'] + change_server = change_server + datetime.timedelta(minutes=30) + + # chek if it is time to analyse again + if len(have_a_task) > 0 and datetime.datetime.now() >= next_time: + next_time += datetime.timedelta(minutes=15) + for task in have_a_task: + task['group'].work_and_print() + + # check if it is time to give recommendations + for task in have_a_task: + if len(have_a_task) > 0 and datetime.datetime.now() >= task['next_recommend']: + task['group'].recommendation_for_this_day_of_the_week() + if datetime.datetime.now().weekday() == 0: + task['group'].recommendation_for_this_week() + task['next_recommend'] += datetime.timedelta(days=1) + + code, return_message = func.process_input_message(message) + + if code == 3: + analyse_group_id = return_message + group_object = vk_api2.groups.getById(group_id=analyse_group_id, fields=["id"]) + analyse_group_id = str(group_object[0]['id']) + # this code means that user gave a correct task + if len(have_a_task) < 10 and func.find_the_task(analyse_group_id, current_user_id, have_a_task) == -1: + this_task = {} + # group initialising block + file = open(begin_file, "r") + commands = list(file.read().split('\n')) + file.close() + file = open(begin_file, "w") + for command in commands: + if len(command) > 0 and command[0] != '-': + file.write(command + '\n') + file.write(f"{analyse_group_id} {current_user_id} 0") + file.close() + this_task['group'] = gc.Group(analyse_group_id, current_user_id) + # group.fill_in_index_to_date() + this_task['master'] = current_user_id + # counting time when to start and when to give a new recommendation + this_task['next_time'], this_task['next_recommend'] = this_task['group'].calculate_new_analyse_time() + if len(have_a_task) == 0: + next_time = this_task['next_time'] + have_a_task.append(this_task) + elif len(have_a_task) == 10: + # in the case when the user wants to give a new task while bot is already working on the OTHER user's task. + func.cannot_receive_more_tasks(current_user_id) + else: + func.have_such_a_task_already(current_user_id) + elif code == 2: + # if the bot has received a secret password which switches it off + run = func.switch_off(current_user_id, have_a_task) + for x in have_a_task: + x['group'].del_table() + del x['group'] + file = open(begin_file, "w") + file.write("-1 0 0") + file.close() + elif code == 1: + # if the user WHO GAVE A TASK decided to cancel it with a 'stop' or 'Stop' command + group_object = vk_api2.groups.getById(group_id=return_message, fields=["id"]) + return_message = str(group_object[0]['id']) + task_number = func.find_the_task(return_message, current_user_id, have_a_task) + if task_number != -1: + have_a_task[task_number]['group'].del_table() + del have_a_task[task_number]['group'] + file = open(begin_file, "r") + commands = list(file.read().split('\n')) + file.close() + file = open(begin_file, "w") + for cmd_number in range(len(commands)): + if cmd_number != task_number: + file.write(commands[cmd_number] + '\n') + file.close() + func.cancel_the_task(have_a_task, task_number, current_user_id) + else: + func.no_such_a_task(current_user_id) + elif code == 4: + # greeting + func.say_hello(current_user_id) + elif code == -1: + # unknown message + func.instruction_message(current_user_id) + elif code == 5: + # if the group does not exist + func.incorrect_id(current_user_id) + elif code == 7: + # If the user needs today's best online percent and the time it happened + group_object = vk_api2.groups.getById(group_id=return_message, fields=["id"]) + return_message = str(group_object[0]['id']) + task_number = func.find_the_task(return_message, current_user_id, have_a_task) + if task_number != -1: + have_a_task[task_number]['group'].give_today_stats() + else: + func.no_such_a_task(current_user_id) + elif code == 8: + # If the user needs week's best online percent and the time it happened + group_object = vk_api2.groups.getById(group_id=return_message, fields=["id"]) + return_message = str(group_object[0]['id']) + task_number = func.find_the_task(return_message, current_user_id, have_a_task) + if task_number != -1: + have_a_task[task_number]['group'].give_this_week_stats() + else: + func.not_such_a_task(current_user_id) + elif code == 9: + func.send_big_instruction(current_user_id) + elif code == 10: + func.task_by_button(current_user_id) + elif code == 12: + group_id = return_message[6:].strip() + group_object = vk_api2.groups.getById(group_id=group_id, fields=["id"]) + group_id = str(group_object[0]['id']) + task_number = func.find_the_task(group_id, current_user_id, have_a_task) + if task_number != -1: + r_id = func.get_r_id() + have_a_task[task_number]['next_recommend'] = \ + have_a_task[task_number]['next_recommend'].replace(hour=int(return_message[1: 3])) + if datetime.datetime.now().hour <= int(return_message[1: 3]): + have_a_task[task_number]['next_recommend'] -= datetime.timedelta(days=1) + have_a_task[task_number]['group'].recommend_hour = int(return_message[1: 3]) + vk_api2.messages.send( + user_id=current_user_id, + message=f"Отчёты по группе {group_id} буду присылать в {return_message[1:3]}:00!", + random_id=r_id + ) + # group.recommend_hour = int(return_message[1: 3]) + func.change_recommend_time(begin_file, task_number, return_message) + else: + not func.no_such_a_task(current_user_id) + elif code == 13: + func.free_places(current_user_id, len(have_a_task)) + elif code == 14: + func.send_keyboard(current_user_id) + elif code == 15: + func.user_groups(current_user_id, have_a_task) + elif code == 16: + func.too_big_group(current_user_id) + elif code == 17: + for x in have_a_task: + if x['master'] == current_user_id: + x['group'].current_percents = int(return_message) + r_id = func.get_r_id() + vk_api2.messages.send(user_id=current_user_id, message="OK", random_id=r_id)