diff --git a/bot/helper/ext_utils/bot_utils.py b/bot/helper/ext_utils/bot_utils.py index 20b316c..a7ec1c3 100644 --- a/bot/helper/ext_utils/bot_utils.py +++ b/bot/helper/ext_utils/bot_utils.py @@ -23,6 +23,7 @@ PAGE_NO = 1 class MirrorStatus: STATUS_UPLOADING = "Uploading...📤" STATUS_DOWNLOADING = "Downloading...📥" + STATUS_CLONING = "Cloning...♻️" STATUS_WAITING = "Queued...📝" STATUS_FAILED = "Failed 🚫. Cleaning Download..." STATUS_ARCHIVING = "Archiving...🔐" @@ -123,6 +124,8 @@ def get_readable_message(): msg += f"\n{get_progress_bar_string(download)} {download.progress()}" if download.status() == MirrorStatus.STATUS_DOWNLOADING: msg += f"\nDownloaded: {get_readable_file_size(download.processed_bytes())} of {download.size()}" + elif download.status() == MirrorStatus.STATUS_CLONING: + msg += f"\nCloned: {get_readable_file_size(download.processed_bytes())} of {download.size()}" else: msg += f"\nUploaded: {get_readable_file_size(download.processed_bytes())} of {download.size()}" msg += f"\nSpeed: {download.speed()}" \ @@ -134,7 +137,7 @@ def get_readable_message(): except: pass msg += f'\nUser: {download.message.from_user.first_name} ({download.message.from_user.id})' - if download.status() == MirrorStatus.STATUS_DOWNLOADING: + if download.status() == MirrorStatus.STATUS_DOWNLOADING or download.status() == MirrorStatus.STATUS_CLONING: msg += f"\nTo Stop: /{BotCommands.CancelMirror} {download.gid()}" msg += "\n\n" if STATUS_LIMIT is not None: diff --git a/bot/helper/mirror_utils/status_utils/clone_status.py b/bot/helper/mirror_utils/status_utils/clone_status.py new file mode 100644 index 0000000..f450ae7 --- /dev/null +++ b/bot/helper/mirror_utils/status_utils/clone_status.py @@ -0,0 +1,56 @@ +from .status import Status +from bot.helper.ext_utils.bot_utils import MirrorStatus, get_readable_file_size, get_readable_time + + +class CloneStatus(Status): + def __init__(self, obj, size, update, gid): + self.cobj = obj + self.__csize = size + self.message = update.message + self.__cgid = gid + + def processed_bytes(self): + return self.cobj.transferred_size + + def size_raw(self): + return self.__csize + + def size(self): + return get_readable_file_size(self.__csize) + + def status(self): + return MirrorStatus.STATUS_CLONING + + def name(self): + return self.cobj.name + + def gid(self) -> str: + return self.__cgid + + def progress_raw(self): + try: + return self.cobj.transferred_size / self.__csize * 100 + except ZeroDivisionError: + return 0 + + def progress(self): + return f'{round(self.progress_raw(), 2)}%' + + def speed_raw(self): + """ + :return: Download speed in Bytes/Seconds + """ + return self.cobj.cspeed() + + def speed(self): + return f'{get_readable_file_size(self.speed_raw())}/s' + + def eta(self): + try: + seconds = (self.__csize - self.cobj.transferred_size) / self.speed_raw() + return f'{get_readable_time(seconds)}' + except ZeroDivisionError: + return '-' + + def download(self): + return self.cobj diff --git a/bot/helper/mirror_utils/upload_utils/gdriveTools.py b/bot/helper/mirror_utils/upload_utils/gdriveTools.py index b2fab5d..2cc9427 100644 --- a/bot/helper/mirror_utils/upload_utils/gdriveTools.py +++ b/bot/helper/mirror_utils/upload_utils/gdriveTools.py @@ -22,7 +22,7 @@ from telegram import InlineKeyboardMarkup from bot.helper.telegram_helper import button_build from telegraph import Telegraph from bot import parent_id, DOWNLOAD_DIR, IS_TEAM_DRIVE, INDEX_URL, \ - USE_SERVICE_ACCOUNTS, download_dict, telegraph_token, BUTTON_FOUR_NAME, BUTTON_FOUR_URL, BUTTON_FIVE_NAME, BUTTON_FIVE_URL, BUTTON_SIX_NAME, BUTTON_SIX_URL, SHORTENER, SHORTENER_API, IMAGE_URL, VIEW_LINK + USE_SERVICE_ACCOUNTS, telegraph_token, BUTTON_FOUR_NAME, BUTTON_FOUR_URL, BUTTON_FIVE_NAME, BUTTON_FIVE_URL, BUTTON_SIX_NAME, BUTTON_SIX_URL, SHORTENER, SHORTENER_API, IMAGE_URL, VIEW_LINK from bot.helper.ext_utils.bot_utils import * from bot.helper.ext_utils.fs_utils import get_mime_type, get_path_size @@ -44,17 +44,15 @@ class GoogleDriveHelper: self.__G_DRIVE_DIR_BASE_DOWNLOAD_URL = "https://drive.google.com/drive/folders/{}" self.__listener = listener self.__service = self.authorize() - self.__listener = listener self._file_uploaded_bytes = 0 self._file_downloaded_bytes = 0 self.uploaded_bytes = 0 self.downloaded_bytes = 0 - self.UPDATE_INTERVAL = 5 self.start_time = 0 self.total_time = 0 self.dtotal_time = 0 - self._should_update = True - self.is_uploading = True + self.is_downloading = False + self.is_cloning = False self.is_cancelled = False self.status = None self.dstatus = None @@ -66,12 +64,9 @@ class GoogleDriveHelper: self.total_bytes = 0 self.total_files = 0 self.total_folders = 0 + self.transferred_size = 0 self.sa_count = 0 - def cancel(self): - self.is_cancelled = True - self.is_uploading = False - def speed(self): """ It calculates the average upload speed and returns it in bytes/seconds unit @@ -86,7 +81,13 @@ class GoogleDriveHelper: try: return self.downloaded_bytes / self.dtotal_time except ZeroDivisionError: - return 0 + return 0 + + def cspeed(self): + try: + return self.transferred_size / int(time.time() - self.start_time) + except ZeroDivisionError: + return 0 @staticmethod def getIdFromUrl(link: str): @@ -236,7 +237,6 @@ class GoogleDriveHelper: file_path = f"{file_dir}/{file_name}" size = get_readable_file_size(get_path_size(file_path)) LOGGER.info("Uploading File: " + file_path) - self.start_time = time.time() self.updater = setInterval(self.update_interval, self._on_upload_progress) if os.path.isfile(file_path): try: @@ -275,7 +275,6 @@ class GoogleDriveHelper: return finally: self.updater.cancel() - LOGGER.info(download_dict) files = self.total_files folders = self.total_folders typ = self.typee @@ -338,7 +337,8 @@ class GoogleDriveHelper: return files def clone(self, link): - self.transferred_size = 0 + self.is_cloning = True + self.start_time = time.time() self.total_files = 0 self.total_folders = 0 if USE_SERVICE_ACCOUNTS: @@ -355,11 +355,16 @@ class GoogleDriveHelper: if meta.get("mimeType") == self.__G_DRIVE_DIR_MIME_TYPE: dir_id = self.create_directory(meta.get('name'), parent_id) self.cloneFolder(meta.get('name'), meta.get('name'), meta.get('id'), dir_id) + durl = self.__G_DRIVE_DIR_BASE_DOWNLOAD_URL.format(dir_id) + if self.is_cancelled: + LOGGER.info("Deleting cloned data from drive...") + msg = self.deletefile(durl) + LOGGER.info(f"{msg}") + return "Your clone has been stopped and cloned data has been deleted!", "cancelled" msg += f'Filename: {meta.get("name")}\nSize: {get_readable_file_size(self.transferred_size)}' msg += f'\nType: Folder' msg += f'\nSubFolders: {self.total_folders}' msg += f'\nFiles: {self.total_files}' - durl = self.__G_DRIVE_DIR_BASE_DOWNLOAD_URL.format(dir_id) buttons = button_build.ButtonMaker() if SHORTENER is not None and SHORTENER_API is not None: surl = requests.get(f'https://{SHORTENER}/api?api={SHORTENER_API}&url={durl}&format=text').text @@ -723,6 +728,7 @@ class GoogleDriveHelper: except TypeError: pass clonesize = self.total_bytes + files = self.total_files except Exception as err: err = str(err).replace('>', '').replace('<', '') LOGGER.error(err) @@ -731,13 +737,13 @@ class GoogleDriveHelper: else: msg = f"Error.\n{err}" return msg, "", "" - return "", clonesize, name + return "", clonesize, name, files def download(self, link): + self.is_downloading = True file_id = self.getIdFromUrl(link) if USE_SERVICE_ACCOUNTS: self.service_account_count = len(os.listdir("accounts")) - self.start_time = time.time() self.updater = setInterval(self.update_interval, self._on_download_progress) try: meta = self.getFileMetadata(file_id) @@ -834,5 +840,8 @@ class GoogleDriveHelper: def cancel_download(self): self.is_cancelled = True - LOGGER.info(f"Cancelling Download: {self.name}") - self.__listener.onDownloadError('Download stopped by user!') + if self.is_downloading: + LOGGER.info(f"Cancelling Download: {self.name}") + self.__listener.onDownloadError('Download stopped by user!') + elif self.is_cloning: + LOGGER.info(f"Cancelling Clone: {self.name}") diff --git a/bot/helper/telegram_helper/message_utils.py b/bot/helper/telegram_helper/message_utils.py index 7f4ae4b..19b081a 100644 --- a/bot/helper/telegram_helper/message_utils.py +++ b/bot/helper/telegram_helper/message_utils.py @@ -93,7 +93,7 @@ def update_all_messages(): uldl_bytes += float(speedy.split('M')[0]) * 1048576 dlspeed = get_readable_file_size(dlspeed_bytes) ulspeed = get_readable_file_size(uldl_bytes) - msg += f"\nFREE: {free} | UPTIME: {currentTime}\nDL: {dlspeed}ps 🔻 | UL: {ulspeed}ps 🔺\n" + msg += f"\nFREE: {free} | UPTIME: {currentTime}\nDL: {dlspeed}/s 🔻 | UL: {ulspeed}/s 🔺\n" with status_reply_dict_lock: for chat_id in list(status_reply_dict.keys()): if status_reply_dict[chat_id] and msg != status_reply_dict[chat_id].text: @@ -134,7 +134,7 @@ def sendStatusMessage(msg, bot): uldl_bytes += float(speedy.split('M')[0]) * 1048576 dlspeed = get_readable_file_size(dlspeed_bytes) ulspeed = get_readable_file_size(uldl_bytes) - progress += f"\nFREE: {free} | UPTIME: {currentTime}\nDL: {dlspeed}ps 🔻 | UL: {ulspeed}ps 🔺\n" + progress += f"\nFREE: {free} | UPTIME: {currentTime}\nDL: {dlspeed}/s 🔻 | UL: {ulspeed}/s 🔺\n" with status_reply_dict_lock: if msg.message.chat.id in list(status_reply_dict.keys()): try: diff --git a/bot/modules/cancel_mirror.py b/bot/modules/cancel_mirror.py index a11e1ca..6385ac9 100644 --- a/bot/modules/cancel_mirror.py +++ b/bot/modules/cancel_mirror.py @@ -72,7 +72,6 @@ def cancel_all(update, context): count += 1 else: break - delete_all_messages() sendMessage(f'{count} Download(s) has been Cancelled!', context.bot, update) diff --git a/bot/modules/clone.py b/bot/modules/clone.py index df4f909..cae1aaa 100644 --- a/bot/modules/clone.py +++ b/bot/modules/clone.py @@ -1,56 +1,84 @@ from telegram.ext import CommandHandler -from bot.helper.mirror_utils.upload_utils.gdriveTools import GoogleDriveHelper -from bot.helper.telegram_helper.message_utils import sendMarkup, deleteMessage, sendMessage +from bot.helper.mirror_utils.upload_utils import gdriveTools +from bot.helper.telegram_helper.message_utils import * from bot.helper.telegram_helper.filters import CustomFilters from bot.helper.telegram_helper.bot_commands import BotCommands -from bot import dispatcher, LOGGER, CLONE_LIMIT, STOP_DUPLICATE_CLONE -from bot.helper.ext_utils.bot_utils import get_readable_file_size +from bot.helper.mirror_utils.status_utils.clone_status import CloneStatus +from bot import dispatcher, LOGGER, CLONE_LIMIT, STOP_DUPLICATE_CLONE, download_dict, download_dict_lock, Interval, DOWNLOAD_STATUS_UPDATE_INTERVAL +from bot.helper.ext_utils.bot_utils import get_readable_file_size, setInterval +import random +import string def cloneNode(update, context): args = update.message.text.split(" ", maxsplit=1) if len(args) > 1: link = args[1] - gd = GoogleDriveHelper() - if CLONE_LIMIT is not None or STOP_DUPLICATE_CLONE: - res, clonesize, name = gd.clonehelper(link) - if res != "": - sendMessage(res, context.bot, update) - return - if STOP_DUPLICATE_CLONE: - LOGGER.info(f"Checking File/Folder if already in Drive...") - smsg, button = gd.drive_list(name) - if smsg: - msg3 = "File/Folder is already available in Drive.\nHere are the search results:" - sendMarkup(msg3, context.bot, update, button) + gd = gdriveTools.GoogleDriveHelper() + res, clonesize, name, files = gd.clonehelper(link) + if res != "": + sendMessage(res, context.bot, update) + return + if STOP_DUPLICATE_CLONE: + LOGGER.info(f"Checking File/Folder if already in Drive...") + smsg, button = gd.drive_list(name) + if smsg: + msg3 = "File/Folder is already available in Drive.\nHere are the search results:" + sendMarkup(msg3, context.bot, update, button) + return + if CLONE_LIMIT is not None: + LOGGER.info(f"Checking File/Folder Size...") + limit = CLONE_LIMIT + limit = limit.split(' ', maxsplit=1) + limitint = int(limit[0]) + msg2 = f'Failed, Clone limit is {CLONE_LIMIT}.\nYour File/Folder size is {get_readable_file_size(clonesize)}.' + if 'G' in limit[1] or 'g' in limit[1]: + if clonesize > limitint * 1024**3: + sendMessage(msg2, context.bot, update) return - if CLONE_LIMIT is not None: - LOGGER.info(f"Checking File/Folder Size...") - limit = CLONE_LIMIT - limit = limit.split(' ', maxsplit=1) - limitint = int(limit[0]) - msg2 = f'Failed, Clone limit is {CLONE_LIMIT}.\nYour File/Folder size is {get_readable_file_size(clonesize)}.' - if 'G' in limit[1] or 'g' in limit[1]: - if clonesize > limitint * 1024**3: - sendMessage(msg2, context.bot, update) - return - elif 'T' in limit[1] or 't' in limit[1]: - if clonesize > limitint * 1024**4: - sendMessage(msg2, context.bot, update) - return - msg = sendMessage(f"Cloning: {link}", context.bot, update) - result, button = gd.clone(link) - deleteMessage(context.bot, msg) - if button == "": - sendMessage(result, context.bot, update) + elif 'T' in limit[1] or 't' in limit[1]: + if clonesize > limitint * 1024**4: + sendMessage(msg2, context.bot, update) + return + if files < 15: + msg = sendMessage(f"Cloning: {link}", context.bot, update) + result, button = gd.clone(link) + deleteMessage(context.bot, msg) + else: + drive = gdriveTools.GoogleDriveHelper(name) + gid = ''.join(random.SystemRandom().choices(string.ascii_letters + string.digits, k=12)) + clone_status = CloneStatus(drive, clonesize, update, gid) + with download_dict_lock: + download_dict[update.message.message_id] = clone_status + if len(Interval) == 0: + Interval.append(setInterval(DOWNLOAD_STATUS_UPDATE_INTERVAL, update_all_messages)) + sendStatusMessage(update, context.bot) + result, button = drive.clone(link) + if update.message.from_user.username: + uname = f'@{update.message.from_user.username}' + else: + uname = f'{update.message.from_user.first_name}' + if uname is not None: + cc = f'\n\ncc: {uname}' + men = f'{uname} ' + if button == "cancelled": + sendMessage(men + result, context.bot, update) + elif button == "": + sendMessage(men + result, context.bot, update) else: - if update.message.from_user.username: - uname = f'@{update.message.from_user.username}' - else: - uname = f'{update.message.from_user.first_name}' - if uname is not None: - cc = f'\n\ncc: {uname}' sendMarkup(result + cc, context.bot, update, button) + try: + with download_dict_lock: + del download_dict[update.message.message_id] + count = len(download_dict) + if count == 0: + Interval[0].cancel() + del Interval[0] + delete_all_messages() + else: + update_all_messages() + except IndexError: + pass else: sendMessage('Provide G-Drive Shareable Link to Clone.', context.bot, update) diff --git a/bot/modules/mirror.py b/bot/modules/mirror.py index 0fca8ec..14b59dd 100644 --- a/bot/modules/mirror.py +++ b/bot/modules/mirror.py @@ -302,7 +302,7 @@ def _mirror(bot, update, isTar=False, extract=False): if not isTar and not extract: sendMessage(f"Use /{BotCommands.CloneCommand} to clone Google Drive file/folder\nUse /{BotCommands.TarMirrorCommand} to make tar of Google Drive folder\nUse /{BotCommands.UnzipMirrorCommand} to extracts archive Google Drive file", bot, update) return - res, size, name = gdriveTools.GoogleDriveHelper().clonehelper(link) + res, size, name, files = gdriveTools.GoogleDriveHelper().clonehelper(link) if res != "": sendMessage(res, bot, update) return