Skip to content
This repository has been archived by the owner on Dec 4, 2023. It is now read-only.

Commit

Permalink
tar/unzip G-Drive Links (#220)
Browse files Browse the repository at this point in the history
* tar/unzip G-Drive Links

Signed-off-by: anas <[email protected]>

* Fix overall download speed for mega and others

Signed-off-by: anas <[email protected]>
  • Loading branch information
anasty17 authored Jun 19, 2021
1 parent 2c35781 commit d2173c9
Show file tree
Hide file tree
Showing 6 changed files with 207 additions and 11 deletions.
2 changes: 2 additions & 0 deletions bot/helper/ext_utils/bot_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,8 @@ def is_url(url: str):
return True
return False

def is_gdrive_link(url: str):
return "drive.google.com" in url

def is_mega_link(url: str):
return "mega.nz" in url
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,6 @@ def direct_link_generator(link: str):
raise DirectDownloadLinkException("`No links found!`")
elif 'youtube.com' in link or 'youtu.be' in link:
raise DirectDownloadLinkException(f"Youtube Link use /{BotCommands.WatchCommand} or /{BotCommands.TarWatchCommand}")
elif 'drive.google.com' in link:
raise DirectDownloadLinkException(f"G-Drive Link use /{BotCommands.CloneCommand}")
elif 'zippyshare.com' in link:
return zippy_share(link)
elif 'yadi.sk' in link:
Expand Down
61 changes: 61 additions & 0 deletions bot/helper/mirror_utils/status_utils/gdownload_status.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
from .status import Status
from bot.helper.ext_utils.bot_utils import MirrorStatus, get_readable_file_size, get_readable_time
from bot import DOWNLOAD_DIR


class DownloadStatus(Status):
def __init__(self, obj, size, listener, gid):
self.dobj = obj
self.__dsize = size
self.uid = listener.uid
self.message = listener.message
self.__dgid = gid

def path(self):
return f"{DOWNLOAD_DIR}{self.uid}"

def processed_bytes(self):
return self.dobj.downloaded_bytes

def size_raw(self):
return self.__dsize

def size(self):
return get_readable_file_size(self.__dsize)

def status(self):
return MirrorStatus.STATUS_DOWNLOADING

def name(self):
return self.dobj.name

def gid(self) -> str:
return self.__dgid

def progress_raw(self):
try:
return self.dobj.downloaded_bytes / self.__dsize * 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.dobj.dspeed()

def speed(self):
return f'{get_readable_file_size(self.speed_raw())}/s'

def eta(self):
try:
seconds = (self.__dsize - self.dobj.downloaded_bytes) / self.speed_raw()
return f'{get_readable_time(seconds)}'
except ZeroDivisionError:
return '-'

def download(self):
return self.dobj
116 changes: 115 additions & 1 deletion bot/helper/mirror_utils/upload_utils/gdriveTools.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import os
import io
import pickle
import urllib.parse as urlparse
from urllib.parse import parse_qs
Expand All @@ -13,7 +14,7 @@
from google_auth_oauthlib.flow import InstalledAppFlow
from googleapiclient.discovery import build
from googleapiclient.errors import HttpError
from googleapiclient.http import MediaFileUpload
from googleapiclient.http import MediaFileUpload, MediaIoBaseDownload
from tenacity import *

from telegram import InlineKeyboardMarkup
Expand Down Expand Up @@ -43,14 +44,18 @@ def __init__(self, name=None, listener=None):
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_cancelled = False
self.status = None
self.dstatus = None
self.updater = None
self.name = name
self.update_interval = 3
Expand All @@ -74,6 +79,12 @@ def speed(self):
except ZeroDivisionError:
return 0

def dspeed(self):
try:
return self.downloaded_bytes / self.dtotal_time
except ZeroDivisionError:
return 0

@staticmethod
def getIdFromUrl(link: str):
if "folders" in link or "file" in link:
Expand Down Expand Up @@ -728,3 +739,106 @@ def clonehelper(self, link):
return msg, "", ""
return "", clonesize, name

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)
path = f"{DOWNLOAD_DIR}{self.__listener.uid}/"
if meta.get("mimeType") == self.__G_DRIVE_DIR_MIME_TYPE:
self.download_folder(file_id, path, meta.get('name'))
else:
os.makedirs(path)
self.download_file(file_id, path, meta.get('name'), meta.get('mimeType'))
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)
self.is_cancelled = True
self.__listener.onDownloadError(err)
return
finally:
self.updater.cancel()
if self.is_cancelled:
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)
path += folder_name + '/'
result = []
page_token = None
while True:
files = self.__service.files().list(
supportsTeamDrives=True,
includeTeamDriveItems=True,
q=f"'{folder_id}' in parents",
fields='nextPageToken, files(id, name, mimeType, size, shortcutDetails)',
pageToken=page_token,
pageSize=1000).execute()
result.extend(files['files'])
page_token = files.get("nextPageToken")
if not page_token:
break

result = sorted(result, key=lambda k: k['name'])
for item in result:
file_id = item['id']
filename = item['name']
mime_type = item['mimeType']
shortcut_details = item.get('shortcutDetails', None)
if shortcut_details != None:
file_id = shortcut_details['targetId']
mime_type = shortcut_details['targetMimeType']
if mime_type == 'application/vnd.google-apps.folder':
self.download_folder(file_id, path, filename)
elif not os.path.isfile(path + filename):
self.download_file(file_id, path, filename, mime_type)
if self.is_cancelled:
break
return

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')
downloader = MediaIoBaseDownload(fh, request, chunksize = 50 * 1024 * 1024)
done = False
while done is False:
if self.is_cancelled:
fh.close()
break
return
try:
self.dstatus, done = downloader.next_chunk()
except HttpError as err:
if err.resp.get('content-type', '').startswith('application/json'):
reason = json.loads(err.content).get('error').get('errors')[0].get('reason')
if reason == 'userRateLimitExceeded' or reason == 'dailyLimitExceeded':
if USE_SERVICE_ACCOUNTS:
if not self.switchServiceAccount():
raise err
LOGGER.info(f"Got: {reason}, Trying Again...")
return self.download_file(file_id, path, filename, mime_type)
else:
raise err
else:
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
self.__listener.onDownloadError('Download stopped by user!')
8 changes: 4 additions & 4 deletions bot/helper/telegram_helper/message_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,9 @@ def update_all_messages():
for download in list(download_dict.values()):
speedy = download.speed()
if download.status() == MirrorStatus.STATUS_DOWNLOADING:
if 'KiB/s' in speedy:
if 'K' in speedy:
dlspeed_bytes += float(speedy.split('K')[0]) * 1024
elif 'MiB/s' in speedy:
elif 'M' in speedy:
dlspeed_bytes += float(speedy.split('M')[0]) * 1048576
if download.status() == MirrorStatus.STATUS_UPLOADING:
if 'KB/s' in speedy:
Expand Down Expand Up @@ -118,9 +118,9 @@ def sendStatusMessage(msg, bot):
for download in list(download_dict.values()):
speedy = download.speed()
if download.status() == MirrorStatus.STATUS_DOWNLOADING:
if 'KiB/s' in speedy:
if 'K' in speedy:
dlspeed_bytes += float(speedy.split('K')[0]) * 1024
elif 'MiB/s' in speedy:
elif 'M' in speedy:
dlspeed_bytes += float(speedy.split('M')[0]) * 1048576
if download.status() == MirrorStatus.STATUS_UPLOADING:
if 'KB/s' in speedy:
Expand Down
29 changes: 25 additions & 4 deletions bot/modules/mirror.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
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.status_utils.gdownload_status import DownloadStatus
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
Expand All @@ -26,6 +27,8 @@
import subprocess
import threading
import re
import random
import string

ariaDlManager = AriaDownloadHelper()
ariaDlManager.start_listener()
Expand Down Expand Up @@ -291,14 +294,32 @@ def _mirror(bot, update, isTar=False, extract=False):
if "ERROR:" in str(e):
sendMessage(f"{e}", bot, update)
return
if "G-Drive" in str(e):
sendMessage(f"ERROR: {e}", bot, update)
return
if "Youtube" in str(e):
sendMessage(f"ERROR: {e}", bot, update)
return

listener = MirrorListener(bot, update, pswd, isTar, tag, extract)
if bot_utils.is_mega_link(link):

if bot_utils.is_gdrive_link(link):
if not isTar and not extract:
sendMessage(f"Use /{BotCommands.CloneCommand} To Copy File/Folder", bot, update)
return
res, size, name = gdriveTools.GoogleDriveHelper().clonehelper(link)
if res != "":
sendMessage(res, bot, update)
return
LOGGER.info(f"Download Name : {name}")
drive = gdriveTools.GoogleDriveHelper(name, listener)
gid = ''.join(random.SystemRandom().choices(string.ascii_letters + string.digits, k=12))
download_status = DownloadStatus(drive, size, listener, gid)
with download_dict_lock:
download_dict[listener.uid] = download_status
if len(Interval) == 0:
Interval.append(setInterval(DOWNLOAD_STATUS_UPDATE_INTERVAL, update_all_messages))
sendStatusMessage(update, bot)
drive.download(link)

elif bot_utils.is_mega_link(link):
link_type = get_mega_link_type(link)
if link_type == "folder" and BLOCK_MEGA_FOLDER:
sendMessage("Mega folder are blocked!", bot, update)
Expand Down

0 comments on commit d2173c9

Please sign in to comment.