async def force_add_user(self, user_id, message=None): if not self.aa_options['is_set']: self.tg_bot_controller.tg_client.me_last_activity = datetime.now( ) + timedelta(minutes=-10) if not message: message = str(MainHelper().get_config_value( 'chat_bot', 'bot_aa_default_message')) self.reset_aa() self.reset_user_setup() self.aa_options = { 'is_set': True, 'from_mode': 4, 'from_user_ids': [], 'activate_after_minutes': 10.0, 'answer_after_minutes': 2.0, 'show_bot': True, 'allow_bot_chat': True, 'notify_entity_id': None, 'message': '' } self.aa_options['from_mode'] = 4 if user_id not in self.aa_options['from_user_ids']: self.aa_options['from_user_ids'].append(user_id) if user_id in self.aa_not_for_users: self.aa_not_for_users.remove(user_id) if user_id in self.aa_for_users: del self.aa_for_users[user_id] if message: self.aa_options['message'] = message await self.on_user_message_to_me(user_id, '---')
def do_start(self): print('Starting of bot') self.start(bot_token=MainHelper().get_config_value('tg_bot', 'token')) self.loop.run_until_complete(self.init_bot_entity()) self.add_event_handler(self.message_handler, event=events.NewMessage) self.add_event_handler(self.callback_handler, event=events.CallbackQuery)
async def bot_check_user_message(self, message_text, from_id, dialog_entity_id, dialog_entity_type): bot_check_message = message_text.replace(',', ' ') bot_check_message = self.adapt_command(bot_check_message) if self.is_active_for_user(dialog_entity_id, False) and bot_check_message.startswith(MainHelper().get_config_value('chat_bot', 'bot_ignore_prefix')): return False if self.is_active_for_user(dialog_entity_id, False) and bot_check_message.startswith(MainHelper().get_config_value('chat_bot', 'bot_end_prefix')): bot_message = bot_check_message.replace(MainHelper().get_config_value('chat_bot', 'bot_end_prefix'), '', 1).strip() if not bot_message: bot_message = MainHelper().get_config_value('chat_bot', 'bot_empty_goodbuy') print('Bot command:') self.tg_client.sprint('<<< ' + bot_message.replace('\n', ' \\n ')) await self.bot_command(bot_message, from_id, dialog_entity_id, dialog_entity_type) self.stop_chat_with_user(dialog_entity_id) return True elif self.is_active_for_user(dialog_entity_id, False) or ((self.tg_client.selected_user_activity == dialog_entity_id) and (bot_check_message.startswith(MainHelper().get_config_value('chat_bot', 'bot_start_prefix')))): if not self.is_active_for_user(dialog_entity_id, False): bot_message = bot_check_message.replace(MainHelper().get_config_value('chat_bot', 'bot_start_prefix'), '', 1).strip() else: bot_message = message_text.strip() if not bot_message: bot_message = MainHelper().get_config_value('chat_bot', 'bot_empty_greet') print('Bot command:') self.tg_client.sprint('<<< ' + message_text.replace('\n', ' \\n ')) await self.bot_command(bot_message, from_id, dialog_entity_id, dialog_entity_type) return True return False
def chatbot_message_response(self, message_text, user_id): try: weather_words = str(MainHelper().get_config_value('chat_bot', 'bot_weather_keywords')) weather_words = weather_words.split('|') message_text_words = re.findall(r'\w+', message_text) intersect_words = set(message_text_words).intersection(weather_words) is_weather = (len(intersect_words) > 0) and MainHelper().get_config_value('chat_bot', 'bot_weather_owm_api_key') if not is_weather: api = apiai.ApiAI(str(MainHelper().get_config_value('chat_bot', 'bot_client_token')), str(MainHelper().get_config_value('chat_bot', 'bot_session_name')) + '_' + str(user_id)) else: api = apiai.ApiAI(str(MainHelper().get_config_value('chat_bot', 'bot_client_token_weather')), str(MainHelper().get_config_value('chat_bot', 'bot_session_name_weather')) + '_' + str(user_id)) request = api.text_request() request.lang = 'ru' request.query = message_text response_json = json.loads(request.getresponse().read().decode('utf-8')) if is_weather: city = None if response_json['result']['parameters'] and response_json['result']['parameters']['address'] and response_json['result']['parameters']['address']['city']: city = response_json['result']['parameters']['address']['city'] if not city: city = str(MainHelper().get_config_value('chat_bot', 'bot_weather_city_default')) owm = pyowm.OWM(str(MainHelper().get_config_value('chat_bot', 'bot_weather_owm_api_key')), language="ru", use_ssl=True) observation = owm.weather_at_place(city) w = observation.get_weather() status = w.get_detailed_status() + ' (облачность '+str(w.get_clouds())+'%)' pressure_res = w.get_pressure() pressure = str(pressure_res.get('press')) + ' мм.рт.ст.' visibility_distance = str(w.get_visibility_distance()) + ' м.' wind_res = w.get_wind() wind_speed = str(wind_res.get('speed')) + ' м/с' humidity = str(w.get_humidity()) + '%' celsius_result = w.get_temperature('celsius') temp_min_celsius = str(celsius_result.get('temp_min')) + '°C' temp_max_celsius = str(celsius_result.get('temp_max')) + '°C' response = "Текущая погода в г. " + city + ": \n" + \ status + "\n" + \ "Температура:\n Макс: " + temp_max_celsius + "\n Мин: " + temp_min_celsius + "\n"+\ "Влажность: " + humidity + "\n"+\ "Давление: " + pressure + "\n"+\ "Видимость: " + visibility_distance + "\n"+\ "Ветер: " + wind_speed + "\n" else: response = response_json['result']['fulfillment']['speech'] if response: return response except: traceback.print_exc() return str(MainHelper().get_config_value('chat_bot', 'bot_error_message')) return str(MainHelper().get_config_value('chat_bot', 'bot_cant_understand_message'))
async def send_activity_message(self, for_id, send_to_id, date_activity=None, result_only_time=False, a_type="plot_img", img_caption="График активности [user]"): for_name = await self.tg_bot_controller.tg_client.get_entity_name( for_id) status_results = await self.tg_bot_controller.tg_client.status_controller.print_user_activity( for_id, for_name, a_type, date_activity, result_only_time) status_results = status_results.strip().splitlines() last_str = '' if a_type == "plot_img": last_str = str(status_results.pop()) if last_str and last_str.startswith(MainHelper( ).get_config_root_folder_value('main', 'files_folder') + "/"): u_link = await self.user_link(for_id, for_name) await self.send_file_to_user(send_to_id, last_str, img_caption.replace('[user]', u_link), True) else: full_results = "\n".join(status_results) if (len(full_results) + 8) >= 4096: status_results.reverse() buff_len = 1 while buff_len > 0: buff = [] buff_len = 0 while (len(status_results) > 0) and (buff_len + len( status_results[len(status_results) - 1]) + 8) < 4096: last_s = status_results.pop() buff.append(last_s) buff_len = buff_len + len(last_s) + 1 if buff_len > 0: await self.send_message_to_user( send_to_id, '```\n' + ("\n".join(buff)) + '\n```') if len(status_results) > 0: await asyncio.sleep(0.75) else: await self.send_message_to_user( send_to_id, '```\n' + full_results + '\n```')
async def on_timer(self): if not self.branch_parent.has_insta_lib: return if self.last_stories_check_time and ( datetime.now() - self.last_stories_check_time ).total_seconds() < MainHelper().get_config_int_value( 'instagram', 'check_story_delay_seconds'): return self.last_stories_check_time = datetime.now() ustories = self.tg_bot_controller.tg_client.entity_controller.get_entity_db_option_list( 'stories_accounts') if ustories and (len(ustories) > 0): ustories = str("\n".join(ustories)).splitlines() ustories = list(dict.fromkeys(ustories)) else: return self.branch_parent.do_login_if_need() if not self.branch_parent.api: print('API-клиент не был инициализирован!') return insta_id_cache = self.tg_bot_controller.tg_client.entity_controller.get_entity_db_option( 0, 'insta_user_ids', True, {}) for username in ustories: if username in insta_id_cache: user_id = insta_id_cache[username] else: info = await self.branch_parent.get_user_info_by_username( None, username, False) if not info: continue user_id = int(info['user']['pk']) insta_id_cache[username] = user_id self.save_user_stories(user_id, username) self.download_stories() self.tg_bot_controller.tg_client.entity_controller.set_entity_db_option( 0, 'insta_user_ids', insta_id_cache, True)
async def send_version_message_to_all_bot_users(self): sent_count = 0 try: version_messages = self.get_version_messages() new_ver = MainHelper().get_config_float_value( 'main', 'actual_version') new_ver_title = MainHelper().get_config_value( 'main', 'new_version_title') new_ver_help = MainHelper().get_config_value( 'main', 'new_version_help') result_title = new_ver_title.replace( '[actual_version]', "{0:0.2f}".format(new_ver)).replace( '[bot_name]', MainHelper().get_config_value('tg_bot', 'bot_username')) result_title = result_title + '\n' + new_ver_help chats = self.tg_client.entity_controller.get_all_bot_users_chats() if chats and len(chats) > 0: for chat in chats: user_last_version = self.tg_client.entity_controller.get_user_bot_last_version( chat.user_id) if not user_last_version: user_last_version = 0.0 user_last_version = float(user_last_version) result_user_message = [] for version_message in version_messages: if version_message['version'] > user_last_version: version_message_text = 'Список изменений версии {0:0.2f}:\n'.format( version_message['version']) version_message_text = version_message_text + version_message[ 'message'] result_user_message.append(version_message_text) if len(result_user_message) > 0: result_user_message = result_title + '\n--------\n' + ( "\n--------\n".join(result_user_message)).strip() self.tg_client.entity_controller.save_user_bot_last_version( chat.user_id, new_ver) await self.send_message(chat, result_user_message) sent_count = sent_count + 1 except: traceback.print_exc() return sent_count
async def on_bot_message(self, message, from_id): if (self.setup_step == 0) or (self.setup_user_id != from_id): return await super().on_bot_message(message, from_id) if not self.is_in_current_branch(from_id): return False message = str(message).strip() if self.setup_step == 1: num_msg = int(message) if (num_msg >= 0) and (num_msg <= 4): self.aa_options['from_mode'] = num_msg self.aa_options['from_user_ids'] = [] if num_msg == 4: await self.next_setup_step(2) else: await self.next_setup_step(3) else: await self.next_setup_step(1) elif self.setup_step == 2: self.aa_options['from_user_ids'] = [] logins = message.lower().split(',') for login_s in logins: login = str(login_s).strip() entity = None try: entity = await self.tg_bot_controller.tg_client.get_entity( login) except ValueError: try: entity = await self.tg_bot_controller.tg_client.get_entity( PeerUser(int(login))) except: pass if entity and (type(entity) == User): if entity.id not in self.aa_options['from_user_ids']: self.aa_options['from_user_ids'].append(entity.id) else: await self.send_message_to_user(from_id, 'Сущность не опознана - ' + str(login), do_set_next=False) if len(self.aa_options['from_user_ids']) > 0: await self.next_setup_step(3) else: await self.next_setup_step(2) elif self.setup_step == 3: num_msg = float(message) if num_msg < 0.01: num_msg = 0.0 elif num_msg > 999999999999: num_msg = 999999999999 self.aa_options['activate_after_minutes'] = num_msg await self.next_setup_step() elif self.setup_step == 4: num_msg = float(message) if num_msg < 0.01: num_msg = 0.0 elif num_msg > 999999999999: num_msg = 999999999999 self.aa_options['answer_after_minutes'] = num_msg await self.next_setup_step() elif self.setup_step == 5: message = message.lower() self.aa_options['show_bot'] = message in self.yes_variants await self.next_setup_step() elif self.setup_step == 6: message = message.lower() self.aa_options['allow_bot_chat'] = message in self.yes_variants await self.next_setup_step() elif self.setup_step == 7: if not message or (message in self.no_variants): message = str(MainHelper().get_config_value( 'chat_bot', 'bot_aa_default_message')) elif re.match(r"[0-9]{1,2}:[0-9]{1,2}", message): d_msg = message message = str(MainHelper().get_config_value( 'chat_bot', 'bot_aa_default_message_time')) message = message.replace('[datetime]', d_msg) self.aa_options['message'] = message await self.next_setup_step() elif self.setup_step == 200: self.aa_options['message'] = str(MainHelper().get_config_value( 'chat_bot', 'bot_aa_default_message_time')) self.aa_options['message'] = self.aa_options['message'].replace( '[datetime]', message) self.reset_user_setup() await self.send_message_to_user(from_id, 'Сообщение изменено!') return True
async def next_setup_step(self, next_step=None, from_user_id=None): if not from_user_id: from_user_id = self.setup_user_id if next_step is not None: self.setup_step = next_step else: self.setup_step = self.setup_step + 1 if self.setup_step == 1: msg = '**Шаг 1**\n\n' msg = msg + 'Для сообщений от кого должен срабатывать автоответчик? (уровень доступа)\n\n' msg = msg + ' 0 - ото всех\n' msg = msg + ' 1 - от моих контактов\n' msg = msg + ' 2 - от моих взаимных контактов\n' msg = msg + ' 3 - от выбранных в общем списке пользователей\n' msg = msg + ' 4 - указать логины/ID\n' await self.send_message_to_user(from_user_id, msg.strip(), buttons=self.cmd_to_btns( { '0': '0', '1': '1', '2': '2', '3': '3', '4': 'указать логины', }, 4), do_set_next=False) elif self.setup_step == 2: msg = '**Шаг 1.1**\n\n' msg = msg + 'Перечислите логины/ID через запятую' await self.send_message_to_user(from_user_id, msg.strip(), do_set_next=False) elif self.setup_step == 3: msg = '**Шаг 2**\n\n' msg = msg + 'Сколько минут ' + self.tg_bot_controller.tg_client.me_user_name + ' должен быть не в сети для срабатывания автоответчика?' await self.send_message_to_user(from_user_id, msg.strip(), buttons=self.cmd_to_btns( { '1': '1 мин', '5': '5 мин', '10': '10 мин', '30': '30 мин', '60': '1 ч', '120': '2 ч', '360': '3 ч', '480': '4 ч', '720': '6 ч', }, 3), do_set_next=False) elif self.setup_step == 4: msg = '**Шаг 3**\n\n' msg = msg + 'Через сколько минут после сообщения автоответчик сработает?' await self.send_message_to_user(from_user_id, msg.strip(), buttons=self.cmd_to_btns( { '0': 'сразу же', '0.5': '0.5 мин', '1': '1 мин', '2': '2 мин', '5': '5 мин', '10': '10 мин', '20': '20 мин', '30': '30 мин', '60': '1 ч', }, 3), do_set_next=False) elif self.setup_step == 5: msg = '**Шаг 4**\n\n' msg = msg + 'Показывать, что отвечает бот?' await self.send_message_to_user(from_user_id, msg.strip(), buttons=self.cmd_to_btns( { '0': 'нет', '1': 'да', }, 2), do_set_next=False) elif self.setup_step == 6: msg = '**Шаг 5**\n\n' msg = msg + 'После сообщения позволить боту продолжить диалог?' await self.send_message_to_user(from_user_id, msg.strip(), buttons=self.cmd_to_btns( { '0': 'нет', '1': 'да', }, 2), do_set_next=False) elif self.setup_step == 7: msg = '**Шаг 6**\n\n' msg = msg + 'Ну и наконец, введите текст сообщения.\n' msg = msg + 'Тире или 0 - использовать стандартное сообщение.\n' msg = msg + 'Время в формате 21:55 - использовать стандартное с уведомлением о времени прибытия.\n' msg = msg + 'Кроме того в тексте можно использовать следующие коды:\n' msg = msg + '[username] - подстановка имени пользователя для которого настраивается автоответчик.\n' msg = msg + '[statistics] - статистика активности и прогноз времени прибытия.\n' await self.send_message_to_user( from_user_id, msg.strip(), buttons=self.cmd_to_btns({ '0': 'стандартное сообщение', }, 2), do_set_next=False) elif self.setup_step == 8: msg = '**Настройка завершена!!!**\n\n' self.aa_options['notify_entity_id'] = from_user_id self.reset_aa() self.reset_user_setup() self.aa_options['is_set'] = True await self.send_message_to_user(from_user_id, msg.strip()) elif self.setup_step == 200: msg = '**Настройка даты/времени прибытия**\n\n' msg = msg + 'оно будет указано ботом в начальном сообщении вида:\n' msg = msg + '```' + MainHelper().get_config_value( 'chat_bot', 'bot_aa_default_message_time') + '```\n' msg = msg + 'Введите дату/время' await self.send_message_to_user(from_user_id, msg.strip(), do_set_next=False)
async def init_bot_entity(self): if not self.bot_entity: self.bot_entity = await self.get_entity( MainHelper().get_config_value('tg_bot', 'bot_username')) self.bot_entity_id = self.bot_entity.id print('Bot entity ID: {}'.format(self.bot_entity_id))
async def message_handler(self, event): if type(event.original_update) != UpdateNewMessage: return try: await self.init_bot_entity() data = event.original_update if data.message.from_id == self.bot_entity_id: return MainHelper().play_notify_sound('notify_when_my_bot_message') if data.message.id and data.message.from_id and ( data.message.from_id != self.tg_client.me_user_id): msg_entity_name = await self.tg_client.get_entity_name( data.message.from_id, 'User') if msg_entity_name: print( StatusController.datetime_to_str(datetime.now()) + ' Message to my bot from "' + msg_entity_name + '"') print('<<< ' + str(data.message.message)) t_date = StatusController.tg_datetime_to_local_datetime( data.message.date) self.tg_client.add_message_to_db(self.bot_entity_id, 'Bot', data.message.from_id, self.bot_entity_id, data.message.id, data.message.message, t_date, 0) elif data.message.id and data.message.from_id and ( data.message.from_id == self.tg_client.me_user_id): t_date = StatusController.tg_datetime_to_local_datetime( data.message.date) self.tg_client.add_message_to_db(self.bot_entity_id, 'Bot', data.message.from_id, self.bot_entity_id, data.message.id, data.message.message, t_date, 0) elif not data.message.id and data.message.from_id: t_date = StatusController.now_local_datetime() self.tg_client.add_message_to_db(self.bot_entity_id, 'Bot', data.message.from_id, self.bot_entity_id, None, data.message.message, t_date, 0) msg_entity_name = await self.tg_client.get_entity_name( data.message.from_id, 'User') if msg_entity_name: print( StatusController.datetime_to_str(datetime.now()) + ' Command to my bot from "' + msg_entity_name + '"') print('<<< ' + str(data.message.message)) forward_data = None if data.message.id: bot_chat = await event.get_input_chat() if data.message.fwd_from: forward_data = { 'from_id': data.message.fwd_from.from_id, 'date_from': data.message.fwd_from.date } else: try: bot_chat = await self.get_input_entity( PeerUser(data.message.from_id)) except: traceback.print_exc() bot_chat = None if not bot_chat: bot_chat = self.tg_client.entity_controller.get_user_bot_chat( data.message.from_id) if not bot_chat: print("Can't get chat!") return try: ee_name = await self.tg_client.get_entity_name( bot_chat.user_id, 'User') except: ee_name = str(bot_chat.user_id) self.tg_client.entity_controller.add_entity_db_name( bot_chat.user_id, 'User', ee_name) self.tg_client.entity_controller.save_user_bot_chat(bot_chat) if data.message.message == '/start': self.tg_client.entity_controller.save_user_bot_last_version( bot_chat.user_id, MainHelper().get_config_float_value( 'main', 'actual_version')) if data.message.id: self.tg_client.bot_controller.set_message_for_user( data.message.from_id, data.message.id, False) await self.tg_client.bot_controller.bot_command( data.message.message, data.message.from_id, self.bot_entity_id, 'Bot', forward_data) except: traceback.print_exc()
def __init__(self, tg_client): super().__init__(self, None, None) self.tg_client = tg_client self.entity_controller = tg_client.entity_controller self.bot_answer_format_text = str(MainHelper().get_config_value('chat_bot', 'bot_answer_format')) self.users = {} self.right_levels = { '0': 'all', '1': 'contacts', '2': 'mutual contacts', '3': 'pre selected', '4': 'only me' } self.max_commands = 5 self.commands.update({ '/start': { 'cmd': self.cmd_start, 'places': ['bot'], 'rights_level': 0, 'desc': None }, '/exit': { 'cmd': self.cmd_exit, 'places': ['dialog'], 'rights_level': 0, 'desc': 'конец диалога' }, '/insta_check': { 'class': InstaBranch, 'places': ['bot'], 'bot_button': { 'title': 'Инстаграм', 'position': [1, 0], }, 'rights_level': 0, 'desc': 'управление скриптом для работы с инстаграмом.' }, '/auto': { 'class': AutoAnswers, 'places': ['bot'], 'bot_button': { 'title': 'Автоответчик', 'position': [2, 0], }, 'rights_level': 3, 'desc': 'автоответчик - начальная настройка или изменение настроек.', }, '/tools': { 'class': ToolsBranch, 'places': ['bot'], 'bot_button': { 'title': 'Утилиты', 'position': [3, 0], }, 'rights_level': 1, 'desc': 'всякие разные утилиты.' }, '/user_dialogue_info': { 'class': DialogueBranch, 'places': ['bot', 'dialog'], 'bot_button': { 'title': 'Диалоги', 'position': [4, 0], }, 'rights_level': 2, 'desc': 'статистика диалогов с пользователем [me_user].' }, '/user_activity_info': { 'class': ActivityBranch, 'places': ['bot', 'dialog'], 'bot_button': { 'title': 'Активность пользователей', 'position': [4, 1], }, 'rights_level': 2, 'desc': 'статистика активности пользователей - графики и листинги.' }, }) self.on_init_finish()
def show_plot(self, plot_data, days_count, result_only_time, as_img=False): # https://plot.ly/python/renderers/ if (days_count < 2) or result_only_time: fig = make_subplots(rows=2, cols=4, specs=[ [{"colspan": 2}, None, {"colspan": 2}, None], [None, {"colspan": 2}, None, None] ]) row2 = 1 col2 = 3 row3 = 2 col3 = 2 else: fig = make_subplots(rows=3, cols=6, specs=[ [{"colspan": 6}, None, None, None, None, None], [{"colspan": 3}, None, None, {"colspan": 3}, None, None], [{"colspan": 2}, None, {"colspan": 2}, None, {"colspan": 2}, None] ]) row2 = 2 col2 = 1 row3 = 2 col3 = 4 fig.update_layout( title_text=plot_data['title'] ) fig.add_trace( go.Bar(x=plot_data['x_full'], y=plot_data['y_time'], name="Activity time (minutes)"), row=1, col=1 ) fig.add_trace( go.Bar(x=plot_data['x_full'], y=plot_data['y_intervals'], name="Sessions count"), row=row2, col=col2 ) fig.add_trace( go.Bar(x=plot_data['x_full'], y=plot_data['y_interval_time'], name="Avg session time (minutes)"), row=row3, col=col3 ) fig.update_yaxes(title_text='Activity time', row=1, col=1) fig.update_yaxes(title_text='Sessions count', row=row2, col=col2) fig.update_yaxes(title_text='Avg session time', row=row3, col=col3) if (days_count >= 2) and not result_only_time: fig.add_trace( go.Bar(x=plot_data['x_days'], y=plot_data['y_days_time'], name="Days activity time (minutes)"), row=3, col=1 ) fig.update_yaxes(title_text='Activity time', row=3, col=1) fig.add_trace( go.Bar(x=plot_data['x_days'], y=plot_data['y_days_intervals'], name="Days sessions count"), row=3, col=3 ) fig.update_yaxes(title_text='Sessions count', row=3, col=3) fig.add_trace( go.Bar(x=plot_data['x_days'], y=plot_data['y_days_interval_time'], name="Days avg session time (minutes)"), row=3, col=5 ) fig.update_yaxes(title_text='Avg session time', row=3, col=5) # fig.update_yaxes(type="log") if as_img: if MainHelper().get_config_value('main', 'orca_path'): try: plotly.io.orca.config.executable = MainHelper().get_config_value('main', 'orca_path') fname = str(datetime.now().timestamp()) + '_' + hashlib.md5(plot_data['title'].encode('utf-8')).hexdigest() fname = MainHelper().get_config_root_folder_value('main', 'files_folder') + "/" + fname + ".png" fig.write_image(fname, format="png", width=1920, height=1080) return fname except: return 'Какая-то ошибка. Скорее всего некорректно настроен orca или не хватает прав на запись файла!' else: return 'Требуется сначала настроить orca!' else: fig.show() return ''
def __init__(self, tg_bot_controller, branch_parent, branch_code=None): super().__init__(tg_bot_controller, branch_parent, branch_code) self.use_timer = False self.last_stories_check_time = None self.api = None self.has_insta_lib = False self.insta_username = None self.insta_password = None try: from libs.instagram_private_api import Client print('Instagram lib was found!') self.has_insta_lib = True self.insta_username = MainHelper().get_config_value( 'instagram', 'username') self.insta_password = MainHelper().get_config_value( 'instagram', 'password') self.cache_file = MainHelper().get_config_root_file_value( 'instagram', 'cache_file') except ImportError: pass self.max_commands = 9 self.commands.update({ '/insta_check_followers': { 'cmd': self.cmd_check_followers, 'condition': self.can_use_branch, 'bot_button': { 'title': 'Сверка подписчиков', 'position': [0, 0], }, 'places': ['bot'], 'rights_level': 0, 'desc': 'сверить списки подписчиков и подписок чтобы найти пользователей, не подписанных на вас из тех, на которых вы подписаны' }, '/insta_check_followings': { 'cmd': self.cmd_check_followings, 'condition': self.can_use_branch, 'bot_button': { 'title': 'Сверка подписок', 'position': [0, 1], }, 'places': ['bot'], 'rights_level': 0, 'desc': 'сверить списки подписчиков и подписок чтобы найти пользователей, на которых вы не подписаны из тех, что подписанных на вас' }, '/insta_user_info': { 'cmd': self.cmd_user_info, 'condition': self.can_use_branch, 'bot_button': { 'title': 'Информация', 'position': [1, 0], }, 'places': ['bot'], 'rights_level': 0, 'desc': 'информация о пользователе' }, '/insta_user_locations': { 'cmd': self.cmd_user_locations, 'condition': self.can_use_branch, 'bot_button': { 'title': 'Локации', 'position': [1, 1], }, 'places': ['bot'], 'rights_level': 0, 'desc': 'все локации, отмеченные пользователем' }, '/insta_user_active_commenters': { 'cmd': self.cmd_user_active_commenters, 'condition': self.can_use_branch, 'bot_button': { 'title': 'Активные комментаторы', 'position': [2, 0], }, 'places': ['bot'], 'rights_level': 0, 'desc': 'активные в комментах пользователи' }, '/insta_user_active_likers': { 'cmd': self.cmd_user_active_likers, 'condition': self.can_use_branch, 'bot_button': { 'title': 'Активные лайкеры', 'position': [2, 1], }, 'places': ['bot'], 'rights_level': 0, 'desc': 'активно ставящие лайки пользователи' }, '/insta_stories': { 'class': InstaStoriesBranch, 'condition': self.can_use_branch, 'bot_button': { 'title': 'Источники историй', 'position': [3, 0], }, 'places': ['bot'], 'rights_level': 3, 'desc': 'управление списками пользователей - источников stories. У этих пользователей будет проводиться регулярное выкачивание stories' }, '/insta_set_username': { 'cmd': self.cmd_set_username, 'condition': self.can_set_username, 'bot_button': { 'title': 'Указать имя', 'position': [3, 1], }, 'places': ['bot'], 'rights_level': 0, 'desc': 'указать имя пользователя (чтобы каждый раз не спрашивать)' }, '/insta_reset_username': { 'cmd': self.cmd_reset_username, 'condition': self.can_reset_username, 'bot_button': { 'title': 'Сбросить имя', 'position': [3, 2], }, 'places': ['bot'], 'rights_level': 0, 'desc': 'сбросить имя пользователя (чтобы каждый раз спрашивать)' }, }) self.on_init_finish()
def save_user_stories(self, user_id, username): try: response = self.branch_parent.api.user_reel_media(user_id) except: print(username + ': Stories read error!') traceback.print_exc() return story_records = self.tg_bot_controller.tg_client.entity_controller.get_entity_db_option( 0, 'insta_story_entries', True, {}) for st_id in list(story_records.keys()): try: n_time = StatusController.now_local_datetime() d_time = StatusController.timestamp_to_local_datetime( int(story_records[st_id]['taken_at'])) if (not d_time) or (n_time - d_time).total_seconds() > ( 2 * 24 * 60 * 60): del story_records[st_id] except: del story_records[st_id] dups = 0 for item in response['items']: id = item['id'] try: url = item['video_versions'][0]['url'] except KeyError: url = item['image_versions2']['candidates'][0]['url'] taken_at = item['taken_at'] location = '' if 'story_locations' in item: location_items = item['story_locations'] if location_items and len(location_items) > 0: location_item = location_items[0] if location_item and ('location' in location_item ) and location_item['location']: location_item = location_item['location'] location = location_item['name'] if ('address' in location_item) and location_item['address']: location = location + ', ' + str( location_item['address']) if ('city' in location_item) and location_item['city']: location = location + ', ' + str( location_item['city']) if ('lat' in location_item) and ('lng' in location_item): location = location + ', ' + str( location_item['lat']) + ',' + str( location_item['lng']) story_fname = self.get_story_file_name(taken_at, location) viewers_info = {} viewers_ids = [] if 'viewers' in item: viewers = item['viewers'] for viewer in viewers: viewers_info[str(viewer['pk'])] = { 'date': datetime.now(), 'username': viewer['username'], 'full_name': viewer['full_name'], 'pk': viewer['pk'] } viewers_ids.append(viewer['pk']) viewers_ids.sort() viewers = json.dumps(viewers_ids) else: viewers = '[]' if id not in story_records: entry = { "id": id, "url": url, "userid": user_id, "username": username, "taken_at": taken_at, "filename": "", "viewers": viewers, "location": location } story_records[id] = entry old_viewers = '[]' print('New story for user ' + str(username) + ' was found: ' + story_fname) MainHelper().play_notify_sound('notify_when_new_insta_story') else: dups = dups + 1 old_viewers = story_records[id]['viewers'] if old_viewers != viewers: if viewers != '[]': MainHelper().play_notify_sound( 'notify_when_new_insta_view') old_viewers = json.loads(old_viewers) append_strs = [] for new_viewer in viewers_ids: if new_viewer not in old_viewers: new_data = viewers_info[str(new_viewer)] new_str = '"' + str(new_data['pk']) + '";"' + \ new_data['full_name'] + '";"' + str(new_data['date'].strftime('%Y-%m-%d %H:%M:%S')) + \ '";"https://www.instagram.com/' + new_data['username'] + '"' append_strs.append(new_str) print('!!! User ' + new_data['full_name'] + ' watched your story ' + story_fname) if len(append_strs) > 0: stories_folder = MainHelper().get_config_root_folder_value( 'instagram', 'stories_folder') if not os.path.exists(stories_folder): os.makedirs(stories_folder) file_path = stories_folder + "/" + str(username) if not os.path.exists(file_path): os.makedirs(file_path) file_name = story_fname + ".csv" with open(file_path + "/" + file_name, 'a') as file: if len(old_viewers) == 0: file.write('"ID";"Full name";"Date";"User link"' + "\n") for line in append_strs: file.write(line + "\n") file.close() if id in story_records: story_records[id]['viewers'] = viewers if dups > 0: if dups > 1: stories_str = "stories" else: stories_str = "story" print(username + ": " + str(dups) + " old " + stories_str + " was skipped.") if (not response['items']) or (len(response['items']) == 0): print(username + ": Stories was not found.") self.tg_bot_controller.tg_client.entity_controller.set_entity_db_option( 0, 'insta_story_entries', story_records, True)
def download_stories(self): stories_folder = MainHelper().get_config_root_folder_value( 'instagram', 'stories_folder') to_delete, to_update = [], [] if not os.path.exists(stories_folder): os.makedirs(stories_folder) try: c_session = self.get_session() except: c_session = None print('!!! Error: Cant open session') traceback.print_exc() story_records = self.tg_bot_controller.tg_client.entity_controller.get_entity_db_option( 0, 'insta_story_entries', True, {}) for row in story_records.values(): if row['filename'] and len(row['filename']) > 0: continue r = c_session.get(row['url']) if r.status_code == 404: print("Deleting old story DB record: " + str(row['id'])) to_delete.append(row['id']) elif r.status_code % 200 < 100: if len(to_update) == 0: print() print("Downloading new story files:") file_name = self.get_story_file_name(row['taken_at'], row['location']) if r.headers["Content-Type"] == "video/mp4" or r.headers[ "Content-Type"] == "text/plain": filename = str(row['username']) + "/" + file_name + ".mp4" elif r.headers["Content-Type"] == "image/jpeg": filename = str(row['username']) + "/" + file_name + ".jpg" else: filename = str( row['username']) + "/" + file_name + ".unknown" print("WARNING: couldn't identify MIME type for URL " + row['url']) if not os.path.exists(stories_folder + "/" + str(row['username'])): os.makedirs(stories_folder + "/" + str(row['username'])) with open(stories_folder + "/" + filename, 'wb') as f: for chunk in r.iter_content(chunk_size=1024): if chunk: f.write(chunk) to_update.append([row['id'], filename]) print(filename) for item in to_delete: if item in story_records: del story_records[item] for item in to_update: if item[0] in story_records: story_records[item[0]]['filename'] = item[1] self.tg_bot_controller.tg_client.entity_controller.set_entity_db_option( 0, 'insta_story_entries', story_records, True)