def update_model_image(self): """ Updates self.image :raise ModelOffline if self.status is 'offline' :raise ModelAway if self.status is 'away' :raise ModelPrivate if self.status is 'private' or 'hidden' :raise ModelPassword if self.status is 'password' :raise ModelDeleted if self.status is 'deleted' :raise ModelBanned if self.status is 'banned' :raise ModelGeoblocked if self.status is 'geoblocked' :raise ModelCanceled if self.status is 'canceled' :raise ModelNotViewable if any other error happens """ if self.online and self.status not in { "away", "private", "hidden", "password" }: attempt_count = 0 for attempt in range(5): try: data = requests.get( f'https://roomimg.stream.highwebmedia.com/ri/{self.username}.jpg' ).content bio_data = io.BytesIO(data) self.model_image = bio_data except Exception as e: Utils.handle_exception(e) attempt_count += 1 logging.info(self.username + " has failed to obtain image on attempt " + str(attempt)) time.sleep(1) # sleep and retry else: break if attempt_count == 5: logging.info(self.username + " has failed to obtain image after all attempts") raise ConnectionError elif self.status == "offline": raise Exceptions.ModelOffline elif self.status == "away": raise Exceptions.ModelAway elif self.status in {"private", "hidden"}: raise Exceptions.ModelPrivate elif self.status == "password": raise Exceptions.ModelPassword elif self.status == "deleted": raise Exceptions.ModelDeleted elif self.status == "banned": raise Exceptions.ModelBanned elif self.status == "geoblocked": raise Exceptions.ModelGeoblocked elif self.status == "canceled": raise Exceptions.ModelCanceled else: raise Exceptions.ModelNotViewable
def send_image(chatid: str, image, bot: updater.bot, html: bool = False, markup=None, caption=None) -> None: """ Sends an image to a telegram user and sends "sending image" action :param chatid: The chatid of the user who will receive the message :param image: The image to send :param bot: telegram bot instance :param html: Enable html markdown parsing in the message :param markup: The reply_markup to use when sending the message """ notification = not Preferences.get_user_notifications_sound_preference( chatid) # the setting is opposite of preference try: bot.send_chat_action(chatid, action="upload_photo") if html and markup != None and caption != None: bot.send_photo(chat_id=chatid, photo=image, parse_mode=telegram.ParseMode.HTML, reply_markup=markup, disable_notification=notification, caption=caption) elif html and markup != None: bot.send_photo(chat_id=chatid, photo=image, parse_mode=telegram.ParseMode.HTML, reply_markup=markup, disable_notification=notification) elif markup != None and caption != None: bot.send_photo(chat_id=chatid, photo=image, reply_markup=markup, disable_notification=notification, caption=caption) elif html and caption != None: bot.send_photo(chat_id=chatid, photo=image, parse_mode=telegram.ParseMode.HTML, disable_notification=notification, caption=caption) elif html: bot.send_photo(chat_id=chatid, photo=image, parse_mode=telegram.ParseMode.HTML, disable_notification=notification) elif markup != None: bot.send_photo(chat_id=chatid, photo=image, reply_markup=markup, disable_notification=notification) elif caption != None: bot.send_photo(chat_id=chatid, photo=image, disable_notification=notification, caption=caption) else: bot.send_photo(chat_id=chatid, photo=image, disable_notification=notification) except Unauthorized: # user blocked the bot if auto_remove == True: logging.info(f"{chatid} blocked the bot, he's been removed from the database") Utils.exec_query(f"DELETE FROM CHATURBATE WHERE CHAT_ID='{chatid}'") Preferences.remove_user_from_preferences(chatid) except Exception as e: Utils.handle_exception(e)
def send_message(chatid: str, messaggio: str, bot: updater.bot, html: bool = False, markup=None) -> None: """ Sends a message to a telegram user and sends "typing" action :param chatid: The chatid of the user who will receive the message :param messaggio: The message who the user will receive :param bot: telegram bot instance :param html: Enable html markdown parsing in the message :param markup: The reply_markup to use when sending the message """ disable_webpage_preview = not Preferences.get_user_link_preview_preference( chatid) # the setting is opposite of preference notification = not Preferences.get_user_notifications_sound_preference( chatid) # the setting is opposite of preference try: bot.send_chat_action(chat_id=chatid, action="typing") if html and markup != None: bot.send_message(chat_id=chatid, text=messaggio, parse_mode=telegram.ParseMode.HTML, disable_web_page_preview=disable_webpage_preview, reply_markup=markup, disable_notification=notification) elif html: bot.send_message(chat_id=chatid, text=messaggio, parse_mode=telegram.ParseMode.HTML, disable_web_page_preview=disable_webpage_preview, disable_notification=notification) elif markup != None: bot.send_message(chat_id=chatid, text=messaggio, disable_web_page_preview=disable_webpage_preview, reply_markup=markup, disable_notification=notification) else: bot.send_message(chat_id=chatid, text=messaggio, disable_web_page_preview=disable_webpage_preview, disable_notification=notification) except Unauthorized: # user blocked the bot if auto_remove == True: logging.info(f"{chatid} blocked the bot, he's been removed from the database") Utils.exec_query(f"DELETE FROM CHATURBATE WHERE CHAT_ID='{chatid}'") Preferences.remove_user_from_preferences(chatid) except Exception as e: Utils.handle_exception(e)
def update_status() -> None: username_list = [] chat_and_online_dict = {} # create a dictionary with usernames and online using distinct username_list = Utils.alchemy_instance.session.query( ChaturbateUser.username).distinct().all() # obtain chatid for username in username_list: results: List[ ChaturbateUser] = Utils.alchemy_instance.session.query( ChaturbateUser).filter_by(username=username).all() chat_and_online_dict[ username] = results # assign (chatid,online) to every model # Threaded function for queue processing. def crawl(q, model_instances_dict): while not q.empty(): username = Utils.sanitize_username(q.get()[1].username) model_instance = Model(username, autoupdate=False) model_instance.update_model_status() try: model_instance.update_model_image() except Exception: model_instance.model_image = None # set to None just to be secure Todo: this may be extra model_instances_dict[username] = model_instance # signal to the queue that task has been processed q.task_done() return True q = Queue(maxsize=0) # Populating Queue with tasks model_instances_dict = {} # load up the queue with the username_list to fetch and the index for each job (as a tuple): for index, value in enumerate(username_list): # need the index and the username in each queue item. q.put((index, value)) # Starting worker threads on queue processing for i in range(http_threads): worker = threading.Thread(target=crawl, args=(q, model_instances_dict), daemon=True) worker.start() time.sleep( wait_time ) # avoid server spamming by time-limiting the start of requests # now we wait until the queue has been processed q.join() for username in username_list: model_instance = model_instances_dict[username] keyboard_with_link_preview = [[ InlineKeyboardButton("Watch the live", url=f'http://chaturbate.com/{username}'), InlineKeyboardButton( "Update stream image", callback_data='view_stream_image_callback_' + username) ]] keyboard_without_link_preview = [[ InlineKeyboardButton("Watch the live", url=f'http://chaturbate.com/{username}') ]] markup_with_link_preview = InlineKeyboardMarkup( keyboard_with_link_preview) markup_without_link_preview = InlineKeyboardMarkup( keyboard_without_link_preview) try: if model_instance.status != "error": for chatid_tuple in chat_and_online_dict[username]: chat_id = chatid_tuple.chat_id db_status = chatid_tuple.online if model_instance.online and db_status == False: if model_instance.status in { "away", "private", "hidden", "password" }: # assuming the user knows the password Utils.alchemy_instance.session.query( ChaturbateUser).filter( ChaturbateUser.username == username and ChaturbateUser.chat_id == chat_id).update( {ChaturbateUser.online: True}, synchronize_session=False) send_message( chat_id, f"{username} is now <b>online</b>!\n<i>No link preview can be provided</i>", bot, html=True, markup=markup_without_link_preview) else: Utils.alchemy_instance.session.query( ChaturbateUser).filter( ChaturbateUser.username == username and ChaturbateUser.chat_id == chat_id).update( {ChaturbateUser.online: True}, synchronize_session=False) if Preferences.get_user_link_preview_preference( chat_id ) and model_instance.model_image is not None: send_image( chat_id, model_instance.model_image, bot, markup=markup_with_link_preview, caption= f"{username} is now <b>online</b>!", html=True) else: send_message( chat_id, f"{username} is now <b>online</b>!", bot, html=True, markup=markup_without_link_preview) elif model_instance.online == False and db_status: Utils.alchemy_instance.session.query( ChaturbateUser).filter( ChaturbateUser.username == username and ChaturbateUser.chat_id == chat_id).update( {ChaturbateUser.online: False}, synchronize_session=False) send_message(chat_id, f"{username} is now <b>offline</b>", bot, html=True) if model_instance.status == "deleted": Utils.alchemy_instance.session.query( ChaturbateUser).filter_by( username=username, chat_id=chat_id).delete( synchronize_session=False) send_message( chat_id, f"{username} has been removed because room has been deleted", bot) logging.info( f"{username} has been removed from {chat_id} because room has been deleted" ) elif model_instance.status == "banned": Utils.alchemy_instance.session.query( ChaturbateUser).filter_by( username=username, chat_id=chat_id).delete( synchronize_session=False) send_message( chat_id, f"{username} has been removed because room has been banned", bot) logging.info( f"{username} has been removed from {chat_id} because has been banned" ) elif model_instance.status == "canceled": Utils.alchemy_instance.session.query( ChaturbateUser).filter_by( username=username, chat_id=chat_id).delete( synchronize_session=False) send_message( chat_id, f"{username} has been removed because room has been canceled", bot) logging.info( f"{username} has been removed from {chat_id} because has been canceled" ) elif model_instance.status == "geoblocked": Utils.alchemy_instance.session.query( ChaturbateUser).filter_by( username=username, chat_id=chat_id).delete( synchronize_session=False) send_message( chat_id, f"{username} has been removed because of geoblocking", bot) logging.info( f"{username} has been removed from {chat_id} because of geoblocking" ) except Exception as e: Utils.handle_exception(e)
def send_message(chatid: str, messaggio: str, bot_p: updater.bot, html: bool = False, markup=None) -> None: """ Sends a message to a telegram user and sends "typing" action :param chatid: The chatid of the user who will receive the message :param messaggio: The message who the user will receive :param bot_p: telegram bot instance :param html: Enable html markdown parsing in the message :param markup: The reply_markup to use when sending the message """ disable_webpage_preview = not Preferences.get_user_link_preview_preference( chatid) # the setting is opposite of preference notification = not Preferences.get_user_notifications_sound_preference( chatid) # the setting is opposite of preference try: bot_p.send_chat_action(chat_id=chatid, action="typing") if html and markup is not None: bot_p.send_message( chat_id=chatid, text=messaggio, parse_mode=telegram.ParseMode.HTML, disable_web_page_preview=disable_webpage_preview, reply_markup=markup, disable_notification=notification) elif html: bot_p.send_message( chat_id=chatid, text=messaggio, parse_mode=telegram.ParseMode.HTML, disable_web_page_preview=disable_webpage_preview, disable_notification=notification) elif markup is not None: bot_p.send_message( chat_id=chatid, text=messaggio, disable_web_page_preview=disable_webpage_preview, reply_markup=markup, disable_notification=notification) else: bot_p.send_message( chat_id=chatid, text=messaggio, disable_web_page_preview=disable_webpage_preview, disable_notification=notification) except Unauthorized: # user blocked the bot if auto_remove: logging.info( f"{chatid} blocked the bot, he's been removed from the database" ) Utils.alchemy_instance.session.query(ChaturbateUser).filter_by( chat_id=str(chatid)).delete(synchronize_session=False) Preferences.remove_user_from_preferences(chatid) except Exception as e: Utils.handle_exception(e)
def send_image(chatid: str, image, bot_p: updater.bot, html: bool = False, markup=None, caption=None) -> None: """ Sends an image to a telegram user and sends "sending image" action :param caption: Photo caption :param chatid: The chatid of the user who will receive the message :param image: The image to send :param bot_p: telegram bot instance :param html: Enable html markdown parsing in the message :param markup: The reply_markup to use when sending the message """ notification = not Preferences.get_user_notifications_sound_preference( chatid) # the setting is opposite of preference try: bot_p.send_chat_action(chatid, action="upload_photo") if html and markup is not None and caption is not None: bot_p.send_photo(chat_id=chatid, photo=image, parse_mode=telegram.ParseMode.HTML, reply_markup=markup, disable_notification=notification, caption=caption) elif html and markup is not None: bot_p.send_photo(chat_id=chatid, photo=image, parse_mode=telegram.ParseMode.HTML, reply_markup=markup, disable_notification=notification) elif markup is not None and caption is not None: bot_p.send_photo(chat_id=chatid, photo=image, reply_markup=markup, disable_notification=notification, caption=caption) elif html and caption is not None: bot_p.send_photo(chat_id=chatid, photo=image, parse_mode=telegram.ParseMode.HTML, disable_notification=notification, caption=caption) elif html: bot_p.send_photo(chat_id=chatid, photo=image, parse_mode=telegram.ParseMode.HTML, disable_notification=notification) elif markup is not None: bot_p.send_photo(chat_id=chatid, photo=image, reply_markup=markup, disable_notification=notification) elif caption is not None: bot_p.send_photo(chat_id=chatid, photo=image, disable_notification=notification, caption=caption) else: bot_p.send_photo(chat_id=chatid, photo=image, disable_notification=notification) except Unauthorized: # user blocked the bot if auto_remove: logging.info( f"{chatid} blocked the bot, he's been removed from the database" ) Utils.alchemy_instance.session.query(ChaturbateUser).filter_by( chat_id=str(chatid)).delete(synchronize_session=False) Preferences.remove_user_from_preferences(chatid) except Exception as e: Utils.handle_exception(e)
def update_model_status(self): """ Updates self.online and self.status """ for attempt in range(5): # noinspection PyBroadException try: self.last_update = datetime.datetime.now() target = f"https://en.chaturbate.com/api/chatvideocontext/{self.username}" headers = { 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36', } self._response = requests.get(target, headers=headers) except Exception: self._response = None logging.info(self.username + " has failed to connect on attempt " + str(attempt)) time.sleep(3) # sleep and retry else: break if self._response is None: logging.info(self.username + " has failed to connect after all attempts") self.status = "error" elif b"It's probably just a broken link, or perhaps a cancelled broadcaster." in self._response.content: # check if models still exists self.status = "canceled" elif self._response.status_code == 401: self._response = json.loads(self._response.content) if "Room is deleted" in str(self._response['detail']): self.status = "deleted" elif "This room has been banned" in str(self._response['detail']): self.status = "banned" elif "This room is not available to your region or gender." in str( self._response['detail']): self.status = "geoblocked" elif "This room requires a password" in str( self._response['detail']): self.status = "password" else: self.status = "error" elif self._response.status_code == (200 and 401): logging.error( f'{self.username} got a {self._response.status_code} error') self.status = "error" else: try: self._response = json.loads(self._response.content) except Exception as e: Utils.handle_exception(e) logging.critical( "This response should have been json decodable") try: logging.critical(str(self._response.content)) except Exception as e: Utils.handle_exception(e) logging.critical("The response could not be printed") self.status = "error" else: self.status = self._response["room_status"] if self.status in { "offline", "error", "deleted", "banned", "geoblocked", "canceled" }: self.online = False else: self.online = True
def update_status() -> None: username_list = [] chat_and_online_dict={} # create a dictionary with usernames and online using distinct results = Utils.retrieve_query_results("SELECT DISTINCT USERNAME FROM CHATURBATE") for row in results: username_list.append(row[0]) # obtain chatid for username in username_list: results = Utils.retrieve_query_results(f"SELECT DISTINCT CHAT_ID, ONLINE FROM CHATURBATE WHERE USERNAME='******'") chat_and_online_dict[username]=results # assign (chatid,online) to every model # Threaded function for queue processing. def crawl(q, model_instances_dict): while not q.empty(): work = q.get() # fetch new work from the Queue username = Utils.sanitize_username(work[1]) model_instance=Model(username,autoupdate=False) model_instance.update_model_status() try: model_instance.update_model_image() except Exception: model_instance.model_image = None # set to None just to be secure Todo: this may be extra model_instances_dict[username] = model_instance # signal to the queue that task has been processed q.task_done() return True q = Queue(maxsize=0) # Populating Queue with tasks model_instances_dict = {} # load up the queue with the username_list to fetch and the index for each job (as a tuple): for index, value in enumerate(username_list): # need the index and the username in each queue item. q.put((index, value)) # Starting worker threads on queue processing for i in range(http_threads): worker = threading.Thread(target=crawl, args=(q, model_instances_dict), daemon=True) worker.start() time.sleep(wait_time) # avoid server spamming by time-limiting the start of requests # now we wait until the queue has been processed q.join() for username in username_list: model_instance = model_instances_dict[username] keyboard_with_link_preview = [[InlineKeyboardButton("Watch the live", url=f'http://chaturbate.com/{username}'), InlineKeyboardButton("Update stream image",callback_data='view_stream_image_callback_' + username)]] keyboard_without_link_preview = [ [InlineKeyboardButton("Watch the live", url=f'http://chaturbate.com/{username}')]] markup_with_link_preview = InlineKeyboardMarkup(keyboard_with_link_preview) markup_without_link_preview = InlineKeyboardMarkup(keyboard_without_link_preview) try: if model_instance.status != "error": for chatid_tuple in chat_and_online_dict[username]: chat_id=chatid_tuple[0] db_status=chatid_tuple[1] if model_instance.online and db_status == "F": if model_instance.status in {"away", "private", "hidden", "password"}: # assuming the user knows the password Utils.exec_query(f"UPDATE CHATURBATE SET ONLINE='T' WHERE USERNAME='******' AND CHAT_ID='{chat_id}'") send_message(chat_id, f"{username} is now <b>online</b>!\n<i>No link preview can be provided</i>", bot, html=True, markup=markup_without_link_preview) else: Utils.exec_query( f"UPDATE CHATURBATE SET ONLINE='T' WHERE USERNAME='******' AND CHAT_ID='{chat_id}'") if Preferences.get_user_link_preview_preference(chat_id) and model_instance.model_image != None: send_image(chat_id, model_instance.model_image, bot, markup=markup_with_link_preview, caption=f"{username} is now <b>online</b>!", html=True) else: send_message(chat_id,f"{username} is now <b>online</b>!",bot,html=True,markup=markup_without_link_preview) elif model_instance.online==False and db_status == "T": Utils.exec_query( f"UPDATE CHATURBATE SET ONLINE='F' WHERE USERNAME='******' AND CHAT_ID='{chat_id}'") send_message(chat_id, f"{username} is now <b>offline</b>", bot, html=True) if model_instance.status=="deleted": Utils.exec_query(f"DELETE FROM CHATURBATE WHERE USERNAME='******' AND CHAT_ID='{chat_id}'") send_message(chat_id, f"{username} has been removed because room has been deleted", bot) logging.info(f"{username} has been removed from {chat_id} because room has been deleted") elif model_instance.status=="banned": Utils.exec_query(f"DELETE FROM CHATURBATE WHERE USERNAME='******' AND CHAT_ID='{chat_id}'") send_message(chat_id, f"{username} has been removed because room has been banned", bot) logging.info(f"{username} has been removed from {chat_id} because has been banned") elif model_instance.status=="canceled": Utils.exec_query(f"DELETE FROM CHATURBATE WHERE USERNAME='******' AND CHAT_ID='{chat_id}'") send_message(chat_id, f"{username} has been removed because room has been canceled", bot) logging.info(f"{username} has been removed from {chat_id} because has been canceled") elif model_instance.status=="geoblocked": Utils.exec_query(f"DELETE FROM CHATURBATE WHERE USERNAME='******' AND CHAT_ID='{chat_id}'") send_message(chat_id, f"{username} has been removed because of geoblocking", bot) logging.info(f"{username} has been removed from {chat_id} because of geoblocking") except Exception as e: Utils.handle_exception(e)