def authorize_admin(update, CallbackContext) -> None: global bot args = CallbackContext.args chatid = update.message.chat_id if len(args) != 1: send_message( chatid, "You need to specify the admin password, use the command like /authorize_admin <b>password</b>", bot, html=True ) return elif admin_pw == "": send_message( chatid, "The admin is disabled, check your telegram bot configuration", bot ) return if Utils.admin_check(chatid): send_message(chatid, "You already are an admin", bot) elif args[0] == admin_pw: Utils.exec_query(f"""INSERT INTO ADMIN VALUES ({chatid})""") send_message(chatid, "Admin enabled", bot) send_message(chatid, "Remember to disable the --admin-password if you want to avoid people trying to bruteforce this command", bot) logging.info(f"{chatid} got admin authorization") else: send_message(chatid, "The password is wrong", bot)
def remove_user_from_preferences(chatid: str) -> None: """ Remove the chatid from the preference table :param chatid: The chatid of the user who will be removed """ Utils.exec_query(f"DELETE FROM PREFERENCES WHERE CHAT_ID='{chatid}'") logging.info(f'{chatid} has been removed from preferences')
def add_user_to_preferences(chatid: str) -> None: """ Add user to the preference table :param chatid: The chatid of the user who will be tested """ Utils.exec_query(f"INSERT INTO PREFERENCES VALUES ('{chatid}', '1', '1')") logging.info(f'{chatid} has been added to preferences')
def update_notifications_sound_preference(chatid: str, value: bool) -> None: """ Update the notifications preference of the user :param chatid: The chatid of the user who will be tested :param value: The boolean value that will be converted to int and inserted in the table """ if value: value = 1 else: value = 0 Utils.exec_query( f"UPDATE PREFERENCES SET NOTIFICATIONS_SOUND='{value}' WHERE CHAT_ID='{chatid}'" )
def update_link_preview_preference(chatid: str, value: bool) -> None: """ Update the link_preview preference of the user :param chatid: The chatid of the user who will be tested :param value: The boolean value that will be converted to int and inserted in the table """ if value: value = 1 else: value = 0 Utils.exec_query( f"UPDATE PREFERENCES SET LINK_PREVIEW='{value}' WHERE CHAT_ID='{chatid}'" )
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 remove(update, CallbackContext) -> None: global bot args = CallbackContext.args chatid = update.message.chat_id username_message_list = [] usernames_in_database = [] if len(args) < 1: send_message( chatid, "You need to specify an username to follow, use the command like /remove <b>test</b>\n You can also remove multiple users at the same time by separating them using a comma, like /remove <b>username1</b>,<b>username2</b>", bot, html=True ) return if len(args) > 1: for username in args: if username != "": username_message_list.append(Utils.sanitize_username(username).replace(",", "")) # len(args)==0 -> only one username or all in one line elif "," in args[0].lower(): for splitted_username in args[0].lower().replace(" ", "").rstrip().split(","): if splitted_username != "": username_message_list.append(Utils.sanitize_username(splitted_username)) else: username_message_list.append(Utils.sanitize_username(args[0])) results = Utils.retrieve_query_results(f"SELECT * FROM CHATURBATE WHERE CHAT_ID='{chatid}'") for row in results: usernames_in_database.append(row[0]) if "all" in username_message_list: Utils.exec_query( f"DELETE FROM CHATURBATE WHERE CHAT_ID='{chatid}'") send_message(chatid, "All usernames have been removed", bot) logging.info(f"{chatid} removed all usernames") else: for username in username_message_list: if username in usernames_in_database: Utils.exec_query(f"DELETE FROM CHATURBATE WHERE USERNAME='******' AND CHAT_ID='{chatid}'") send_message(chatid, f"{username} has been removed", bot) logging.info(f"{chatid} removed {username}") else: send_message(chatid, f"You aren't following {username}", bot)
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 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)
def add(update, CallbackContext) -> None: global bot args = CallbackContext.args chatid = update.message.chat_id username_message_list = [] if len(args) < 1: send_message( chatid, "You need to specify an username to follow, use the command like /add <b>username</b>\n You can also add multiple users at the same time by separating them using a comma, like /add <b>username1</b>,<b>username2</b>", bot, html=True ) return # not lowercase usernames bug the api calls if len(args) > 1: for username in args: if username != "": username_message_list.append(Utils.sanitize_username(username).replace(",", "")) # len(args)==0 -> only one username or all in one line elif "," in args[0].lower(): for splitted_username in args[0].lower().replace(" ", "").rstrip().split(","): if splitted_username != "": username_message_list.append(Utils.sanitize_username(splitted_username)) else: username_message_list.append(Utils.sanitize_username(args[0])) username_message_list = list(dict.fromkeys(username_message_list)) # remove duplicate usernames usernames_in_database = [] # obtain present usernames results = Utils.retrieve_query_results(f"SELECT USERNAME FROM CHATURBATE WHERE CHAT_ID='{chatid}'") for row in results: usernames_in_database.append(row[0]) # 0 is unlimited usernames if len(usernames_in_database) + len(username_message_list) > user_limit and ( Utils.admin_check(chatid) == False != user_limit != 0): send_message(chatid, "You are trying to add more usernames than your limit permits, which is " + str(user_limit), bot) logging.info(f'{chatid} tried to add more usernames than his limit permits') return for username in username_message_list: model_instance=Model(username) if model_instance.status not in ('deleted', 'banned', 'geoblocked', 'canceled', 'error'): if username not in usernames_in_database: Utils.exec_query(f"INSERT INTO CHATURBATE VALUES ('{username}', '{chatid}', 'F')") send_message(chatid, f"{username} has been added", bot) logging.info(f'{chatid} added {username}') else: send_message(chatid,f"{username} has already been added",bot) elif model_instance.status=='deleted': send_message(chatid, f"{username} has not been added because is deleted", bot) logging.info(f"{chatid} could not add {username} because is deleted") elif model_instance.status=='banned': send_message(chatid, f"{username} has not been added because is banned", bot) logging.info(f"{chatid} could not add {username} because is banned") elif model_instance.status=='geoblocked': send_message(chatid, f"{username} has not been added because is geoblocked", bot) logging.info(f"{chatid} could not add {username} because is geoblocked") elif model_instance.status=='canceled': send_message(chatid, f"{username} was not added because it doesn't exist", bot) logging.info(f'{chatid} tried to add {username}, which does not exist') elif model_instance.status=='error': send_message(chatid, f"{username} was not added because an error happened", bot) logging.info(f'{chatid} could not add {username} because an error happened')
dispatcher.add_handler(CommandHandler('authorize_admin', authorize_admin)) dispatcher.add_handler(CommandHandler('send_message_to_everyone', send_message_to_everyone)) dispatcher.add_handler(CommandHandler('active_users', active_users)) dispatcher.add_handler(CommandHandler('active_models', active_models)) logging.info('Checking database existence...') # default table creation Utils.exec_query("""CREATE TABLE IF NOT EXISTS CHATURBATE ( USERNAME CHAR(60) NOT NULL, CHAT_ID CHAR(100), ONLINE CHAR(1))""") # admin table creation Utils.exec_query("""CREATE TABLE IF NOT EXISTS ADMIN ( CHAT_ID CHAR(100))""") Utils.exec_query('''CREATE TABLE IF NOT EXISTS "PREFERENCES" ( "CHAT_ID" CHAR(100) UNIQUE, "LINK_PREVIEW" INTEGER DEFAULT 1, "NOTIFICATIONS_SOUND" INTEGER DEFAULT 1, PRIMARY KEY("CHAT_ID") )''') logging.info('Starting models checking thread...') threading.Thread(target=check_online_status, daemon=True).start()