diff --git a/bot/helper/ext_utils/shortenurl.py b/bot/helper/ext_utils/shortenurl.py new file mode 100644 index 0000000..03be2f7 --- /dev/null +++ b/bot/helper/ext_utils/shortenurl.py @@ -0,0 +1,27 @@ +import requests +import random +import base64 +import pyshorteners +from urllib.parse import quote +from urllib3 import disable_warnings +from bot import SHORTENER, SHORTENER_API + + +def short_url(longurl): + if "shorte.st" in SHORTENER: + disable_warnings() + return requests.get(f'http://api.shorte.st/stxt/{SHORTENER_API}/{longurl}', verify=False).text + elif "linkvertise" in SHORTENER: + url = quote(base64.b64encode(longurl.encode("utf-8"))) + linkvertise = [ + f"https://link-to.net/{SHORTENER_API}/{random.random() * 1000}/dynamic?r={url}", + f"https://up-to-down.net/{SHORTENER_API}/{random.random() * 1000}/dynamic?r={url}", + f"https://direct-link.net/{SHORTENER_API}/{random.random() * 1000}/dynamic?r={url}", + f"https://file-link.net/{SHORTENER_API}/{random.random() * 1000}/dynamic?r={url}"] + return random.choice(linkvertise) + elif "bitly.com" in SHORTENER: + s = pyshorteners.Shortener(api_key=SHORTENER_API) + bitly = s.bitly.short(longurl) + return bitly + else: + return requests.get(f'https://{SHORTENER}/api?api={SHORTENER_API}&url={longurl}&format=text').text diff --git a/bot/helper/mirror_utils/download_utils/download_helper.py b/bot/helper/mirror_utils/download_utils/download_helper.py deleted file mode 100644 index ebcca14..0000000 --- a/bot/helper/mirror_utils/download_utils/download_helper.py +++ /dev/null @@ -1,27 +0,0 @@ -# An abstract class which will be inherited by the tool specific classes like aria2_helper or mega_download_helper -import threading - - -class MethodNotImplementedError(NotImplementedError): - def __init__(self): - super(self, 'Not implemented method') - - -class DownloadHelper: - def __init__(self): - self.name = '' # Name of the download; empty string if no download has been started - self.size = 0.0 # Size of the download - self.downloaded_bytes = 0.0 # Bytes downloaded - self.speed = 0.0 # Download speed in bytes per second - self.progress = 0.0 - self.progress_string = '0.00%' - self.eta = 0 # Estimated time of download complete - self.eta_string = '0s' # A listener class which have event callbacks - self._resource_lock = threading.Lock() - - def add_download(self, link: str, path): - raise MethodNotImplementedError - - def cancel_download(self): - # Returns None if successfully cancelled, else error string - raise MethodNotImplementedError diff --git a/bot/helper/mirror_utils/download_utils/mega_downloader.py b/bot/helper/mirror_utils/download_utils/mega_downloader.py index 0d0b474..e0ae427 100644 --- a/bot/helper/mirror_utils/download_utils/mega_downloader.py +++ b/bot/helper/mirror_utils/download_utils/mega_downloader.py @@ -77,10 +77,10 @@ class MegaAppListener(MegaListener): self.continue_event.set() def onRequestTemporaryError(self, api, request, error: MegaError): - LOGGER.info(f'Mega Request error in {error}') + LOGGER.error(f'Mega Request error in {error}') if not self.is_cancelled: - self.listener.onDownloadError("RequestTempError: " + error.toString()) self.is_cancelled = True + self.listener.onDownloadError("RequestTempError: " + error.toString()) self.error = error.toString() self.continue_event.set() @@ -90,12 +90,15 @@ class MegaAppListener(MegaListener): def onTransferUpdate(self, api: MegaApi, transfer: MegaTransfer): if self.is_cancelled: api.cancelTransfer(transfer, None) + return self.__speed = transfer.getSpeed() self.__bytes_transferred = transfer.getTransferredBytes() def onTransferFinish(self, api: MegaApi, transfer: MegaTransfer, error): try: - if transfer.isFolderTransfer() and transfer.isFinished() or transfer.getFileName() == self.name and not self.is_cancelled: + if self.is_cancelled: + self.continue_event.set() + elif transfer.isFinished() and (transfer.isFolderTransfer() or transfer.getFileName() == self.name): self.listener.onDownloadComplete() self.continue_event.set() except Exception as e: @@ -105,7 +108,7 @@ class MegaAppListener(MegaListener): filen = transfer.getFileName() state = transfer.getState() errStr = error.toString() - LOGGER.info(f'Mega download error in file {transfer} {filen}: {error}') + LOGGER.error(f'Mega download error in file {transfer} {filen}: {error}') if state == 1 or state == 4: # Sometimes MEGA (offical client) can't stream a node either and raises a temp failed error. @@ -163,7 +166,7 @@ class MegaDownloadHelper: executor.do(folder_api.loginToFolder, (mega_link,)) node = folder_api.authorizeNode(mega_listener.node) if mega_listener.error is not None: - return listener.onDownloadError(str(mega_listener.error)) + return sendMessage(str(mega_listener.error), listener.bot, listener.update) if STOP_DUPLICATE: LOGGER.info(f'Checking File/Folder if already in Drive') mname = node.getName() diff --git a/bot/helper/mirror_utils/upload_utils/gdriveTools.py b/bot/helper/mirror_utils/upload_utils/gdriveTools.py index 72c9a71..ea7589c 100644 --- a/bot/helper/mirror_utils/upload_utils/gdriveTools.py +++ b/bot/helper/mirror_utils/upload_utils/gdriveTools.py @@ -26,14 +26,20 @@ from bot import parent_id, DOWNLOAD_DIR, IS_TEAM_DRIVE, INDEX_URL, \ 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, VIEW_LINK from bot.helper.ext_utils.bot_utils import get_readable_file_size, setInterval from bot.helper.ext_utils.fs_utils import get_mime_type, get_path_size +from bot.helper.ext_utils.shortenurl import short_url LOGGER = logging.getLogger(__name__) logging.getLogger('googleapiclient.discovery').setLevel(logging.ERROR) + if USE_SERVICE_ACCOUNTS: SERVICE_ACCOUNT_INDEX = randrange(len(os.listdir("accounts"))) + TELEGRAPHLIMIT = 80 + class GoogleDriveHelper: + + def __init__(self, name=None, listener=None): self.__G_DRIVE_TOKEN_FILE = "token.pickle" # Check https://developers.google.com/drive/scopes for all available scopes @@ -69,6 +75,7 @@ class GoogleDriveHelper: self.transferred_size = 0 self.sa_count = 0 + def speed(self): """ It calculates the average upload speed and returns it in bytes/seconds unit @@ -79,18 +86,21 @@ class GoogleDriveHelper: except ZeroDivisionError: return 0 + def dspeed(self): try: return self.downloaded_bytes / self.dtotal_time except ZeroDivisionError: 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): if "folders" in link or "file" in link: @@ -102,6 +112,7 @@ class GoogleDriveHelper: parsed = urlparse.urlparse(link) return parse_qs(parsed.query)['id'][0] + @retry(wait=wait_exponential(multiplier=2, min=3, max=6), stop=stop_after_attempt(5), retry=retry_if_exception_type(HttpError), before=before_log(LOGGER, logging.DEBUG)) def _on_upload_progress(self): @@ -112,6 +123,7 @@ class GoogleDriveHelper: self.uploaded_bytes += chunk_size self.total_time += self.update_interval + def __upload_empty_file(self, path, file_name, mime_type, parent_id=None): media_body = MediaFileUpload(path, mimetype=mime_type, @@ -125,6 +137,8 @@ class GoogleDriveHelper: file_metadata['parents'] = [parent_id] return self.__service.files().create(supportsTeamDrives=True, body=file_metadata, media_body=media_body).execute() + + def deletefile(self, link: str): try: file_id = self.getIdFromUrl(link) @@ -144,6 +158,7 @@ class GoogleDriveHelper: finally: return msg + def switchServiceAccount(self): global SERVICE_ACCOUNT_INDEX service_account_count = len(os.listdir("accounts")) @@ -153,7 +168,8 @@ class GoogleDriveHelper: SERVICE_ACCOUNT_INDEX += 1 LOGGER.info(f"Switching to {SERVICE_ACCOUNT_INDEX}.json service account") self.__service = self.authorize() - + + @retry(wait=wait_exponential(multiplier=2, min=3, max=6), stop=stop_after_attempt(5), retry=retry_if_exception_type(HttpError), before=before_log(LOGGER, logging.DEBUG)) def __set_permission(self, drive_id): @@ -166,6 +182,7 @@ class GoogleDriveHelper: return self.__service.permissions().create(supportsTeamDrives=True, fileId=drive_id, body=permissions).execute() + @retry(wait=wait_exponential(multiplier=2, min=3, max=6), stop=stop_after_attempt(5), retry=retry_if_exception_type(HttpError), before=before_log(LOGGER, logging.DEBUG)) def upload_file(self, file_path, file_name, mime_type, parent_id): @@ -234,6 +251,7 @@ class GoogleDriveHelper: download_url = self.__G_DRIVE_BASE_DOWNLOAD_URL.format(drive_file.get('id')) return download_url + def upload(self, file_name: str): self.is_downloading = False self.is_uploading = True @@ -299,6 +317,7 @@ class GoogleDriveHelper: self.__listener.onUploadComplete(link, size, files, folders, typ) return link + @retry(wait=wait_exponential(multiplier=2, min=3, max=6), stop=stop_after_attempt(5), retry=retry_if_exception_type(HttpError), before=before_log(LOGGER, logging.DEBUG)) def copyFile(self, file_id, dest_id): @@ -327,12 +346,14 @@ class GoogleDriveHelper: else: raise err + @retry(wait=wait_exponential(multiplier=2, min=3, max=6), stop=stop_after_attempt(5), retry=retry_if_exception_type(HttpError), before=before_log(LOGGER, logging.DEBUG)) def getFileMetadata(self,file_id): return self.__service.files().get(supportsAllDrives=True, fileId=file_id, fields="name,id,mimeType,size").execute() + @retry(wait=wait_exponential(multiplier=2, min=3, max=6), stop=stop_after_attempt(5), retry=retry_if_exception_type(HttpError), before=before_log(LOGGER, logging.DEBUG)) def getFilesByFolderId(self,folder_id): @@ -354,6 +375,7 @@ class GoogleDriveHelper: break return files + def clone(self, link): self.is_cloning = True self.start_time = time.time() @@ -385,7 +407,7 @@ class GoogleDriveHelper: msg += f'\nFiles: {self.total_files}' 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 + surl = short_url(durl) buttons.buildbutton("☁️ Drive Link", surl) else: buttons.buildbutton("☁️ Drive Link", durl) @@ -393,7 +415,7 @@ class GoogleDriveHelper: url_path = requests.utils.quote(f'{meta.get("name")}') url = f'{INDEX_URL}/{url_path}/' if SHORTENER is not None and SHORTENER_API is not None: - siurl = requests.get(f'https://{SHORTENER}/api?api={SHORTENER_API}&url={url}&format=text').text + siurl = short_url(url) buttons.buildbutton("⚡ Index Link", siurl) else: buttons.buildbutton("⚡ Index Link", url) @@ -409,17 +431,17 @@ class GoogleDriveHelper: durl = self.__G_DRIVE_BASE_DOWNLOAD_URL.format(file.get("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 + surl = short_url(durl) buttons.buildbutton("☁️ Drive Link", surl) else: buttons.buildbutton("☁️ Drive Link", durl) try: - typeee = file.get('mimeType') + typ = file.get('mimeType') except: - typeee = 'File' + typ = 'File' try: msg += f'\nSize: {get_readable_file_size(int(meta.get("size")))}' - msg += f'\nType: {typeee}' + msg += f'\nType: {typ}' except TypeError: pass if INDEX_URL is not None: @@ -427,10 +449,10 @@ class GoogleDriveHelper: url = f'{INDEX_URL}/{url_path}' urls = f'{INDEX_URL}/{url_path}?a=view' if SHORTENER is not None and SHORTENER_API is not None: - siurl = requests.get(f'https://{SHORTENER}/api?api={SHORTENER_API}&url={url}&format=text').text - siurls = requests.get(f'https://{SHORTENER}/api?api={SHORTENER_API}&url={urls}&format=text').text + siurl = short_url(url) buttons.buildbutton("⚡ Index Link", siurl) if VIEW_LINK: + siurls = short_url(urls) buttons.buildbutton("🌐 View Link", siurls) else: buttons.buildbutton("⚡ Index Link", url) @@ -457,6 +479,7 @@ class GoogleDriveHelper: return msg, "" return msg, InlineKeyboardMarkup(buttons.build_menu(2)) + def cloneFolder(self, name, local_path, folder_id, parent_id): LOGGER.info(f"Syncing: {local_path}") files = self.getFilesByFolderId(folder_id) @@ -480,6 +503,7 @@ class GoogleDriveHelper: if self.is_cancelled: break + @retry(wait=wait_exponential(multiplier=2, min=3, max=6), stop=stop_after_attempt(5), retry=retry_if_exception_type(HttpError), before=before_log(LOGGER, logging.DEBUG)) def create_directory(self, directory_name, parent_id): @@ -496,6 +520,7 @@ class GoogleDriveHelper: LOGGER.info("Created G-Drive Folder:\nName: {}\nID: {} ".format(file.get("name"), file_id)) return file_id + def upload_dir(self, input_directory, parent_id): list_dirs = os.listdir(input_directory) if len(list_dirs) == 0: @@ -518,6 +543,7 @@ class GoogleDriveHelper: break return new_id + def authorize(self): # Get credentials credentials = None @@ -543,6 +569,8 @@ class GoogleDriveHelper: f'accounts/{SERVICE_ACCOUNT_INDEX}.json', scopes=self.__OAUTH_SCOPE) return build('drive', 'v3', credentials=credentials, cache_discovery=False) + + def edit_telegraph(self): nxt_page = 1 prev_page = 0 @@ -564,12 +592,14 @@ class GoogleDriveHelper: html_content=content) return + def escapes(self, str): chars = ['\\', "'", '"', r'\a', r'\b', r'\f', r'\n', r'\r', r'\t'] for char in chars: str = str.replace(char, '\\'+char) return str + def drive_list(self, fileName): msg = "" fileName = self.escapes(str(fileName)) @@ -590,7 +620,7 @@ class GoogleDriveHelper: furl = f"https://drive.google.com/drive/folders/{file.get('id')}" msg += f"📁 {file.get('name')}
(folder)

" if SHORTENER is not None and SHORTENER_API is not None: - sfurl = requests.get(f'https://{SHORTENER}/api?api={SHORTENER_API}&url={furl}&format=text').text + sfurl = short_url(furl) msg += f"Drive Link" else: msg += f"Drive Link" @@ -598,7 +628,7 @@ class GoogleDriveHelper: url_path = requests.utils.quote(f'{file.get("name")}') url = f'{INDEX_URL}/{url_path}/' if SHORTENER is not None and SHORTENER_API is not None: - siurl = requests.get(f'https://{SHORTENER}/api?api={SHORTENER_API}&url={url}&format=text').text + siurl = short_url(url) msg += f' | Index Link' else: msg += f' | Index Link' @@ -610,7 +640,7 @@ class GoogleDriveHelper: furl = f"https://drive.google.com/uc?id={file.get('id')}&export=download" msg += f"📄 {file.get('name')}
({get_readable_file_size(int(file.get('size')))})

" if SHORTENER is not None and SHORTENER_API is not None: - sfurl = requests.get(f'https://{SHORTENER}/api?api={SHORTENER_API}&url={furl}&format=text').text + sfurl = short_url(furl) msg += f"Drive Link" else: msg += f"Drive Link" @@ -619,10 +649,10 @@ class GoogleDriveHelper: url = f'{INDEX_URL}/{url_path}' urls = f'{INDEX_URL}/{url_path}?a=view' if SHORTENER is not None and SHORTENER_API is not None: - siurl = requests.get(f'https://{SHORTENER}/api?api={SHORTENER_API}&url={url}&format=text').text - siurls = requests.get(f'https://{SHORTENER}/api?api={SHORTENER_API}&url={urls}&format=text').text + siurl = short_url(url) msg += f' | Index Link' if VIEW_LINK: + siurls = short_url(urls) msg += f' | View Link' else: msg += f' | Index Link' @@ -662,6 +692,7 @@ class GoogleDriveHelper: else : return '', '' + def count(self, link): try: file_id = self.getIdFromUrl(link) @@ -706,6 +737,7 @@ class GoogleDriveHelper: return msg return msg + def gDrive_file(self, **kwargs): try: size = int(kwargs['size']) @@ -713,6 +745,7 @@ class GoogleDriveHelper: size = 0 self.total_bytes += size + def gDrive_directory(self, **kwargs) -> None: files = self.getFilesByFolderId(kwargs['id']) if len(files) == 0: @@ -725,6 +758,7 @@ class GoogleDriveHelper: self.total_files += 1 self.gDrive_file(**file_) + def clonehelper(self, link): try: file_id = self.getIdFromUrl(link) @@ -757,6 +791,7 @@ class GoogleDriveHelper: return msg, "", "", "" return "", clonesize, name, files + def download(self, link): self.is_downloading = True file_id = self.getIdFromUrl(link) @@ -784,6 +819,7 @@ class GoogleDriveHelper: return self.__listener.onDownloadComplete() + def download_folder(self, folder_id, path, folder_name): if not os.path.exists(path + folder_name): os.makedirs(path + folder_name) @@ -819,6 +855,7 @@ class GoogleDriveHelper: if self.is_cancelled: break + def download_file(self, file_id, path, filename, mime_type): request = self.__service.files().get_media(fileId=file_id) fh = io.FileIO('{}{}'.format(path, filename), 'wb') @@ -850,13 +887,15 @@ class GoogleDriveHelper: raise err self._file_downloaded_bytes = 0 + def _on_download_progress(self): if self.dstatus is not None: chunk_size = self.dstatus.total_size * self.dstatus.progress() - self._file_downloaded_bytes self._file_downloaded_bytes = self.dstatus.total_size * self.dstatus.progress() self.downloaded_bytes += chunk_size self.dtotal_time += self.update_interval - + + def cancel_download(self): self.is_cancelled = True if self.is_downloading: @@ -865,5 +904,5 @@ class GoogleDriveHelper: elif self.is_cloning: LOGGER.info(f"Cancelling Clone: {self.name}") elif self.is_uploading: - LOGGER.info(f"Cancelling upload: {self.name}") + LOGGER.info(f"Cancelling Upload: {self.name}") self.__listener.onUploadError('your upload has been stopped and uploaded data has been deleted!') diff --git a/bot/modules/mirror.py b/bot/modules/mirror.py index 06f53c4..014a4d6 100644 --- a/bot/modules/mirror.py +++ b/bot/modules/mirror.py @@ -5,7 +5,7 @@ from telegram import InlineKeyboardMarkup from bot import Interval, INDEX_URL, BUTTON_FOUR_NAME, BUTTON_FOUR_URL, BUTTON_FIVE_NAME, BUTTON_FIVE_URL, BUTTON_SIX_NAME, BUTTON_SIX_URL, BLOCK_MEGA_FOLDER, BLOCK_MEGA_LINKS, VIEW_LINK, aria2, get_client from bot import dispatcher, DOWNLOAD_DIR, download_dict, download_dict_lock, SHORTENER, SHORTENER_API, TAR_UNZIP_LIMIT from bot.helper.ext_utils import fs_utils, bot_utils -from bot.helper.ext_utils.bot_utils import get_mega_link_type, check_limit +from bot.helper.ext_utils.shortenurl import short_url from bot.helper.ext_utils.exceptions import DirectDownloadLinkException, NotSupportedExtractionArchive from bot.helper.mirror_utils.download_utils.aria2_download import AriaDownloadHelper from bot.helper.mirror_utils.download_utils.mega_downloader import MegaDownloadHelper @@ -164,7 +164,7 @@ class MirrorListener(listeners.MirrorListeners): msg += f'\nType: {typ}' 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={link}&format=text').text + surl = short_url(link) buttons.buildbutton("☁️ Drive Link", surl) else: buttons.buildbutton("☁️ Drive Link", link) @@ -175,17 +175,17 @@ class MirrorListener(listeners.MirrorListeners): if os.path.isdir(f'{DOWNLOAD_DIR}/{self.uid}/{download_dict[self.uid].name()}'): share_url += '/' if SHORTENER is not None and SHORTENER_API is not None: - siurl = requests.get(f'https://{SHORTENER}/api?api={SHORTENER_API}&url={share_url}&format=text').text + siurl = short_url(share_url) buttons.buildbutton("⚡ Index Link", siurl) else: buttons.buildbutton("⚡ Index Link", share_url) else: share_urls = f'{INDEX_URL}/{url_path}?a=view' if SHORTENER is not None and SHORTENER_API is not None: - siurl = requests.get(f'https://{SHORTENER}/api?api={SHORTENER_API}&url={share_url}&format=text').text - siurls = requests.get(f'https://{SHORTENER}/api?api={SHORTENER_API}&url={share_urls}&format=text').text + siurl = short_url(share_url) buttons.buildbutton("⚡ Index Link", siurl) if VIEW_LINK: + siurls = short_url(share_urls) buttons.buildbutton("🌐 View Link", siurls) else: buttons.buildbutton("⚡ Index Link", share_url) @@ -335,7 +335,7 @@ def _mirror(bot, update, isTar=False, extract=False, isZip=False, isQbit=False): sendMessage(res, bot, update) return if TAR_UNZIP_LIMIT is not None: - result = check_limit(size, TAR_UNZIP_LIMIT) + result = bot_utils.check_limit(size, TAR_UNZIP_LIMIT) if result: msg = f'Failed, Tar/Unzip limit is {TAR_UNZIP_LIMIT}.\nYour File/Folder size is {get_readable_file_size(size)}.' sendMessage(msg, listener.bot, listener.update) @@ -350,11 +350,12 @@ def _mirror(bot, update, isTar=False, extract=False, isZip=False, isQbit=False): drive.download(link) elif bot_utils.is_mega_link(link): - link_type = get_mega_link_type(link) + if BLOCK_MEGA_LINKS: + sendMessage("Mega links are blocked!", bot, update) + return + link_type = bot_utils.get_mega_link_type(link) if link_type == "folder" and BLOCK_MEGA_FOLDER: sendMessage("Mega folder are blocked!", bot, update) - elif BLOCK_MEGA_LINKS: - sendMessage("Mega links are blocked!", bot, update) else: mega_dl = MegaDownloadHelper() mega_dl.add_download(link, f'{DOWNLOAD_DIR}{listener.uid}/', listener) diff --git a/requirements.txt b/requirements.txt index 2c78ca0..b30ae44 100644 --- a/requirements.txt +++ b/requirements.txt @@ -30,3 +30,4 @@ TgCrypto torrentool urllib3 youtube_dl +pyshorteners