diff --git a/Dockerfile b/Dockerfile index 5ef3fce..2537f0e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,7 +5,8 @@ RUN chmod 777 /usr/src/app RUN apt-get -qq update && \ DEBIAN_FRONTEND="noninteractive" apt-get -qq install -y tzdata aria2 git python3 python3-pip \ locales python3-lxml \ - curl pv jq ffmpeg + curl pv jq ffmpeg \ + p7zip-full p7zip-rar COPY requirements.txt . RUN pip3 install --no-cache-dir -r requirements.txt && \ apt-get -qq purge git diff --git a/bot/__init__.py b/bot/__init__.py index 1f5cf40..3097979 100644 --- a/bot/__init__.py +++ b/bot/__init__.py @@ -54,7 +54,7 @@ status_reply_dict_lock = threading.Lock() # Value: telegram.Message status_reply_dict = {} # Key: update.message.message_id -# Value: An object of DownloadStatus +# Value: An object of Status download_dict = {} # Stores list of users and chats the bot is authorized to use in AUTHORIZED_CHATS = set() diff --git a/bot/__main__.py b/bot/__main__.py index 4140a3b..bc432bb 100644 --- a/bot/__main__.py +++ b/bot/__main__.py @@ -1,9 +1,10 @@ -import shutil +import shutil, psutil import signal import pickle from os import execl, path, remove from sys import executable +import time from telegram.ext import CommandHandler, run_async from bot import dispatcher, updater, botStartTime @@ -22,17 +23,24 @@ def stats(update, context): total = get_readable_file_size(total) used = get_readable_file_size(used) free = get_readable_file_size(free) + cpuUsage = psutil.cpu_percent(interval=0.5) + memory = psutil.virtual_memory().percent stats = f'Bot Uptime: {currentTime}\n' \ f'Total disk space: {total}\n' \ f'Used: {used}\n' \ - f'Free: {free}' + f'Free: {free}\n' \ + f'CPU: {cpuUsage}%\n' \ + f'RAM: {memory}%' sendMessage(stats, context.bot, update) @run_async def start(update, context): - sendMessage("This is a bot which can mirror all your links to Google drive!\n" - "Type /help to get a list of available commands", context.bot, update) + start_string = f''' +This is a bot which can mirror all your links to Google drive! +Type /{BotCommands.HelpCommand} to get a list of available commands +''' + sendMessage(start_string, context.bot, update) @run_async @@ -65,6 +73,8 @@ def bot_help(update, context): /{BotCommands.MirrorCommand} [download_url][magnet_link]: Start mirroring the link to google drive +/{BotCommands.UnzipMirrorCommand} [download_url][magnet_link] : starts mirroring and if downloaded file is any archive , extracts it to google drive + /{BotCommands.TarMirrorCommand} [download_url][magnet_link]: start mirroring and upload the archived (.tar) version of the download /{BotCommands.WatchCommand} [youtube-dl supported link]: Mirror through youtube-dl diff --git a/bot/helper/ext_utils/bot_utils.py b/bot/helper/ext_utils/bot_utils.py index 5998e53..56bc930 100644 --- a/bot/helper/ext_utils/bot_utils.py +++ b/bot/helper/ext_utils/bot_utils.py @@ -19,6 +19,7 @@ class MirrorStatus: STATUS_FAILED = "Failed. Cleaning download" STATUS_CANCELLED = "Cancelled" STATUS_ARCHIVING = "Archiving" + STATUS_EXTRACTING = "Extracting" PROGRESS_MAX_SIZE = 100 // 8 @@ -61,7 +62,9 @@ def get_readable_file_size(size_in_bytes) -> str: def getDownloadByGid(gid): with download_dict_lock: for dl in download_dict.values(): - if dl.status() != MirrorStatus.STATUS_UPLOADING and dl.status() != MirrorStatus.STATUS_ARCHIVING: + status = dl.status() + if status != MirrorStatus.STATUS_UPLOADING and status != MirrorStatus.STATUS_ARCHIVING\ + and status != MirrorStatus.STATUS_EXTRACTING: if dl.gid() == gid: return dl return None @@ -91,7 +94,7 @@ def get_readable_message(): for download in list(download_dict.values()): msg += f"{download.name()} - " msg += download.status() - if download.status() != MirrorStatus.STATUS_ARCHIVING: + if download.status() != MirrorStatus.STATUS_ARCHIVING and download.status() != MirrorStatus.STATUS_EXTRACTING: msg += f"\n{get_progress_bar_string(download)} {download.progress()} of " \ f"{download.size()}" \ f" at {download.speed()}, ETA: {download.eta()} " @@ -140,8 +143,10 @@ def new_thread(fn): """To use as decorator to make a function call threaded. Needs import from threading import Thread""" + def wrapper(*args, **kwargs): thread = threading.Thread(target=fn, args=args, kwargs=kwargs) thread.start() return thread - return wrapper \ No newline at end of file + + return wrapper diff --git a/bot/helper/ext_utils/exceptions.py b/bot/helper/ext_utils/exceptions.py index 25ff87f..a2f600c 100644 --- a/bot/helper/ext_utils/exceptions.py +++ b/bot/helper/ext_utils/exceptions.py @@ -1,2 +1,8 @@ class DirectDownloadLinkException(Exception): + """Not method found for extracting direct download link from the http link""" + pass + + +class NotSupportedExtractionArchive(Exception): + """The archive format use is trying to extract is not supported""" pass diff --git a/bot/helper/ext_utils/fs_utils.py b/bot/helper/ext_utils/fs_utils.py index 0b92aa0..cbf50b2 100644 --- a/bot/helper/ext_utils/fs_utils.py +++ b/bot/helper/ext_utils/fs_utils.py @@ -5,6 +5,7 @@ import os import pathlib import magic import tarfile +from .exceptions import NotSupportedExtractionArchive def clean_download(path: str): @@ -56,6 +57,33 @@ def tar(org_path): return tar_path +def get_base_name(orig_path: str): + if orig_path.endswith(".tar.bz2"): + return orig_path.replace(".tar.bz2", "") + elif orig_path.endswith(".tar.gz"): + return orig_path.replace(".tar.gz", "") + elif orig_path.endswith(".bz2"): + return orig_path.replace(".bz2", "") + elif orig_path.endswith(".gz"): + return orig_path.replace(".gz", "") + elif orig_path.endswith(".tar"): + return orig_path.replace(".tar", "") + elif orig_path.endswith(".tbz2"): + return orig_path.replace("tbz2", "") + elif orig_path.endswith(".tgz"): + return orig_path.replace(".tgz", "") + elif orig_path.endswith(".zip"): + return orig_path.replace(".zip", "") + elif orig_path.endswith(".7z"): + return orig_path.replace(".7z", "") + elif orig_path.endswith(".Z"): + return orig_path.replace(".Z", "") + elif orig_path.endswith(".rar"): + return orig_path.replace(".rar", "") + else: + raise NotSupportedExtractionArchive('File format not supported for extraction') + + def get_mime_type(file_path): mime = magic.Magic(mime=True) mime_type = mime.from_file(file_path) diff --git a/bot/helper/mirror_utils/download_utils/aria2_download.py b/bot/helper/mirror_utils/download_utils/aria2_download.py index 9473e46..a610f81 100644 --- a/bot/helper/mirror_utils/download_utils/aria2_download.py +++ b/bot/helper/mirror_utils/download_utils/aria2_download.py @@ -24,9 +24,10 @@ class AriaDownloadHelper(DownloadHelper): download = api.get_download(gid) if download.followed_by_ids: new_gid = download.followed_by_ids[0] + new_download = api.get_download(new_gid) with download_dict_lock: download_dict[dl.uid()] = AriaDownloadStatus(new_gid, dl.getListener()) - if download.is_torrent: + if new_download.is_torrent: download_dict[dl.uid()].is_torrent = True update_all_messages() LOGGER.info(f'Changed gid from {gid} to {new_gid}') @@ -62,15 +63,16 @@ class AriaDownloadHelper(DownloadHelper): on_download_stop=self.__onDownloadStopped, on_download_complete=self.__onDownloadComplete) - def add_download(self, link: str, path, listener): + + def add_download(self, link: str, path,listener): if is_magnet(link): download = aria2.add_magnet(link, {'dir': path}) else: download = aria2.add_uris([link], {'dir': path}) - if download.error_message: # no need to proceed further at this point listener.onDownloadError(download.error_message) return with download_dict_lock: download_dict[listener.uid] = AriaDownloadStatus(download.gid, listener) LOGGER.info(f"Started: {download.gid} DIR:{download.dir} ") + diff --git a/bot/helper/mirror_utils/status_utils/aria_download_status.py b/bot/helper/mirror_utils/status_utils/aria_download_status.py index c3199f7..ef04a79 100644 --- a/bot/helper/mirror_utils/status_utils/aria_download_status.py +++ b/bot/helper/mirror_utils/status_utils/aria_download_status.py @@ -20,6 +20,7 @@ class AriaDownloadStatus(Status): self.message = listener.message self.last = None self.is_waiting = False + self.is_extracting = False def __update(self): self.__download = get_download(self.__gid) diff --git a/bot/helper/mirror_utils/status_utils/extract_status.py b/bot/helper/mirror_utils/status_utils/extract_status.py new file mode 100644 index 0000000..41b6ff5 --- /dev/null +++ b/bot/helper/mirror_utils/status_utils/extract_status.py @@ -0,0 +1,36 @@ +from .status import Status +from bot.helper.ext_utils.bot_utils import get_readable_file_size, MirrorStatus + + +class ExtractStatus(Status): + def __init__(self, name, path, size): + self.__name = name + self.__path = path + self.__size = size + + # The progress of extract function cannot be tracked. So we just return dummy values. + # If this is possible in future,we should implement it + + def progress(self): + return '0' + + def speed(self): + return '0' + + def name(self): + return self.__name + + def path(self): + return self.__path + + def size(self): + return get_readable_file_size(self.__size) + + def eta(self): + return '0s' + + def status(self): + return MirrorStatus.STATUS_EXTRACTING + + def processed_bytes(self): + return 0 diff --git a/bot/helper/mirror_utils/upload_utils/gdriveTools.py b/bot/helper/mirror_utils/upload_utils/gdriveTools.py index 0fe2f19..554c789 100644 --- a/bot/helper/mirror_utils/upload_utils/gdriveTools.py +++ b/bot/helper/mirror_utils/upload_utils/gdriveTools.py @@ -289,46 +289,32 @@ class GoogleDriveHelper: msg = "" LOGGER.info(f"File ID: {file_id}") try: - meta = self.__service.files().get(supportsAllDrives=True, fileId=file_id, - fields="name,id,mimeType,size").execute() - except Exception as e: - return f"{str(e).replace('>', '').replace('<', '')}" - if meta.get("mimeType") == self.__G_DRIVE_DIR_MIME_TYPE: - dir_id = self.create_directory(meta.get('name'), parent_id) - try: + meta = self.getFileMetadata(file_id) + if meta.get("mimeType") == self.__G_DRIVE_DIR_MIME_TYPE: + dir_id = self.create_directory(meta.get('name'), parent_id) result = self.cloneFolder(meta.get('name'), meta.get('name'), meta.get('id'), dir_id) - except Exception as e: - if isinstance(e, RetryError): - LOGGER.info(f"Total Attempts: {e.last_attempt.attempt_number}") - err = e.last_attempt.exception() - else: - err = str(e).replace('>', '').replace('<', '') - LOGGER.error(err) - return err - msg += f'{meta.get("name")}' \ - f' ({get_readable_file_size(self.transferred_size)})' - if INDEX_URL is not None: - url = requests.utils.requote_uri(f'{INDEX_URL}/{meta.get("name")}/') - msg += f' | Index URL' - else: - try: - file = self.copyFile(meta.get('id'), parent_id) - except Exception as e: - if isinstance(e, RetryError): - LOGGER.info(f"Total Attempts: {e.last_attempt.attempt_number}") - err = e.last_attempt.exception() - else: - err = str(e).replace('>', '').replace('<', '') - LOGGER.error(err) - return err - msg += f'{file.get("name")}' - try: - msg += f' ({get_readable_file_size(int(meta.get("size")))}) ' + msg += f'{meta.get("name")}' \ + f' ({get_readable_file_size(self.transferred_size)})' if INDEX_URL is not None: - url = requests.utils.requote_uri(f'{INDEX_URL}/{file.get("name")}') + url = requests.utils.requote_uri(f'{INDEX_URL}/{meta.get("name")}/') msg += f' | Index URL' - except TypeError: - pass + else: + file = self.copyFile(meta.get('id'), parent_id) + msg += f'{file.get("name")}' + try: + msg += f' ({get_readable_file_size(int(meta.get("size")))}) ' + except TypeError: + pass + if INDEX_URL is not None: + url = requests.utils.requote_uri(f'{INDEX_URL}/{file.get("name")}') + msg += f' | Index URL' + except Exception as err: + if isinstance(err, RetryError): + LOGGER.info(f"Total Attempts: {err.last_attempt.attempt_number}") + err = err.last_attempt.exception() + err = str(err).replace('>', '').replace('<', '') + LOGGER.error(err) + return err return msg def cloneFolder(self, name, local_path, folder_id, parent_id): @@ -421,8 +407,15 @@ class GoogleDriveHelper: scopes=self.__OAUTH_SCOPE) return build('drive', 'v3', credentials=credentials, cache_discovery=False) + 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)) # Create Search Query for API request. query = f"'{parent_id}' in parents and (name contains '{fileName}')" response = self.__service.files().list(supportsTeamDrives=True, diff --git a/bot/helper/telegram_helper/bot_commands.py b/bot/helper/telegram_helper/bot_commands.py index fee3fa2..bd1af0c 100644 --- a/bot/helper/telegram_helper/bot_commands.py +++ b/bot/helper/telegram_helper/bot_commands.py @@ -2,6 +2,7 @@ class _BotCommands: def __init__(self): self.StartCommand = 'start' self.MirrorCommand = 'mirror' + self.UnzipMirrorCommand = 'unzipmirror' self.TarMirrorCommand = 'tarmirror' self.CancelMirror = 'cancel' self.CancelAllCommand = 'cancelall' diff --git a/bot/helper/telegram_helper/filters.py b/bot/helper/telegram_helper/filters.py index a65445f..3cd3c93 100644 --- a/bot/helper/telegram_helper/filters.py +++ b/bot/helper/telegram_helper/filters.py @@ -1,5 +1,6 @@ from telegram.ext import BaseFilter -from bot import AUTHORIZED_CHATS, OWNER_ID +from telegram import Message +from bot import AUTHORIZED_CHATS, OWNER_ID, download_dict, download_dict_lock class CustomFilters: @@ -21,3 +22,22 @@ class CustomFilters: return bool(message.chat.id in AUTHORIZED_CHATS) authorized_chat = _AuthorizedChat() + + class _MirrorOwner(BaseFilter): + def filter(self, message: Message): + user_id = message.from_user.id + if user_id == OWNER_ID: + return True + args = str(message.text).split(' ') + if len(args) > 1: + # Cancelling by gid + with download_dict_lock: + for message_id, status in download_dict.items(): + if status.gid() == args[1] and status.message.from_user.id == user_id: + return True + else: + return False + # Cancelling by replying to original mirror message + reply_user = message.reply_to_message.from_user.id + return bool(reply_user == user_id) + mirror_owner_filter = _MirrorOwner() diff --git a/bot/helper/telegram_helper/message_utils.py b/bot/helper/telegram_helper/message_utils.py index bc209dd..9d3eb02 100644 --- a/bot/helper/telegram_helper/message_utils.py +++ b/bot/helper/telegram_helper/message_utils.py @@ -9,9 +9,12 @@ from bot import bot def sendMessage(text: str, bot, update: Update): - return bot.send_message(update.message.chat_id, + try: + return bot.send_message(update.message.chat_id, reply_to_message_id=update.message.message_id, text=text, parse_mode='HTMl') + except Exception as e: + LOGGER.error(str(e)) def editMessage(text: str, message: Message): @@ -19,9 +22,8 @@ def editMessage(text: str, message: Message): bot.edit_message_text(text=text, message_id=message.message_id, chat_id=message.chat.id, parse_mode='HTMl') - except TimedOut as e: + except Exception as e: LOGGER.error(str(e)) - pass def deleteMessage(bot, message: Message): @@ -56,10 +58,8 @@ def delete_all_messages(): try: deleteMessage(bot, message) del status_reply_dict[message.chat.id] - except BadRequest as e: - LOGGER.info(str(e)) - del status_reply_dict[message.chat.id] - pass + except Exception as e: + LOGGER.error(str(e)) def update_all_messages(): @@ -69,7 +69,7 @@ def update_all_messages(): if status_reply_dict[chat_id] and msg != status_reply_dict[chat_id].text: try: editMessage(msg, status_reply_dict[chat_id]) - except BadRequest as e: + except Exception as e: LOGGER.error(str(e)) status_reply_dict[chat_id].text = msg diff --git a/bot/modules/cancel_mirror.py b/bot/modules/cancel_mirror.py index c25c460..a4d2d74 100644 --- a/bot/modules/cancel_mirror.py +++ b/bot/modules/cancel_mirror.py @@ -11,14 +11,14 @@ from bot.helper.ext_utils.bot_utils import getDownloadByGid, MirrorStatus @run_async -def cancel_mirror(update,context): - args = update.message.text.split(" ",maxsplit=1) +def cancel_mirror(update, context): + args = update.message.text.split(" ", maxsplit=1) mirror_message = None if len(args) > 1: gid = args[1] dl = getDownloadByGid(gid) if not dl: - sendMessage(f"GID: {gid} not found.",context.bot,update) + sendMessage(f"GID: {gid} not found.", context.bot, update) return with download_dict_lock: keys = list(download_dict.keys()) @@ -33,11 +33,11 @@ def cancel_mirror(update,context): if BotCommands.MirrorCommand in mirror_message.text or \ BotCommands.TarMirrorCommand in mirror_message.text: msg = "Mirror already have been cancelled" - sendMessage(msg,context.bot,update) + sendMessage(msg, context.bot, update) return else: msg = "Please reply to the /mirror message which was used to start the download or /cancel gid to cancel it!" - sendMessage(msg,context.bot,update) + sendMessage(msg, context.bot, update) return if dl.status() == "Uploading": sendMessage("Upload in Progress, Don't Cancel it.", context.bot, update) @@ -56,16 +56,16 @@ def cancel_all(update, context): with download_dict_lock: count = 0 for dlDetails in list(download_dict.values()): - if dlDetails.status() == MirrorStatus.STATUS_DOWNLOADING\ + if dlDetails.status() == MirrorStatus.STATUS_DOWNLOADING \ or dlDetails.status() == MirrorStatus.STATUS_WAITING: dlDetails.download().cancel_download() count += 1 delete_all_messages() - sendMessage(f'Cancelled {count} downloads!', context.bot,update) + sendMessage(f'Cancelled {count} downloads!', context.bot, update) cancel_mirror_handler = CommandHandler(BotCommands.CancelMirror, cancel_mirror, - filters=CustomFilters.authorized_chat | CustomFilters.authorized_user) + filters=(CustomFilters.authorized_chat | CustomFilters.authorized_user) & CustomFilters.mirror_owner_filter) cancel_all_handler = CommandHandler(BotCommands.CancelAllCommand, cancel_all, filters=CustomFilters.owner_filter) dispatcher.add_handler(cancel_all_handler) diff --git a/bot/modules/mirror.py b/bot/modules/mirror.py index a69c8d4..8bdb8d7 100644 --- a/bot/modules/mirror.py +++ b/bot/modules/mirror.py @@ -1,35 +1,36 @@ import requests from telegram.ext import CommandHandler, run_async -from bot import Interval, INDEX_URL +from bot import Interval, INDEX_URL,LOGGER from bot import dispatcher, DOWNLOAD_DIR, DOWNLOAD_STATUS_UPDATE_INTERVAL, download_dict, download_dict_lock from bot.helper.ext_utils import fs_utils, bot_utils from bot.helper.ext_utils.bot_utils import setInterval -from bot.helper.ext_utils.exceptions import DirectDownloadLinkException +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.direct_link_generator import direct_link_generator from bot.helper.mirror_utils.download_utils.telegram_downloader import TelegramDownloadHelper from bot.helper.mirror_utils.status_utils import listeners +from bot.helper.mirror_utils.status_utils.extract_status import ExtractStatus from bot.helper.mirror_utils.status_utils.tar_status import TarStatus from bot.helper.mirror_utils.status_utils.upload_status import UploadStatus from bot.helper.mirror_utils.upload_utils import gdriveTools from bot.helper.telegram_helper.bot_commands import BotCommands from bot.helper.telegram_helper.filters import CustomFilters from bot.helper.telegram_helper.message_utils import * -from bot.helper.mirror_utils.download_utils.youtube_dl_download_helper import YoutubeDLHelper import pathlib import os +import subprocess +import threading ariaDlManager = AriaDownloadHelper() ariaDlManager.start_listener() - class MirrorListener(listeners.MirrorListeners): - - def __init__(self, bot, update, isTar=False, tag=None): + def __init__(self, bot, update, isTar=False,tag=None, extract=False): super().__init__(bot, update) self.isTar = isTar self.tag = tag + self.extract = extract def onDownloadStarted(self): pass @@ -63,8 +64,31 @@ class MirrorListener(listeners.MirrorListeners): LOGGER.info('File to archive not found!') self.onUploadError('Internal error occurred!!') return + elif self.extract: + download.is_extracting = True + try: + path = fs_utils.get_base_name(m_path) + LOGGER.info( + f"Extracting : {name} " + ) + with download_dict_lock: + download_dict[self.uid] = ExtractStatus(name, m_path, size) + archive_result = subprocess.run(["extract", m_path]) + if archive_result.returncode == 0: + threading.Thread(target=os.remove, args=(m_path,)).start() + LOGGER.info(f"Deleting archive : {m_path}") + else: + LOGGER.warning('Unable to extract archive! Uploading anyway') + path = f'{DOWNLOAD_DIR}{self.uid}/{name}' + LOGGER.info( + f'got path : {path}' + ) + + except NotSupportedExtractionArchive: + LOGGER.info("Not any valid archive, uploading file as it is.") + path = f'{DOWNLOAD_DIR}{self.uid}/{name}' else: - path = f'{DOWNLOAD_DIR}{self.uid}/{download_dict[self.uid].name()}' + path = f'{DOWNLOAD_DIR}{self.uid}/{name}' up_name = pathlib.PurePath(path).name LOGGER.info(f"Upload Name : {up_name}") drive = gdriveTools.GoogleDriveHelper(up_name, self) @@ -132,7 +156,7 @@ class MirrorListener(listeners.MirrorListeners): update_all_messages() def onUploadError(self, error): - e_str = str(error.last_attempt.exception()).replace('<', '').replace('>', '') + e_str = error.replace('<', '').replace('>', '') with download_dict_lock: try: fs_utils.clean_download(download_dict[self.uid].path()) @@ -146,8 +170,7 @@ class MirrorListener(listeners.MirrorListeners): else: update_all_messages() - -def _mirror(bot, update, isTar=False): +def _mirror(bot, update, isTar=False, extract=False): message_args = update.message.text.split(' ') try: link = message_args[1] @@ -187,7 +210,8 @@ def _mirror(bot, update, isTar=False): link = direct_link_generator(link) except DirectDownloadLinkException as e: LOGGER.info(f'{link}: {e}') - listener = MirrorListener(bot, update, isTar, tag) + + listener = MirrorListener(bot, update, isTar, tag, extract) ariaDlManager.add_download(link, f'{DOWNLOAD_DIR}/{listener.uid}/',listener) sendStatusMessage(update, bot) if len(Interval) == 0: @@ -204,9 +228,17 @@ def tar_mirror(update, context): _mirror(context.bot, update, True) +@run_async +def unzip_mirror(update, context): + _mirror(context.bot,update, extract=True) + + mirror_handler = CommandHandler(BotCommands.MirrorCommand, mirror, filters=CustomFilters.authorized_chat | CustomFilters.authorized_user) tar_mirror_handler = CommandHandler(BotCommands.TarMirrorCommand, tar_mirror, filters=CustomFilters.authorized_chat | CustomFilters.authorized_user) +unzip_mirror_handler = CommandHandler(BotCommands.UnzipMirrorCommand, unzip_mirror, + filters=CustomFilters.authorized_chat | CustomFilters.authorized_user) dispatcher.add_handler(mirror_handler) dispatcher.add_handler(tar_mirror_handler) +dispatcher.add_handler(unzip_mirror_handler) diff --git a/extract b/extract new file mode 100755 index 0000000..da9847b --- /dev/null +++ b/extract @@ -0,0 +1,69 @@ +#!/bin/bash + +if [ $# -lt 1 ]; then + echo "Usage: $(basename $0) FILES" + exit 1 +fi + +extract() { + arg="$1" + cd "$(dirname "$arg")" || exit + case "$arg" in + *.tar.bz2) + tar xjf "$arg" --one-top-level + local code=$? + ;; + *.tar.gz) + tar xzf "$arg" --one-top-level + local code=$? + ;; + *.bz2) + bunzip2 "$arg" + local code=$? + ;; + *.gz) + gunzip "$arg" + local code=$? + ;; + *.tar) + tar xf "$arg" --one-top-level + local code=$? + ;; + *.tbz2) + (tar xjf "$arg" --one-top-level) + local code=$? + ;; + *.tgz) + tar xzf "$arg" --one-top-level + local code=$? + ;; + *.zip) + a_dir=$(expr "$arg" : '\(.*\).zip') + 7z x "$arg" -o"$a_dir" + local code=$? + ;; + *.7z) + a_dir=$(expr "$arg" : '\(.*\).7z') + 7z x "$arg" -o"$a_dir" + local code=$? + ;; + *.Z) + uncompress "$arg" + local code=$? + ;; + *.rar) + a_dir=$(expr "$arg" : '\(.*\).rar') + mkdir "$a_dir" + 7z x "$arg" -o"$a_dir" + local code=$? + ;; + *) + echo "'$arg' cannot be extracted via extract()" 1>&2 + exit 1 + ;; + esac + cd - || exit $? + exit $code +} + +extract "$1" \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 078a15e..9a915ff 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,5 @@ requests +psutil python-telegram-bot==12.6.1 google-api-python-client>=1.7.11,<1.7.20 google-auth-httplib2>=0.0.3,<0.1.0