diff --git a/Dockerfile b/Dockerfile
index e6e8ba0..4aac024 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,8 +1,10 @@
-FROM breakdowns/mega-sdk-python:latest
+FROM anasty17/megasdk:latest
WORKDIR /usr/src/app
RUN chmod 777 /usr/src/app
+RUN apt-get install -y xz-utils neofetch unzip && apt-get autoremove -y
+
COPY requirements.txt .
RUN pip3 install --no-cache-dir -r requirements.txt
diff --git a/alive.py b/alive.py
new file mode 100644
index 0000000..ee1273a
--- /dev/null
+++ b/alive.py
@@ -0,0 +1,11 @@
+import time
+import requests
+import os
+from dotenv import load_dotenv
+
+load_dotenv('config.env')
+
+url = os.environ.get("BASE_URL_OF_BOT")
+while True:
+ time.sleep(1000)
+ status = requests.get(url).status_code
diff --git a/aria.sh b/aria.sh
index e293d30..506ee19 100755
--- a/aria.sh
+++ b/aria.sh
@@ -1,15 +1,10 @@
-export MAX_DOWNLOAD_SPEED=0
-tracker_list=$(curl -Ns https://raw.githubusercontent.com/XIU2/TrackersListCollection/master/all.txt https://ngosang.github.io/trackerslist/trackers_all_http.txt https://raw.githubusercontent.com/DeSireFire/animeTrackerList/master/AT_all.txt https://raw.githubusercontent.com/hezhijie0327/Trackerslist/main/trackerslist_combine.txt | awk '$0' | tr '\n' ',')
-export MAX_CONCURRENT_DOWNLOADS=7
-
-aria2c --enable-rpc --rpc-listen-all=false --check-certificate=false \
+aria2c --enable-rpc --check-certificate=false \
--max-connection-per-server=10 --rpc-max-request-size=1024M \
- --bt-tracker="[$tracker_list]" --bt-max-peers=0 --bt-tracker-connect-timeout=300 --bt-stop-timeout=1200 --min-split-size=10M \
- --follow-torrent=mem --split=10 \
- --daemon=true --allow-overwrite=true --max-overall-download-limit=$MAX_DOWNLOAD_SPEED \
- --max-overall-upload-limit=1K --max-concurrent-downloads=$MAX_CONCURRENT_DOWNLOADS \
+ --bt-stop-timeout=1200 --min-split-size=10M --follow-torrent=mem --split=10 \
+ --daemon=true --allow-overwrite=true --max-overall-download-limit=0 \
+ --max-overall-upload-limit=1K --max-concurrent-downloads=15 --continue=true \
--peer-id-prefix=-qB4360- --user-agent=qBittorrent/4.3.6 --peer-agent=qBittorrent/4.3.6 \
- --disk-cache=64M --file-allocation=prealloc --continue=true \
- --max-file-not-found=0 --max-tries=20 --auto-file-renaming=true \
- --bt-enable-lpd=true --seed-time=0.01 --seed-ratio=1.0 \
- --content-disposition-default-utf8=true --http-accept-gzip=true --reuse-uri=true --netrc-path=/usr/src/app/.netrc
+ --disk-cache=64M --bt-enable-lpd=true --seed-time=0 --max-file-not-found=0 \
+ --max-tries=20 --auto-file-renaming=true --reuse-uri=true --http-accept-gzip=true \
+ --content-disposition-default-utf8=true --netrc-path=/usr/src/app/.netrc
+
diff --git a/bot/__init__.py b/bot/__init__.py
index 80881fc..7dbaeb8 100644
--- a/bot/__init__.py
+++ b/bot/__init__.py
@@ -6,6 +6,7 @@
import string
import aria2p
+import qbittorrentapi as qba
import telegram.ext as tg
from dotenv import load_dotenv
from pyrogram import Client
@@ -66,6 +67,18 @@ def mktable():
)
)
+
+def get_client() -> qba.TorrentsAPIMixIn:
+ qb_client = qba.Client(host="localhost", port=8090, username="admin", password="adminadmin")
+ try:
+ qb_client.auth_log_in()
+ qb_client.application.set_preferences({"disk_cache":64, "incomplete_files_ext":True, "max_connec":3000, "max_connec_per_torrent":300, "async_io_thread":32})
+ return qb_client
+ except qba.LoginFailed as e:
+ LOGGER.error(str(e))
+ return None
+
+
DOWNLOAD_DIR = None
BOT_TOKEN = None
@@ -313,6 +326,31 @@ def mktable():
except KeyError:
pass
+try:
+ BASE_URL = getConfig('BASE_URL_OF_BOT')
+ if len(BASE_URL) == 0:
+ BASE_URL = None
+except KeyError:
+ logging.warning('BASE_URL_OF_BOT not provided!')
+ BASE_URL = None
+
+try:
+ IS_VPS = getConfig('IS_VPS')
+ if IS_VPS.lower() == 'true':
+ IS_VPS = True
+ else:
+ IS_VPS = False
+except KeyError:
+ IS_VPS = False
+
+try:
+ SERVER_PORT = getConfig('SERVER_PORT')
+ if len(SERVER_PORT) == 0:
+ SERVER_PORT = None
+except KeyError:
+ logging.warning('SERVER_PORT not provided!')
+ SERVER_PORT = None
+
updater = tg.Updater(token=BOT_TOKEN)
bot = updater.bot
dispatcher = updater.dispatcher
diff --git a/bot/__main__.py b/bot/__main__.py
index a6cb1f7..0311e02 100644
--- a/bot/__main__.py
+++ b/bot/__main__.py
@@ -1,6 +1,7 @@
import shutil, psutil
import signal
import os
+import asyncio
from pyrogram import idle
from bot import app
@@ -8,7 +9,8 @@
from telegram import ParseMode
from telegram.ext import CommandHandler
-from bot import bot, dispatcher, updater, botStartTime, IGNORE_PENDING_REQUESTS
+from wserver import start_server_async
+from bot import bot, dispatcher, updater, botStartTime, IGNORE_PENDING_REQUESTS, IS_VPS, SERVER_PORT
from bot.helper.ext_utils import fs_utils
from bot.helper.telegram_helper.bot_commands import BotCommands
from bot.helper.telegram_helper.message_utils import *
@@ -201,6 +203,10 @@ def bot_help(update, context):
def main():
fs_utils.start_cleanup()
+
+ if IS_VPS:
+ asyncio.get_event_loop().run_until_complete(start_server_async(SERVER_PORT))
+
# Check if the bot is restarting
if os.path.isfile(".restartmsg"):
with open(".restartmsg") as f:
diff --git a/bot/helper/ext_utils/bot_utils.py b/bot/helper/ext_utils/bot_utils.py
index 81fb3c5..6a080c4 100644
--- a/bot/helper/ext_utils/bot_utils.py
+++ b/bot/helper/ext_utils/bot_utils.py
@@ -26,6 +26,7 @@ class MirrorStatus:
STATUS_CLONING = "Cloning...♻️"
STATUS_WAITING = "Queued...📝"
STATUS_FAILED = "Failed 🚫. Cleaning Download..."
+ STATUS_PAUSE = "Paused...⭕️"
STATUS_ARCHIVING = "Archiving...🔐"
STATUS_EXTRACTING = "Extracting...📂"
@@ -76,6 +77,7 @@ def getDownloadByGid(gid):
return dl
return None
+
def getAllDownload():
with download_dict_lock:
for dlDetails in list(download_dict.values()):
@@ -84,6 +86,7 @@ def getAllDownload():
return dlDetails
return None
+
def get_progress_bar_string(status):
completed = status.processed_bytes() / 8
total = status.size_raw() / 8
@@ -134,6 +137,11 @@ def get_readable_message():
f" | Peers: {download.aria_download().connections}"
except:
pass
+ try:
+ msg += f"\nSeeders: {download.torrent_info().num_seeds}" \
+ f" | Leechers: {download.torrent_info().num_leechs}"
+ except:
+ pass
msg += f"\nTo Stop: /{BotCommands.CancelMirror} {download.gid()}
"
msg += "\n\n"
if STATUS_LIMIT is not None:
@@ -151,6 +159,7 @@ def get_readable_message():
return msg, button
return msg, ""
+
def flip(update, context):
query = update.callback_query
query.answer()
@@ -171,6 +180,7 @@ def flip(update, context):
PAGE_NO -= 1
message_utils.update_all_messages()
+
def get_readable_time(seconds: int) -> str:
result = ''
(days, remainder) = divmod(seconds, 86400)
@@ -196,12 +206,15 @@ 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 or "mega.co.nz" in url
+
def get_mega_link_type(url: str):
if "folder" in url:
return "folder"
@@ -211,12 +224,14 @@ def get_mega_link_type(url: str):
return "folder"
return "file"
+
def is_magnet(url: str):
magnet = re.findall(MAGNET_REGEX, url)
if magnet:
return True
return False
+
def new_thread(fn):
"""To use as decorator to make a function call threaded.
Needs import
@@ -229,6 +244,7 @@ def wrapper(*args, **kwargs):
return wrapper
+
next_handler = CallbackQueryHandler(flip, pattern="nex", run_async=True)
previous_handler = CallbackQueryHandler(flip, pattern="pre", run_async=True)
dispatcher.add_handler(next_handler)
diff --git a/bot/helper/ext_utils/fs_utils.py b/bot/helper/ext_utils/fs_utils.py
index ce54ac0..32b7849 100644
--- a/bot/helper/ext_utils/fs_utils.py
+++ b/bot/helper/ext_utils/fs_utils.py
@@ -1,5 +1,5 @@
import sys
-from bot import aria2, LOGGER, DOWNLOAD_DIR
+from bot import aria2, LOGGER, DOWNLOAD_DIR, get_client
import shutil
import os
import pathlib
@@ -23,6 +23,7 @@ def start_cleanup():
def clean_all():
aria2.remove_all(True)
+ get_client().torrents_delete(torrent_hashes="all", delete_files=True)
try:
shutil.rmtree(DOWNLOAD_DIR)
except FileNotFoundError:
diff --git a/bot/helper/mirror_utils/download_utils/mega_downloader.py b/bot/helper/mirror_utils/download_utils/mega_downloader.py
index edf2700..8f4778a 100644
--- a/bot/helper/mirror_utils/download_utils/mega_downloader.py
+++ b/bot/helper/mirror_utils/download_utils/mega_downloader.py
@@ -177,6 +177,7 @@ def add_download(mega_link: str, path: str, listener):
if smsg:
msg1 = "File/Folder is already available in Drive.\nHere are the search results:"
sendMarkup(msg1, listener.bot, listener.update, button)
+ executor.continue_event.set()
return
if MEGA_LIMIT is not None or TAR_UNZIP_LIMIT is not None:
limit = None
@@ -193,10 +194,12 @@ def add_download(mega_link: str, path: str, listener):
if 'G' in limit[1] or 'g' in limit[1]:
if api.getSize(node) > limitint * 1024**3:
sendMessage(msg3, listener.bot, listener.update)
+ executor.continue_event.set()
return
elif 'T' in limit[1] or 't' in limit[1]:
if api.getSize(node) > limitint * 1024**4:
sendMessage(msg3, listener.bot, listener.update)
+ executor.continue_event.set()
return
with download_dict_lock:
download_dict[listener.uid] = MegaDownloadStatus(mega_listener, listener)
diff --git a/bot/helper/mirror_utils/download_utils/qbit_downloader.py b/bot/helper/mirror_utils/download_utils/qbit_downloader.py
new file mode 100644
index 0000000..f1f6f41
--- /dev/null
+++ b/bot/helper/mirror_utils/download_utils/qbit_downloader.py
@@ -0,0 +1,198 @@
+import os
+import random
+import string
+import time
+import logging
+
+import qbittorrentapi as qba
+from urllib.parse import urlparse, parse_qs
+from torrentool.api import Torrent
+from telegram import InlineKeyboardMarkup
+from telegram.ext import CallbackQueryHandler
+
+from bot import download_dict, download_dict_lock, BASE_URL, dispatcher, get_client
+from bot.helper.mirror_utils.status_utils.qbit_download_status import QbDownloadStatus
+from bot.helper.telegram_helper.message_utils import *
+from bot.helper.ext_utils.bot_utils import setInterval, new_thread, MirrorStatus
+from bot.helper.telegram_helper import button_build
+
+LOGGER = logging.getLogger(__name__)
+
+
+class qbittorrent:
+
+
+ def __init__(self):
+ self.update_interval = 1.5
+ self.meta_time = time.time()
+
+ @new_thread
+ def add_torrent(self, link, dire, listener, qbitsel):
+ self.client = get_client()
+ self.listener = listener
+ is_file = False
+ count = 0
+ pincode = ""
+ markup = None
+ try:
+ if os.path.exists(link):
+ is_file = True
+ self.ext_hash = get_hash_file(link)
+ else:
+ self.ext_hash = get_hash_magnet(link)
+ tor_info = self.client.torrents_info(torrent_hashes=self.ext_hash)
+ if len(tor_info) > 0:
+ sendMessage("This torrent is already in list.", listener.bot, listener.update)
+ return
+ if is_file:
+ op = self.client.torrents_add(torrent_files=[link], save_path=dire)
+ os.remove(link)
+ else:
+ op = self.client.torrents_add(link, save_path=dire)
+ if op.lower() == "ok.":
+ LOGGER.info(f"QbitDownload started: {self.ext_hash}")
+ tor_info = self.client.torrents_info(torrent_hashes=self.ext_hash)
+ if len(tor_info) == 0:
+ while True:
+ if time.time() - self.meta_time >= 300:
+ sendMessage("The torrent was not added. report when u see this error", listener.bot, listener.update)
+ return False
+ tor_info = self.client.torrents_info(torrent_hashes=self.ext_hash)
+ if len(tor_info) > 0:
+ break
+ else:
+ sendMessage("This is an unsupported/invalid link.", listener.bot, listener.update)
+ return
+ gid = ''.join(random.SystemRandom().choices(string.ascii_letters + string.digits, k=14))
+ self.updater = setInterval(self.update_interval, self.update)
+ tor_info = tor_info[0]
+ if BASE_URL is not None and qbitsel:
+ if not is_file and (tor_info.state == "checkingResumeData" or tor_info.state == "metaDL"):
+ meta = sendMessage("Downloading Metadata...Please wait then you can select files or mirror torrent file if it have low seeders", listener.bot, listener.update)
+ while True:
+ tor_info = self.client.torrents_info(torrent_hashes=self.ext_hash)
+ if len(tor_info) == 0:
+ deleteMessage(listener.bot, meta)
+ return False
+ tor_info = tor_info[0]
+ if tor_info.state == "metaDL" or tor_info.state == "checkingResumeData":
+ time.sleep(1)
+ else:
+ break
+ deleteMessage(listener.bot, meta)
+ for n in str(self.ext_hash):
+ if n.isdigit():
+ pincode += str(n)
+ count += 1
+ if count == 4:
+ break
+ URL = f"{BASE_URL}/slam/files/{self.ext_hash}"
+ pindata = f"pin {gid} {pincode}"
+ donedata = f"done {gid} {self.ext_hash}"
+ buttons = button_build.ButtonMaker()
+ buttons.buildbutton("Select Files", URL)
+ buttons.sbutton("Pincode", pindata)
+ buttons.sbutton("Done Selecting", donedata)
+ QBBUTTONS = InlineKeyboardMarkup(buttons.build_menu(2))
+ msg = "Your download paused. Choose files then press Done Selecting button to start downloading."
+ markup = sendMarkup(msg, listener.bot, listener.update, QBBUTTONS)
+ self.client.torrents_pause(torrent_hashes=self.ext_hash)
+ with download_dict_lock:
+ download_dict[listener.uid] = QbDownloadStatus(gid, listener, self.ext_hash, self.client, markup)
+ else:
+ with download_dict_lock:
+ download_dict[listener.uid] = QbDownloadStatus(gid, listener, self.ext_hash, self.client ,markup)
+ sendStatusMessage(listener.update, listener.bot)
+ except qba.UnsupportedMediaType415Error as e:
+ LOGGER.error(str(e))
+ sendMessage("This is an unsupported/invalid link. {str(e)}", listener.bot, listener.update)
+ except Exception as e:
+ LOGGER.error(str(e))
+ sendMessage(str(e), listener.bot, listener.update)
+ self.client.torrents_delete(torrent_hashes=self.ext_hash)
+
+
+ def update(self):
+ tor_info = self.client.torrents_info(torrent_hashes=self.ext_hash)
+ if len(tor_info) == 0:
+ self.updater.cancel()
+ return
+ else:
+ tor_info = tor_info[0]
+ if tor_info.state == "metaDL":
+ if time.time() - self.meta_time > 600:
+ self.client.torrents_delete(torrent_hashes=self.ext_hash)
+ self.listener.onDownloadError("Dead Torrent!")
+ self.updater.cancel()
+ return
+ elif tor_info.state == "error":
+ self.client.torrents_delete(torrent_hashes=self.ext_hash)
+ self.listener.onDownloadError("Error. IDK why, report in support group")
+ self.updater.cancel()
+ return
+ elif tor_info.state == "uploading" or tor_info.state.lower().endswith("up"):
+ self.client.torrents_pause(torrent_hashes=self.ext_hash)
+ self.listener.onDownloadComplete()
+ self.client.torrents_delete(torrent_hashes=self.ext_hash, delete_files=True)
+ self.updater.cancel()
+
+
+def get_confirm(update, context):
+ query = update.callback_query
+ user_id = query.from_user.id
+ data = query.data
+ data = data.split(" ")
+ qdl = None
+ with download_dict_lock:
+ for dl in download_dict.values():
+ if dl.status() == MirrorStatus.STATUS_PAUSE:
+ if dl.gid() == data[1]:
+ qdl = dl
+ break
+ if qdl is not None:
+ if user_id != qdl.listen().message.from_user.id:
+ query.answer(text="Don't waste your time!", show_alert=True)
+ return
+ if data[0] == "pin":
+ query.answer(text=data[2], show_alert=True)
+ elif data[0] == "done":
+ query.answer()
+ qdl.qbclient().torrents_resume(torrent_hashes=data[2])
+ sendStatusMessage(qdl.listen().update, qdl.listen().bot)
+ deleteMessage(context.bot, qdl.mark())
+ else:
+ query.answer(text="This task has been cancelled!", show_alert=True)
+ query.delete_message()
+
+
+def get_hash_magnet(mgt):
+ if mgt.startswith('magnet:'):
+ _, _, _, _, query, _ = urlparse(mgt)
+
+ qs = parse_qs(query)
+ v = qs.get('xt', None)
+
+ if v == None or v == []:
+ LOGGER.error('Invalid magnet URI: no "xt" query parameter.')
+ return False
+
+ v = v[0]
+ if not v.startswith('urn:btih:'):
+ LOGGER.error('Invalid magnet URI: "xt" value not valid for BitTorrent.')
+ return False
+
+ mgt = v[len('urn:btih:'):]
+ return mgt.lower()
+
+
+def get_hash_file(path):
+ tr = Torrent.from_file(path)
+ mgt = tr.magnet_link
+ return get_hash_magnet(mgt)
+
+
+pin_handler = CallbackQueryHandler(get_confirm, pattern="pin", run_async=True)
+done_handler = CallbackQueryHandler(get_confirm, pattern="done", run_async=True)
+dispatcher.add_handler(pin_handler)
+dispatcher.add_handler(done_handler)
+
diff --git a/bot/helper/mirror_utils/status_utils/qbit_download_status.py b/bot/helper/mirror_utils/status_utils/qbit_download_status.py
new file mode 100644
index 0000000..6a5c0eb
--- /dev/null
+++ b/bot/helper/mirror_utils/status_utils/qbit_download_status.py
@@ -0,0 +1,94 @@
+from bot import DOWNLOAD_DIR, LOGGER, get_client
+from bot.helper.ext_utils.bot_utils import MirrorStatus, get_readable_file_size, get_readable_time
+from .status import Status
+
+
+class QbDownloadStatus(Status):
+
+ def __init__(self, gid, listener, qbhash, client, markup):
+ super().__init__()
+ self.__gid = gid
+ self.__hash = qbhash
+ self.__client = client
+ self.__markup = markup
+ self.__uid = listener.uid
+ self.__listener = listener
+ self.message = listener.message
+ self.is_extracting = False
+ self.is_archiving = False
+
+
+ def progress(self):
+ """
+ Calculates the progress of the mirror (upload or download)
+ :return: returns progress in percentage
+ """
+ return f'{round(self.torrent_info().progress*100,2)}%'
+
+ def size_raw(self):
+ """
+ Gets total size of the mirror file/folder
+ :return: total size of mirror
+ """
+ return self.torrent_info().total_size
+
+ def processed_bytes(self):
+ return self.torrent_info().downloaded
+
+ def speed(self):
+ return f"{get_readable_file_size(self.torrent_info().dlspeed)}/s"
+
+ def name(self):
+ return self.torrent_info().name
+
+ def path(self):
+ return f"{DOWNLOAD_DIR}{self.__uid}"
+
+ def size(self):
+ return get_readable_file_size(self.torrent_info().total_size)
+
+ def eta(self):
+ return get_readable_time(self.torrent_info().eta)
+
+ def status(self):
+ download = self.torrent_info().state
+ if download == "queuedDL":
+ status = MirrorStatus.STATUS_WAITING
+ elif download == "metaDL":
+ status = MirrorStatus.STATUS_DOWNLOADING + " (Metadata)"
+ elif download == "pausedDL":
+ status = MirrorStatus.STATUS_PAUSE
+ else:
+ status = MirrorStatus.STATUS_DOWNLOADING
+ return status
+
+ def torrent_info(self):
+ tor_info = self.__client.torrents_info(torrent_hashes=self.__hash)
+ if len(tor_info) == 0:
+ return None
+ else:
+ return tor_info[0]
+
+ def download(self):
+ return self
+
+ def uid(self):
+ return self.__uid
+
+ def gid(self):
+ return self.__gid
+
+ def listen(self):
+ return self.__listener
+
+ def qbclient(self):
+ return self.__client
+
+ def mark(self):
+ return self.__markup
+
+ def cancel_download(self):
+ LOGGER.info(f"Cancelling Download: {self.name()}")
+ self.__listener.onDownloadError('Download stopped by user!')
+ self.__client.torrents_delete(torrent_hashes=self.__hash)
+
diff --git a/bot/helper/telegram_helper/message_utils.py b/bot/helper/telegram_helper/message_utils.py
index 19b081a..1ad2653 100644
--- a/bot/helper/telegram_helper/message_utils.py
+++ b/bot/helper/telegram_helper/message_utils.py
@@ -4,8 +4,8 @@
import psutil, shutil
import time
from bot import AUTO_DELETE_MESSAGE_DURATION, LOGGER, bot, \
- status_reply_dict, status_reply_dict_lock, download_dict, download_dict_lock, botStartTime
-from bot.helper.ext_utils.bot_utils import get_readable_message, get_readable_file_size, get_readable_time, MirrorStatus
+ status_reply_dict, status_reply_dict_lock, download_dict, download_dict_lock, botStartTime, Interval, DOWNLOAD_STATUS_UPDATE_INTERVAL
+from bot.helper.ext_utils.bot_utils import get_readable_message, get_readable_file_size, get_readable_time, MirrorStatus, setInterval
from telegram.error import TimedOut, BadRequest
@@ -108,6 +108,8 @@ def update_all_messages():
def sendStatusMessage(msg, bot):
+ if len(Interval) == 0:
+ Interval.append(setInterval(DOWNLOAD_STATUS_UPDATE_INTERVAL, update_all_messages))
total, used, free = shutil.disk_usage('.')
free = get_readable_file_size(free)
currentTime = get_readable_time(time.time() - botStartTime)
diff --git a/bot/modules/cancel_mirror.py b/bot/modules/cancel_mirror.py
index bf70fa0..369877f 100644
--- a/bot/modules/cancel_mirror.py
+++ b/bot/modules/cancel_mirror.py
@@ -42,9 +42,9 @@ def cancel_mirror(update, context):
elif not mirror_message:
sendMessage(msg, context.bot, update)
return
- if dl.status() == "Archiving...🔐":
+ if dl.status() == MirrorStatus.STATUS_ARCHIVING:
sendMessage("Archival in Progress, You Can't Cancel It.", context.bot, update)
- elif dl.status() == "Extracting...📂":
+ elif dl.status() == MirrorStatus.STATUS_EXTRACTING:
sendMessage("Extract in Progress, You Can't Cancel It.", context.bot, update)
else:
dl.download().cancel_download()
@@ -54,16 +54,15 @@ def cancel_mirror(update, context):
def cancel_all(update, context):
count = 0
- gid = 1
+ gid = 0
while True:
dl = getAllDownload()
if dl:
- if dl.gid() == gid:
- continue
- else:
+ if dl.gid() != gid:
gid = dl.gid()
dl.download().cancel_download()
count += 1
+ sleep(0.3)
else:
break
sendMessage(f'{count} Download(s) has been Cancelled!', context.bot, update)
diff --git a/bot/modules/clone.py b/bot/modules/clone.py
index 8bde39a..9ef506f 100644
--- a/bot/modules/clone.py
+++ b/bot/modules/clone.py
@@ -4,8 +4,8 @@
from bot.helper.telegram_helper.filters import CustomFilters
from bot.helper.telegram_helper.bot_commands import BotCommands
from bot.helper.mirror_utils.status_utils.clone_status import CloneStatus
-from bot import dispatcher, LOGGER, CLONE_LIMIT, STOP_DUPLICATE, download_dict, download_dict_lock, Interval, DOWNLOAD_STATUS_UPDATE_INTERVAL
-from bot.helper.ext_utils.bot_utils import get_readable_file_size, setInterval
+from bot import dispatcher, LOGGER, CLONE_LIMIT, STOP_DUPLICATE, download_dict, download_dict_lock, Interval
+from bot.helper.ext_utils.bot_utils import get_readable_file_size
import random
import string
@@ -50,8 +50,6 @@ def cloneNode(update, context):
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)
with download_dict_lock:
diff --git a/bot/modules/mirror.py b/bot/modules/mirror.py
index d191b56..d5b8f5f 100644
--- a/bot/modules/mirror.py
+++ b/bot/modules/mirror.py
@@ -3,12 +3,13 @@
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
-from bot import dispatcher, DOWNLOAD_DIR, DOWNLOAD_STATUS_UPDATE_INTERVAL, download_dict, download_dict_lock, SHORTENER, SHORTENER_API, TAR_UNZIP_LIMIT
+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 setInterval, get_mega_link_type
+from bot.helper.ext_utils.bot_utils import get_mega_link_type
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
+from bot.helper.mirror_utils.download_utils.qbit_downloader import qbittorrent
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
@@ -235,8 +236,15 @@ def _mirror(bot, update, isTar=False, extract=False):
mesg = update.message.text.split('\n')
message_args = mesg[0].split(' ')
name_args = mesg[0].split('|')
+ qbit = False
+ qbitsel = False
try:
link = message_args[1]
+ if link == "qb" or link == "qbs":
+ qbit = True
+ if link == "qbs":
+ qbitsel = True
+ link = message_args[2]
print(link)
if link.startswith("|") or link.startswith("pswd: "):
link = ''
@@ -281,11 +289,13 @@ def _mirror(bot, update, isTar=False, extract=False):
tg_downloader = TelegramDownloadHelper(listener)
ms = update.message
tg_downloader.add_download(ms, f'{DOWNLOAD_DIR}{listener.uid}/', name)
- if len(Interval) == 0:
- Interval.append(setInterval(DOWNLOAD_STATUS_UPDATE_INTERVAL, update_all_messages))
return
else:
- link = file.get_file().file_path
+ if qbit:
+ file.get_file().download(custom_path=f"/usr/src/app/{file.file_name}")
+ link = f"/usr/src/app/{file.file_name}"
+ else:
+ link = file.get_file().file_path
else:
tag = None
if not bot_utils.is_url(link) and not bot_utils.is_magnet(link):
@@ -333,8 +343,6 @@ def _mirror(bot, update, isTar=False, extract=False):
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)
@@ -347,11 +355,14 @@ def _mirror(bot, update, isTar=False, extract=False):
else:
mega_dl = MegaDownloadHelper()
mega_dl.add_download(link, f'{DOWNLOAD_DIR}/{listener.uid}/', listener)
+
+ elif qbit and (bot_utils.is_magnet(link) or os.path.exists(link)):
+ qbit = qbittorrent()
+ qbit.add_torrent(link, f'{DOWNLOAD_DIR}{listener.uid}/', listener, qbitsel)
+
else:
ariaDlManager.add_download(link, f'{DOWNLOAD_DIR}/{listener.uid}/', listener, name)
sendStatusMessage(update, bot)
- if len(Interval) == 0:
- Interval.append(setInterval(DOWNLOAD_STATUS_UPDATE_INTERVAL, update_all_messages))
def mirror(update, context):
diff --git a/bot/modules/watch.py b/bot/modules/watch.py
index 97c469e..b6f96d8 100644
--- a/bot/modules/watch.py
+++ b/bot/modules/watch.py
@@ -1,8 +1,7 @@
from telegram.ext import CommandHandler
from telegram import Bot, Update
-from bot import Interval, DOWNLOAD_DIR, DOWNLOAD_STATUS_UPDATE_INTERVAL, dispatcher, LOGGER
-from bot.helper.ext_utils.bot_utils import setInterval
-from bot.helper.telegram_helper.message_utils import update_all_messages, sendMessage, sendStatusMessage
+from bot import DOWNLOAD_DIR, dispatcher, LOGGER
+from bot.helper.telegram_helper.message_utils import sendMessage, sendStatusMessage
from .mirror import MirrorListener
from bot.helper.mirror_utils.download_utils.youtube_dl_download_helper import YoutubeDLHelper
from bot.helper.telegram_helper.bot_commands import BotCommands
@@ -50,8 +49,6 @@ def _watch(bot: Bot, update, isTar=False):
ydl = YoutubeDLHelper(listener)
threading.Thread(target=ydl.add_download,args=(link, f'{DOWNLOAD_DIR}{listener.uid}', qual, name)).start()
sendStatusMessage(update, bot)
- if len(Interval) == 0:
- Interval.append(setInterval(DOWNLOAD_STATUS_UPDATE_INTERVAL, update_all_messages))
def watchTar(update, context):
diff --git a/config_sample.env b/config_sample.env
index 7442aba..3d7f7e7 100644
--- a/config_sample.env
+++ b/config_sample.env
@@ -30,6 +30,10 @@ BLOCK_MEGA_LINKS = ""
STOP_DUPLICATE = ""
SHORTENER = ""
SHORTENER_API = ""
+#Qbittorrent
+IS_VPS = ""
+SERVER_PORT = "80" #For VPS
+BASE_URL_OF_BOT = ""
# If you want to use Credentials externally from Index Links, fill these vars with the direct links
# These are optional, if you don't know, simply leave them, don't fill anything in them.
ACCOUNTS_ZIP_URL = ""
diff --git a/heroku.yml b/heroku.yml
index 75581ef..a3d3035 100644
--- a/heroku.yml
+++ b/heroku.yml
@@ -1,5 +1,5 @@
build:
docker:
- worker: Dockerfile
+ web: Dockerfile
run:
- worker: bash start.sh
\ No newline at end of file
+ web: bash start.sh
diff --git a/nodes.py b/nodes.py
new file mode 100644
index 0000000..f4549a2
--- /dev/null
+++ b/nodes.py
@@ -0,0 +1,140 @@
+# -*- coding: utf-8 -*-
+# (c) YashDK [yash-dk@github]
+
+from anytree import NodeMixin, RenderTree, PreOrderIter
+import qbittorrentapi as qba
+
+SIZE_UNITS = ['B', 'KB', 'MB', 'GB', 'TB', 'PB']
+
+class TorNode(NodeMixin):
+ def __init__(self, name, is_folder=False, is_file=False, parent=None, progress=None, size=None, priority=None, file_id=None):
+ super().__init__()
+ self.name = name
+ self.is_folder = is_folder
+ self.is_file = is_file
+
+ if parent is not None:
+ self.parent = parent
+ if progress is not None:
+ self.progress = progress
+ if size is not None:
+ self.size = size
+ if priority is not None:
+ self.priority = priority
+ if file_id is not None:
+ self.file_id = file_id
+
+
+def get_folders(path):
+ path_seperator = "/"
+ folders = path.split(path_seperator)
+ return folders
+
+
+def make_tree(res):
+ """This function takes the list of all the torrent files. The files are name hierarchically.
+ Felt a need to document to save time.
+
+ Args:
+ res (list): Torrent files list.
+
+ Returns:
+ TorNode: Parent node of the tree constructed and can be used further.
+ """
+ parent = TorNode("Torrent")
+ #nodes = dict()
+ l = 0
+
+ for i in res:
+ # Get the hierarchy of the folders by splitting based on '/'
+ folders = get_folders(i.name)
+ # Check if the file is alone for if its in folder
+ if len(folders) > 1:
+ # Enter here if in folder
+
+ # Set the parent
+ previous_node = parent
+
+ # Traverse till second last assuming the last is a file.
+ for j in range(len(folders)-1):
+ current_node = None
+
+ if previous_node is not None:
+ # As we are traversing the folder from top to bottom we are searching
+ # the first folder (folders list) under the parent node in first iteration.
+ # If the node is found then it becomes the current node else the current node
+ # is left None.
+ for k in previous_node.children:
+ if k.name == folders[j]:
+ current_node = k
+ break
+ else:
+ # think its useless afterall
+ for k in parent.children:
+ if k.name == folders[j]:
+ current_node = k
+ break
+
+ # if the node is not found then create the folder node
+ # if the node is found then use it as base for the next
+ if current_node is None:
+ previous_node = TorNode(folders[j],parent=previous_node,is_folder=True)
+ else:
+ previous_node = current_node
+ # at this point the previous_node will contain the deepest folder in it so add the file to it
+ TorNode(folders[-1],is_file=True,parent=previous_node,progress=i.progress,size=i.size,priority=i.priority,file_id=l)
+ l += 1
+ else:
+ # at the file to the parent if no folders are there
+ TorNode(folders[-1],is_file=True,parent=parent,progress=i.progress,size=i.size,priority=i.priority,file_id=l)
+ l += 1
+
+
+ return parent
+
+
+def print_tree(parent):
+ for pre, _, node in RenderTree(parent):
+ treestr = u"%s%s" % (pre, node.name)
+ print(treestr.ljust(8), node.is_folder, node.is_file)
+
+
+def create_list(par, msg):
+ if par.name != ".unwanted":
+ msg[0] += "