diff --git a/Dockerfile b/Dockerfile
index ff19a0fe2..57ce1bb4b 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,7 +1,7 @@
FROM 5hojib/aeon:latest
-WORKDIR /usr/src/app
-RUN chmod 777 /usr/src/app
+WORKDIR /app
+RUN chmod 777 /app
RUN uv venv
COPY requirements.txt .
diff --git a/bot/__init__.py b/bot/__init__.py
index 44cb46bd8..8745656fa 100644
--- a/bot/__init__.py
+++ b/bot/__init__.py
@@ -70,9 +70,11 @@ def format(self, record: LogRecord) -> str:
LOGGER = getLogger(__name__)
-cpu_no = os.cpu_count()
+cpu_no = 8
+threads = 4
+cores = "0,1,2,3"
-DOWNLOAD_DIR = "/usr/src/app/downloads/"
+DOWNLOAD_DIR = "/app/downloads/"
intervals = {
"status": {},
"qb": "",
@@ -94,6 +96,7 @@ def format(self, record: LogRecord) -> str:
rss_dict = {}
auth_chats = {}
excluded_extensions = ["aria2", "!qB"]
+included_extensions = []
drives_names = []
drives_ids = []
index_urls = []
diff --git a/bot/__main__.py b/bot/__main__.py
index 675ad2f69..305715a4a 100644
--- a/bot/__main__.py
+++ b/bot/__main__.py
@@ -14,7 +14,7 @@
bot_loop.run_until_complete(load_settings())
-from .core.aeon_client import TgClient
+from .core.telegram_manager import TgClient
from .helper.telegram_helper.bot_commands import BotCommands
COMMANDS = {
diff --git a/bot/core/config_manager.py b/bot/core/config_manager.py
index e78cef5df..5b3ba44f7 100644
--- a/bot/core/config_manager.py
+++ b/bot/core/config_manager.py
@@ -18,6 +18,7 @@ class Config:
DATABASE_URL: str = ""
DEFAULT_UPLOAD: str = "gd"
EXCLUDED_EXTENSIONS: str = ""
+ INCLUDED_EXTENSIONS: str = ""
FFMPEG_CMDS: ClassVar[dict[str, list[str]]] = {}
FILELION_API: str = ""
GDRIVE_ID: str = ""
@@ -34,7 +35,7 @@ class Config:
HYBRID_LEECH: bool = False
HYDRA_IP: str = ""
HYDRA_API_KEY: str = ""
- NAME_SUBSTITUTE: str = ""
+ NAME_SUBSTITUTE: str = r""
OWNER_ID: int = 0
QUEUE_ALL: int = 0
QUEUE_DOWNLOAD: int = 0
diff --git a/bot/core/handlers.py b/bot/core/handlers.py
index f7dafdbe6..117464da7 100644
--- a/bot/core/handlers.py
+++ b/bot/core/handlers.py
@@ -10,7 +10,7 @@
from bot.helper.telegram_helper.filters import CustomFilters
from bot.modules import *
-from .aeon_client import TgClient
+from .telegram_manager import TgClient
def add_handlers():
diff --git a/bot/core/jdownloader_booter.py b/bot/core/jdownloader_booter.py
index f7e8ee46c..800dce0a9 100644
--- a/bot/core/jdownloader_booter.py
+++ b/bot/core/jdownloader_booter.py
@@ -9,8 +9,8 @@
from bot.helper.ext_utils.bot_utils import cmd_exec, new_task
from myjd import MyJdApi
-from .aeon_client import TgClient
from .config_manager import Config
+from .telegram_manager import TgClient
class JDownloader(MyJdApi):
diff --git a/bot/core/startup.py b/bot/core/startup.py
index 4bb33c3d2..8024f2cb8 100644
--- a/bot/core/startup.py
+++ b/bot/core/startup.py
@@ -1,4 +1,4 @@
-from asyncio import create_subprocess_exec, create_subprocess_shell
+from asyncio import create_subprocess_exec, create_subprocess_shell, sleep
from os import environ
import aiohttp
@@ -14,6 +14,7 @@
drives_ids,
drives_names,
excluded_extensions,
+ included_extensions,
index_urls,
nzb_options,
qbit_options,
@@ -25,13 +26,14 @@
)
from bot.helper.ext_utils.db_handler import database
-from .aeon_client import TgClient
from .config_manager import Config
+from .telegram_manager import TgClient
from .torrent_manager import TorrentManager
async def update_qb_options():
"""Updates qBittorrent options either from current preferences or saved configuration."""
+ LOGGER.info("Get qBittorrent options from server")
if not qbit_options:
opt = await TorrentManager.qbittorrent.app.preferences()
qbit_options.update(opt)
@@ -49,6 +51,7 @@ async def update_qb_options():
async def update_aria2_options():
"""Updates Aria2c global options either from current settings or saved configuration."""
+ LOGGER.info("Get aria2 options from server")
if not aria2_options:
op = await TorrentManager.aria2.getGlobalOption()
aria2_options.update(op)
@@ -58,8 +61,15 @@ async def update_aria2_options():
async def update_nzb_options():
"""Updates NZB options from Sabnzbd client configuration."""
- no = (await sabnzbd_client.get_config())["config"]["misc"]
- nzb_options.update(no)
+ LOGGER.info("Get SABnzbd options from server")
+ while True:
+ try:
+ no = (await sabnzbd_client.get_config())["config"]["misc"]
+ nzb_options.update(no)
+ except Exception:
+ await sleep(0.5)
+ continue
+ break
async def load_settings():
@@ -260,6 +270,11 @@ async def update_variables():
x = x.lstrip(".")
excluded_extensions.append(x.strip().lower())
+ if Config.INCLUDED_EXTENSIONS:
+ fx = Config.INCLUDED_EXTENSIONS.split()
+ for x in fx:
+ x = x.lstrip(".")
+ included_extensions.append(x.strip().lower())
if Config.GDRIVE_ID:
drives_names.append("Main")
drives_ids.append(Config.GDRIVE_ID)
@@ -273,7 +288,7 @@ async def update_variables():
drives_ids.append(temp[1])
drives_names.append(temp[0].replace("_", " "))
if len(temp) > 2:
- index_urls.append(temp[2].strip("/"))
+ index_urls.append(temp[2])
else:
index_urls.append("")
diff --git a/bot/core/aeon_client.py b/bot/core/telegram_manager.py
similarity index 83%
rename from bot/core/aeon_client.py
rename to bot/core/telegram_manager.py
index e10abbdae..9e9ef7f76 100644
--- a/bot/core/aeon_client.py
+++ b/bot/core/telegram_manager.py
@@ -1,6 +1,7 @@
from asyncio import Lock
from pyrogram import Client, enums
+from pyrogram.types import LinkPreviewOptions
from bot import LOGGER
@@ -26,9 +27,13 @@ async def start_bot(cls):
Config.TELEGRAM_HASH,
proxy=Config.TG_PROXY,
bot_token=Config.BOT_TOKEN,
- workdir="/usr/src/app",
+ workdir="/app",
parse_mode=enums.ParseMode.HTML,
max_concurrent_transmissions=100,
+ max_message_cache_size=15000,
+ max_topic_cache_size=15000,
+ sleep_threshold=0,
+ link_preview_options=LinkPreviewOptions(is_disabled=True),
)
await cls.bot.start()
cls.NAME = cls.bot.me.username
@@ -44,9 +49,13 @@ async def start_user(cls):
Config.TELEGRAM_HASH,
proxy=Config.TG_PROXY,
session_string=Config.USER_SESSION_STRING,
+ workdir="/app",
parse_mode=enums.ParseMode.HTML,
no_updates=True,
max_concurrent_transmissions=100,
+ max_message_cache_size=15000,
+ max_topic_cache_size=15000,
+ link_preview_options=LinkPreviewOptions(is_disabled=True),
)
await cls.user.start()
cls.IS_PREMIUM_USER = cls.user.me.is_premium
diff --git a/bot/helper/aeon_utils/access_check.py b/bot/helper/aeon_utils/access_check.py
index 76ab7538a..a129c2cde 100644
--- a/bot/helper/aeon_utils/access_check.py
+++ b/bot/helper/aeon_utils/access_check.py
@@ -8,8 +8,8 @@
LOGGER,
user_data,
)
-from bot.core.aeon_client import TgClient
from bot.core.config_manager import Config
+from bot.core.telegram_manager import TgClient
from bot.helper.aeon_utils.shorteners import short
from bot.helper.ext_utils.db_handler import database
from bot.helper.ext_utils.help_messages import nsfw_keywords
diff --git a/bot/helper/common.py b/bot/helper/common.py
index 0d0500a5c..c6bf27ce2 100644
--- a/bot/helper/common.py
+++ b/bot/helper/common.py
@@ -17,16 +17,18 @@
from bot import (
DOWNLOAD_DIR,
LOGGER,
+ cores,
cpu_eater_lock,
excluded_extensions,
+ included_extensions,
intervals,
multi_tags,
task_dict,
task_dict_lock,
user_data,
)
-from bot.core.aeon_client import TgClient
from bot.core.config_manager import Config
+from bot.core.telegram_manager import TgClient
from bot.helper.aeon_utils.command_gen import (
get_embed_thumb_cmd,
get_metadata_cmd,
@@ -130,12 +132,14 @@ def __init__(self):
self.is_file = False
self.bot_trans = False
self.user_trans = False
+ self.is_rss = False
self.progress = True
self.ffmpeg_cmds = None
self.chat_thread_id = None
self.subproc = None
self.thumb = None
self.excluded_extensions = []
+ self.included_extensions = []
self.files_to_proceed = []
self.is_super_chat = self.message.chat.type.name in [
"SUPERGROUP",
@@ -226,6 +230,11 @@ async def before_start(self):
if "EXCLUDED_EXTENSIONS" not in self.user_dict
else ["aria2", "!qB"]
)
+ self.included_extensions = self.user_dict.get("INCLUDED_EXTENSIONS") or (
+ included_extensions
+ if "INCLUDED_EXTENSIONS" not in self.user_dict
+ else []
+ )
if not self.rc_flags:
if self.user_dict.get("RCLONE_FLAGS"):
self.rc_flags = self.user_dict["RCLONE_FLAGS"]
@@ -268,41 +277,44 @@ async def before_start(self):
if self.up_dest in self.user_dict["UPLOAD_PATHS"]:
self.up_dest = self.user_dict["UPLOAD_PATHS"][self.up_dest]
elif (
- "UPLOAD_PATHS" not in self.user_dict
+ (
+ "UPLOAD_PATHS" not in self.user_dict
+ or not self.user_dict["UPLOAD_PATHS"]
+ )
and Config.UPLOAD_PATHS
and self.up_dest in Config.UPLOAD_PATHS
):
self.up_dest = Config.UPLOAD_PATHS[self.up_dest]
- if self.ffmpeg_cmds and not isinstance(self.ffmpeg_cmds, list):
+ if self.ffmpeg_cmds:
if self.user_dict.get("FFMPEG_CMDS", None):
ffmpeg_dict = deepcopy(self.user_dict["FFMPEG_CMDS"])
- elif "FFMPEG_CMDS" not in self.user_dict and Config.FFMPEG_CMDS:
+ elif (
+ "FFMPEG_CMDS" not in self.user_dict
+ or not self.user_dict["FFMPEG_CMDS"]
+ ) and Config.FFMPEG_CMDS:
ffmpeg_dict = deepcopy(Config.FFMPEG_CMDS)
else:
ffmpeg_dict = None
- if ffmpeg_dict is None:
- self.ffmpeg_cmds = ffmpeg_dict
- else:
- cmds = []
- for key in list(self.ffmpeg_cmds):
- if isinstance(key, tuple):
- cmds.extend(list(key))
- elif key in ffmpeg_dict:
- for ind, vl in enumerate(ffmpeg_dict[key]):
- if variables := set(findall(r"\{(.*?)\}", vl)):
- ff_values = (
- self.user_dict.get("FFMPEG_VARIABLES", {})
- .get(key, {})
- .get(str(ind), {})
- )
- if Counter(list(variables)) == Counter(
- list(ff_values.keys())
- ):
- cmds.append(vl.format(**ff_values))
- else:
- cmds.append(vl)
- self.ffmpeg_cmds = cmds
+ cmds = []
+ for key in list(self.ffmpeg_cmds):
+ if isinstance(key, tuple):
+ cmds.extend(list(key))
+ elif ffmpeg_dict is not None and key in ffmpeg_dict:
+ for ind, vl in enumerate(ffmpeg_dict[key]):
+ if variables := set(findall(r"\{(.*?)\}", vl)):
+ ff_values = (
+ self.user_dict.get("FFMPEG_VARIABLES", {})
+ .get(key, {})
+ .get(str(ind), {})
+ )
+ if Counter(list(variables)) == Counter(
+ list(ff_values.keys())
+ ):
+ cmds.append(vl.format(**ff_values))
+ else:
+ cmds.append(vl)
+ self.ffmpeg_cmds = cmds
if not self.is_leech:
self.stop_duplicate = self.user_dict.get("STOP_DUPLICATE") or (
"STOP_DUPLICATE" not in self.user_dict and Config.STOP_DUPLICATE
@@ -343,20 +355,18 @@ async def before_start(self):
raise ValueError(
"GoFile API token not configured! Please set your GoFile token in user settings or configure a global token."
)
- if is_gdrive_id(self.up_dest):
- if not self.up_dest.startswith(
- ("mtp:", "tp:", "sa:"),
- ) and self.user_dict.get("USER_TOKENS", False):
- self.up_dest = f"mtp:{self.up_dest}"
- elif is_rclone_path(self.up_dest):
- if not self.up_dest.startswith("mrcc:") and self.user_dict.get(
- "USER_TOKENS",
- False,
- ):
- self.up_dest = f"mrcc:{self.up_dest}"
- self.up_dest = self.up_dest.strip("/")
-
if self.up_dest not in ["rcl", "gdl"]:
+ if is_gdrive_id(self.up_dest):
+ if not self.up_dest.startswith(
+ ("mtp:", "tp:", "sa:")
+ ) and self.user_dict.get("USER_TOKENS", False):
+ self.up_dest = f"mtp:{self.up_dest}"
+ elif is_rclone_path(self.up_dest):
+ if not self.up_dest.startswith("mrcc:") and self.user_dict.get(
+ "USER_TOKENS", False
+ ):
+ self.up_dest = f"mrcc:{self.up_dest}"
+ self.up_dest = self.up_dest.strip("/")
await self.is_token_exists(self.up_dest, "up")
if self.up_dest == "rcl":
@@ -441,26 +451,36 @@ async def before_start(self):
except Exception:
chat = None
if chat is None:
+ LOGGER.warning(
+ "Account of user session can't find the the destination chat!"
+ )
self.user_transmission = False
self.hybrid_leech = False
- else:
- uploader_id = TgClient.user.me.id
- if chat.type.name not in [
- "SUPERGROUP",
- "CHANNEL",
- "GROUP",
- "FORUM",
- ]:
+ elif chat.type.name not in [
+ "SUPERGROUP",
+ "CHANNEL",
+ "GROUP",
+ "FORUM",
+ ]:
+ self.user_transmission = False
+ self.hybrid_leech = False
+ elif chat.is_admin:
+ member = await chat.get_member(TgClient.user.me.id)
+ if (
+ not member.privileges.can_manage_chat
+ or not member.privileges.can_delete_messages
+ ):
self.user_transmission = False
self.hybrid_leech = False
- else:
- member = await chat.get_member(uploader_id)
- if (
- not member.privileges.can_manage_chat
- or not member.privileges.can_delete_messages
- ):
- self.user_transmission = False
- self.hybrid_leech = False
+ LOGGER.warning(
+ "Enable manage chat and delete messages to account of the user session from administration settings!"
+ )
+ else:
+ LOGGER.warning(
+ "Promote the account of the user session to admin in the chat to get the benefit of user transmission!"
+ )
+ self.user_transmission = False
+ self.hybrid_leech = False
if not self.user_transmission or self.hybrid_leech:
try:
@@ -472,34 +492,36 @@ async def before_start(self):
self.hybrid_leech = False
else:
raise ValueError("Chat not found!")
- else:
- uploader_id = self.client.me.id
- if chat.type.name in [
- "SUPERGROUP",
- "CHANNEL",
- "GROUP",
- "FORUM",
- ]:
- member = await chat.get_member(uploader_id)
- if (
- not member.privileges.can_manage_chat
- or not member.privileges.can_delete_messages
- ):
- if not self.user_transmission:
- raise ValueError(
- "You don't have enough privileges in this chat!",
- )
- self.hybrid_leech = False
- else:
- try:
- await self.client.send_chat_action(
- self.up_dest,
- ChatAction.TYPING,
- )
- except Exception:
+ elif chat.type.name in [
+ "SUPERGROUP",
+ "CHANNEL",
+ "GROUP",
+ "FORUM",
+ ]:
+ if not chat.is_admin:
+ raise ValueError(
+ "Bot is not admin in the destination chat!"
+ )
+ member = await chat.get_member(self.client.me.id)
+ if (
+ not member.privileges.can_manage_chat
+ or not member.privileges.can_delete_messages
+ ):
+ if not self.user_transmission:
raise ValueError(
- "Start the bot and try again!",
- ) from None
+ "You don't have enough privileges in this chat! Enable manage chat and delete messages for this bot!"
+ )
+ self.hybrid_leech = False
+ else:
+ try:
+ await self.client.send_chat_action(
+ self.up_dest,
+ ChatAction.TYPING,
+ )
+ except Exception:
+ raise ValueError(
+ "Start the bot and try again!",
+ ) from None
elif (
self.user_transmission or self.hybrid_leech
) and not self.is_super_chat:
@@ -623,13 +645,16 @@ def get_cleaned_value(value, default, allowed=None, to_lower=False):
async def get_tag(self, text: list):
if len(text) > 1 and text[1].startswith("Tag: "):
+ self.is_rss = True
user_info = text[1].split("Tag: ")
if len(user_info) >= 3:
id_ = user_info[-1]
self.tag = " ".join(user_info[:-1])
else:
self.tag, id_ = text[1].split("Tag: ")[1].split()
- self.user = self.message.from_user = await self.client.get_users(id_)
+ self.user = self.message.from_user = await self.client.get_users(
+ int(id_)
+ )
self.user_id = self.user.id
self.user_dict = user_data.get(self.user_id, {})
with contextlib.suppress(Exception):
@@ -714,7 +739,7 @@ async def init_bulk(self, input_list, bulk_start, bulk_end, obj):
index = self.options.index("-b")
del self.options[index]
if bulk_start or bulk_end:
- del self.options[index + 1]
+ del self.options[index]
self.options = " ".join(self.options)
b_msg.append(f"{self.bulk[0]} -i {len(self.bulk)} {self.options}")
msg = " ".join(b_msg)
@@ -822,6 +847,9 @@ async def proceed_ffmpeg(self, dl_path, gid):
for ffmpeg_cmd in cmds:
self.proceed_count = 0
cmd = [
+ "taskset",
+ "-c",
+ f"{cores}",
"xtra",
"-hide_banner",
"-loglevel",
@@ -840,10 +868,17 @@ async def proceed_ffmpeg(self, dl_path, gid):
input_indexes = [
index for index, value in enumerate(cmd) if value == "-i"
]
- for index in input_indexes:
- if cmd[index + 1].startswith("mltb"):
- input_file = cmd[index + 1]
- break
+ input_file = next(
+ (
+ cmd[index + 1]
+ for index in input_indexes
+ if cmd[index + 1].startswith("mltb")
+ ),
+ "",
+ )
+ if not input_file:
+ LOGGER.error("Wrong FFmpeg cmd!")
+ return dl_path
if input_file.lower().endswith(".video"):
ext = "video"
elif input_file.lower().endswith(".audio"):
@@ -886,16 +921,17 @@ async def proceed_ffmpeg(self, dl_path, gid):
await cpu_eater_lock.acquire()
self.progress = True
LOGGER.info(f"Running FFmpeg command for: {file_path}")
+ var_cmd = cmd.copy()
for index in input_indexes:
if cmd[index + 1].startswith("mltb"):
- cmd[index + 1] = file_path
+ var_cmd[index + 1] = file_path
elif is_telegram_link(cmd[index + 1]):
msg = (await get_tg_link_message(cmd[index + 1]))[0]
file_dir = await temp_download(msg)
inputs[index + 1] = file_dir
- cmd[index + 1] = file_dir
+ var_cmd[index + 1] = file_dir
self.subsize = self.size
- res = await ffmpeg.ffmpeg_cmds(cmd, file_path)
+ res = await ffmpeg.ffmpeg_cmds(var_cmd, file_path)
if res:
if delete_files:
await remove(file_path)
@@ -943,7 +979,16 @@ async def proceed_ffmpeg(self, dl_path, gid):
):
continue
self.proceed_count += 1
- var_cmd[index + 1] = f_path
+ for index in input_indexes:
+ if cmd[index + 1].startswith("mltb"):
+ var_cmd[index + 1] = f_path
+ elif is_telegram_link(cmd[index + 1]):
+ msg = (
+ await get_tg_link_message(cmd[index + 1])
+ )[0]
+ file_dir = await temp_download(msg)
+ inputs[index + 1] = file_dir
+ var_cmd[index + 1] = file_dir
if not checked:
checked = True
async with task_dict_lock:
@@ -983,6 +1028,8 @@ def perform_substitution(name, substitutions):
for substitution in substitutions:
sen = False
pattern = substitution[0]
+ if pattern.startswith('"') and pattern.endswith('"'):
+ pattern = pattern.strip('"')
if len(substitution) > 1:
if len(substitution) > 2:
sen = substitution[2] == "s"
@@ -995,7 +1042,7 @@ def perform_substitution(name, substitutions):
res = ""
try:
name = sub(
- rf"{pattern}",
+ pattern,
res,
name,
flags=IGNORECASE if sen else 0,
diff --git a/bot/helper/ext_utils/bot_utils.py b/bot/helper/ext_utils/bot_utils.py
index d3ca3007e..e6ee53180 100644
--- a/bot/helper/ext_utils/bot_utils.py
+++ b/bot/helper/ext_utils/bot_utils.py
@@ -192,6 +192,9 @@ def arg_parser(items, arg_base):
sub_list = []
for j in range(i + 1, total):
if items[j] in arg_base:
+ if part == "-c" and items[j] == "-c":
+ sub_list.append(items[j])
+ continue
if part in bool_arg_set and not sub_list:
arg_base[part] = True
break
diff --git a/bot/helper/ext_utils/bulk_links.py b/bot/helper/ext_utils/bulk_links.py
index 5519eb46b..9183b2df3 100644
--- a/bot/helper/ext_utils/bulk_links.py
+++ b/bot/helper/ext_utils/bulk_links.py
@@ -2,25 +2,10 @@
from aiofiles.os import remove
-def filter_links(links_list: list, bulk_start: int, bulk_end: int) -> list:
- """
- Filters a list of links based on start and end indices.
-
- Args:
- links_list: The list of links to filter.
- bulk_start: The starting index (1-based). If 0, no start filtering.
- bulk_end: The ending index. If 0, no end filtering.
-
- Returns:
- The filtered list of links.
- """
- if bulk_start != 0 and bulk_end != 0:
- links_list = links_list[bulk_start:bulk_end]
- elif bulk_start != 0:
- links_list = links_list[bulk_start:]
- elif bulk_end != 0:
- links_list = links_list[:bulk_end]
- return links_list
+def filter_links(links_list, bulk_start, bulk_end):
+ start = bulk_start if bulk_start > 0 else None
+ end = bulk_end if bulk_end > 0 else None
+ return links_list[start:end]
def get_links_from_message(text: str) -> list:
diff --git a/bot/helper/ext_utils/db_handler.py b/bot/helper/ext_utils/db_handler.py
index 659ae1283..44f6b38ad 100644
--- a/bot/helper/ext_utils/db_handler.py
+++ b/bot/helper/ext_utils/db_handler.py
@@ -7,8 +7,8 @@
from pymongo.server_api import ServerApi
from bot import LOGGER, qbit_options, rss_dict, user_data
-from bot.core.aeon_client import TgClient
from bot.core.config_manager import Config
+from bot.core.telegram_manager import TgClient
class DbManager:
@@ -28,6 +28,8 @@ async def connect(self):
self._conn = AsyncMongoClient(
Config.DATABASE_URL,
server_api=ServerApi("1"),
+ connectTimeoutMS=60000,
+ serverSelectionTimeoutMS=60000,
)
self.db = self._conn.luna
self._return = False
diff --git a/bot/helper/ext_utils/files_utils.py b/bot/helper/ext_utils/files_utils.py
index 0aae3c2a1..08cf2d5dd 100644
--- a/bot/helper/ext_utils/files_utils.py
+++ b/bot/helper/ext_utils/files_utils.py
@@ -1,4 +1,4 @@
-from asyncio import create_subprocess_exec, sleep, wait_for
+from asyncio import create_subprocess_exec, wait_for
from asyncio.subprocess import PIPE
from os import path as ospath
from os import readlink, walk
@@ -237,11 +237,23 @@ def get_mime_type(file_path: str) -> str:
async def remove_excluded_files(fpath, ee):
for root, _, files in await sync_to_async(walk, fpath):
+ if root.strip().endswith("/yt-dlp-thumb"):
+ continue
for f in files:
if f.strip().lower().endswith(tuple(ee)):
await remove(ospath.join(root, f))
+async def remove_non_included_files(fpath, ie):
+ for root, _, files in await sync_to_async(walk, fpath):
+ if root.strip().endswith("/yt-dlp-thumb"):
+ continue
+ for f in files:
+ if f.strip().lower().endswith(tuple(ie)):
+ continue
+ await remove(ospath.join(root, f))
+
+
async def join_files(opath):
files = await listdir(opath)
results = []
@@ -317,7 +329,7 @@ def progress(self):
return self._percentage
async def _sevenz_progress(self):
- pattern = r"(\d+)\s+bytes|Total Physical Size\s*=\s*(\d+)"
+ pattern = r"(\d+)\s+bytes|Total Physical Size\s*=\s*(\d+)|Physical Size\s*=\s*(\d+)"
while not (
self._listener.subproc.returncode is not None
or self._listener.is_cancelled
@@ -328,9 +340,18 @@ async def _sevenz_progress(self):
except Exception:
break
line = line.decode().strip()
+ if "%" in line:
+ perc = line.split("%", 1)[0]
+ if perc.isdigit():
+ self._percentage = f"{perc}%"
+ self._processed_bytes = (
+ int(perc) / 100
+ ) * self._listener.subsize
+ else:
+ self._percentage = "0%"
+ continue
if match := re_search(pattern, line):
- self._listener.subsize = int(match[1] or match[2])
- await sleep(0.05)
+ self._listener.subsize = int(match[1] or match[2] or match[3])
s = b""
while not (
self._listener.is_cancelled
@@ -354,7 +375,6 @@ async def _sevenz_progress(self):
self._processed_bytes = 0
self._percentage = "0%"
s = b""
- await sleep(0.05)
self._processed_bytes = 0
self._percentage = "0%"
diff --git a/bot/helper/ext_utils/help_messages.py b/bot/helper/ext_utils/help_messages.py
index f0ad3e8f7..fa22baf12 100644
--- a/bot/helper/ext_utils/help_messages.py
+++ b/bot/helper/ext_utils/help_messages.py
@@ -1,4 +1,4 @@
-from bot.core.aeon_client import TgClient
+from bot.core.telegram_manager import TgClient
from bot.helper.telegram_helper.bot_commands import BotCommands
nsfw_keywords = [
@@ -277,7 +277,7 @@
Examples: ["-i mltb.mkv -c copy -c:s srt mltb.mkv", "-i mltb.video -c copy -c:s srt mltb", "-i mltb.m4a -c:a libmp3lame -q:a 2 mltb.mp3", "-i mltb.audio -c:a libmp3lame -q:a 2 mltb.mp3", "-i mltb -map 0:a -c copy mltb.mka -map 0:s -c copy mltb.srt", "-i mltb -i tg://openmessage?user_id=5272663208&message_id=322801 -filter_complex 'overlay=W-w-10:H-h-10' -c:a copy mltb"]
Here I will explain how to use mltb.* which is reference to files you want to work on.
1. First cmd: the input is mltb.mkv so this cmd will work only on mkv videos and the output is mltb.mkv also so all outputs is mkv. -del will delete the original media after complete run of the cmd.
-2. Second cmd: the input is mltb.video so this cmd will work on all videos and the output is only mltb so the extenstion is same as input files.
+2. Second cmd: the input is mltb.video so this cmd will work on all videos and the output is only mltb so the extension is same as input files.
3. Third cmd: the input in mltb.m4a so this cmd will work only on m4a audios and the output is mltb.mp3 so the output extension is mp3.
4. Fourth cmd: the input is mltb.audio so this cmd will work on all audios and the output is mltb.mp3 so the output extension is mp3.
5. Fifth cmd: You can add telegram link for small size input like photo to set watermark"""
@@ -391,7 +391,8 @@
"GDRIVE_ID": "Send Gdrive ID. If you want to use your token.pickle edit using owner/user token from usetting or add mtp: before the id. Example: mtp:F435RGGRDXXXXXX . Timeout: 60 sec",
"INDEX_URL": "Send Index URL. Timeout: 60 sec",
"UPLOAD_PATHS": "Send Dict of keys that have path values. Example: {'path 1': 'remote:rclonefolder', 'path 2': 'gdrive1 id', 'path 3': 'tg chat id', 'path 4': 'mrcc:remote:', 'path 5': b:@username} . Timeout: 60 sec",
- "EXCLUDED_EXTENSIONS": "Send exluded extenions separated by space without dot at beginning. Timeout: 60 sec",
+ "EXCLUDED_EXTENSIONS": "Send excluded extensions separated by space without dot at beginning. Timeout: 60 sec",
+ "INCLUDED_EXTENSIONS": "Send included extensions separated by space without dot at beginning. Timeout: 60 sec",
"NAME_SUBSTITUTE": r"""Word Subtitions. You can add pattern instead of normal text. Timeout: 60 sec
NOTE: You must add \ before any character, those are the characters: \^$.|?*+()[]{}-
Example: script/code/s | mirror/leech | tea/ /s | clone | cpu/ | \[mltb\]/mltb | \\text\\/text/s
diff --git a/bot/helper/ext_utils/media_utils.py b/bot/helper/ext_utils/media_utils.py
index a70e756b6..b5b2c38f2 100644
--- a/bot/helper/ext_utils/media_utils.py
+++ b/bot/helper/ext_utils/media_utils.py
@@ -1,5 +1,5 @@
import contextlib
-from asyncio import create_subprocess_exec, gather, sleep, wait_for
+from asyncio import create_subprocess_exec, gather, wait_for
from asyncio.subprocess import PIPE
from os import path as ospath
from re import escape
@@ -11,7 +11,7 @@
from aioshutil import rmtree
from PIL import Image
-from bot import DOWNLOAD_DIR, LOGGER, cpu_no
+from bot import DOWNLOAD_DIR, LOGGER, cores, threads
from .bot_utils import cmd_exec, sync_to_async
from .files_utils import get_mime_type, is_archive, is_archive_split
@@ -130,6 +130,9 @@ async def take_ss(video_file, ss_nb) -> bool:
for i in range(ss_nb):
output = f"{dirpath}/SS.{name}_{i:02}.png"
cmd = [
+ "taskset",
+ "-c",
+ f"{cores}",
"xtra",
"-hide_banner",
"-loglevel",
@@ -143,7 +146,7 @@ async def take_ss(video_file, ss_nb) -> bool:
"-frames:v",
"1",
"-threads",
- f"{max(1, cpu_no // 2)}",
+ f"{threads}",
output,
]
cap_time += interval
@@ -152,13 +155,13 @@ async def take_ss(video_file, ss_nb) -> bool:
resutls = await wait_for(gather(*cmds), timeout=60)
if resutls[0][2] != 0:
LOGGER.error(
- f"Error while creating sreenshots from video. Path: {video_file}. stderr: {resutls[0][1]}",
+ f"Error while creating screenshots from video. Path: {video_file}. stderr: {resutls[0][1]}",
)
await rmtree(dirpath, ignore_errors=True)
return False
except Exception:
LOGGER.error(
- f"Error while creating sreenshots from video. Path: {video_file}. Error: Timeout some issues with ffmpeg with specific arch!",
+ f"Error while creating screenshots from video. Path: {video_file}. Error: Timeout some issues with ffmpeg with specific arch!",
)
await rmtree(dirpath, ignore_errors=True)
return False
@@ -172,6 +175,9 @@ async def get_audio_thumbnail(audio_file):
await makedirs(output_dir, exist_ok=True)
output = ospath.join(output_dir, f"{time()}.jpg")
cmd = [
+ "taskset",
+ "-c",
+ f"{cores}",
"xtra",
"-hide_banner",
"-loglevel",
@@ -182,7 +188,7 @@ async def get_audio_thumbnail(audio_file):
"-vcodec",
"copy",
"-threads",
- f"{max(1, cpu_no // 2)}",
+ f"{threads}",
output,
]
try:
@@ -211,6 +217,9 @@ async def get_video_thumbnail(video_file, duration):
duration = 3
duration = duration // 2
cmd = [
+ "taskset",
+ "-c",
+ f"{cores}",
"xtra",
"-hide_banner",
"-loglevel",
@@ -254,6 +263,9 @@ async def get_multiple_frames_thumbnail(video_file, layout, keep_screenshots):
await makedirs(output_dir, exist_ok=True)
output = ospath.join(output_dir, f"{time()}.jpg")
cmd = [
+ "taskset",
+ "-c",
+ f"{cores}",
"xtra",
"-hide_banner",
"-loglevel",
@@ -271,7 +283,7 @@ async def get_multiple_frames_thumbnail(video_file, layout, keep_screenshots):
"-f",
"mjpeg",
"-threads",
- f"{max(1, cpu_no // 2)}",
+ f"{threads}",
output,
]
try:
@@ -376,7 +388,6 @@ async def _ffmpeg_progress(self):
except Exception:
self._progress_raw = 0
self._eta_raw = 0
- await sleep(0.05)
async def ffmpeg_cmds(self, ffmpeg, f_path):
self.clear()
@@ -471,6 +482,9 @@ async def convert_video(self, video_file, ext, retry=False):
output = f"{base_name}.{ext}"
if retry:
cmd = [
+ "taskset",
+ "-c",
+ f"{cores}",
"xtra",
"-hide_banner",
"-loglevel",
@@ -486,17 +500,20 @@ async def convert_video(self, video_file, ext, retry=False):
"-c:a",
"aac",
"-threads",
- f"{max(1, cpu_no // 2)}",
+ f"{threads}",
output,
]
if ext == "mp4":
- cmd[14:14] = ["-c:s", "mov_text"]
+ cmd[17:17] = ["-c:s", "mov_text"]
elif ext == "mkv":
- cmd[14:14] = ["-c:s", "ass"]
+ cmd[17:17] = ["-c:s", "ass"]
else:
- cmd[14:14] = ["-c:s", "copy"]
+ cmd[17:17] = ["-c:s", "copy"]
else:
cmd = [
+ "taskset",
+ "-c",
+ f"{cores}",
"xtra",
"-hide_banner",
"-loglevel",
@@ -510,7 +527,7 @@ async def convert_video(self, video_file, ext, retry=False):
"-c",
"copy",
"-threads",
- f"{max(1, cpu_no // 2)}",
+ f"{threads}",
output,
]
if self._listener.is_cancelled:
@@ -549,6 +566,9 @@ async def convert_audio(self, audio_file, ext):
base_name = ospath.splitext(audio_file)[0]
output = f"{base_name}.{ext}"
cmd = [
+ "taskset",
+ "-c",
+ f"{cores}",
"xtra",
"-hide_banner",
"-loglevel",
@@ -558,7 +578,7 @@ async def convert_audio(self, audio_file, ext):
"-i",
audio_file,
"-threads",
- f"{max(1, cpu_no // 2)}",
+ f"{threads}",
output,
]
if self._listener.is_cancelled:
@@ -620,6 +640,9 @@ async def sample_video(self, video_file, sample_duration, part_duration):
filter_complex += f"concat=n={len(segments)}:v=1:a=1[vout][aout]"
cmd = [
+ "taskset",
+ "-c",
+ f"{cores}",
"xtra",
"-hide_banner",
"-loglevel",
@@ -639,7 +662,7 @@ async def sample_video(self, video_file, sample_duration, part_duration):
"-c:a",
"aac",
"-threads",
- f"{max(1, cpu_no // 2)}",
+ f"{threads}",
output_file,
]
@@ -682,6 +705,9 @@ async def split(self, f_path, file_, parts, split_size):
while i <= parts or start_time < duration - 4:
out_path = f_path.replace(file_, f"{base_name}.part{i:03}{extension}")
cmd = [
+ "taskset",
+ "-c",
+ f"{cores}",
"xtra",
"-hide_banner",
"-loglevel",
@@ -705,12 +731,12 @@ async def split(self, f_path, file_, parts, split_size):
"-c",
"copy",
"-threads",
- f"{max(1, cpu_no // 2)}",
+ f"{threads}",
out_path,
]
if not multi_streams:
- del cmd[12]
- del cmd[12]
+ del cmd[15]
+ del cmd[15]
if self._listener.is_cancelled:
return False
self._listener.subproc = await create_subprocess_exec(
@@ -759,7 +785,7 @@ async def split(self, f_path, file_, parts, split_size):
break
if duration == lpd:
LOGGER.warning(
- f"This file has been splitted with default stream and audio, so you will only see one part with less size from orginal one because it doesn't have all streams and audios. This happens mostly with MKV videos. Path: {f_path}",
+ f"This file has been splitted with default stream and audio, so you will only see one part with less size from original one because it doesn't have all streams and audios. This happens mostly with MKV videos. Path: {f_path}",
)
break
if lpd <= 3:
diff --git a/bot/helper/ext_utils/task_manager.py b/bot/helper/ext_utils/task_manager.py
index 2d67b19b5..2e1443239 100644
--- a/bot/helper/ext_utils/task_manager.py
+++ b/bot/helper/ext_utils/task_manager.py
@@ -18,13 +18,11 @@
async def stop_duplicate_check(listener):
if (
- isinstance(listener.up_dest, int)
- or listener.is_leech
- or listener.select
- or not is_gdrive_id(listener.up_dest)
- or (listener.up_dest.startswith("mtp:") and listener.stop_duplicate)
+ listener.is_leech
or not listener.stop_duplicate
or listener.same_dir
+ or listener.select
+ or not is_gdrive_id(listener.up_dest)
):
return False, None
diff --git a/bot/helper/listeners/aria2_listener.py b/bot/helper/listeners/aria2_listener.py
index 384512bf8..b891ec1cf 100644
--- a/bot/helper/listeners/aria2_listener.py
+++ b/bot/helper/listeners/aria2_listener.py
@@ -173,12 +173,14 @@ async def _on_download_error(api, data):
await sleep(1)
LOGGER.info(f"onDownloadError: {gid}")
error = "None"
- with contextlib.suppress(TimeoutError, ClientError, Exception):
+ try:
download = await api.tellStatus(gid)
options = await api.getOption(gid)
error = download.get("errorMessage", "")
LOGGER.info(f"Download Error: {error}")
- if options.get("follow-torrent", "") == "false":
+ if options.get("follow-torrent", "") == "false":
+ return
+ except (TimeoutError, ClientError, Exception):
return
if task := await get_task_by_gid(gid):
await task.listener.on_download_error(error)
diff --git a/bot/helper/listeners/task_listener.py b/bot/helper/listeners/task_listener.py
index 7029bd734..284ea50c8 100644
--- a/bot/helper/listeners/task_listener.py
+++ b/bot/helper/listeners/task_listener.py
@@ -32,15 +32,18 @@
get_path_size,
join_files,
remove_excluded_files,
+ remove_non_included_files,
)
from bot.helper.ext_utils.links_utils import is_gdrive_id
from bot.helper.ext_utils.status_utils import get_readable_file_size
from bot.helper.ext_utils.task_manager import check_running_tasks, start_from_queued
from bot.helper.mirror_leech_utils.gdrive_utils.upload import GoogleDriveUpload
+from bot.helper.mirror_leech_utils.gofile_utils.upload import GoFileUpload
from bot.helper.mirror_leech_utils.rclone_utils.transfer import RcloneTransferHelper
from bot.helper.mirror_leech_utils.status_utils.gdrive_status import (
GoogleDriveStatus,
)
+from bot.helper.mirror_leech_utils.status_utils.gofile_status import GoFileStatus
from bot.helper.mirror_leech_utils.status_utils.queue_status import QueueStatus
from bot.helper.mirror_leech_utils.status_utils.rclone_status import RcloneStatus
from bot.helper.mirror_leech_utils.status_utils.telegram_status import TelegramStatus
@@ -196,10 +199,14 @@ async def on_download_complete(self):
else:
up_dir = self.dir
up_path = dl_path
- await remove_excluded_files(
- self.up_dir or self.dir,
- self.excluded_extensions,
- )
+ if not self.included_extensions:
+ await remove_excluded_files(
+ self.up_dir or self.dir, self.excluded_extensions
+ )
+ else:
+ await remove_non_included_files(
+ self.up_dir or self.dir, self.included_extensions
+ )
if not Config.QUEUE_ALL:
async with queue_dict_lock:
if self.mid in non_queued_dl:
@@ -217,7 +224,10 @@ async def on_download_complete(self):
self.name = up_path.replace(f"{up_dir}/", "").split("/", 1)[0]
self.size = await get_path_size(up_dir)
self.clear()
- await remove_excluded_files(up_dir, self.excluded_extensions)
+ if not self.included_extensions:
+ await remove_excluded_files(up_dir, self.excluded_extensions)
+ else:
+ await remove_non_included_files(up_dir, self.included_extensions)
if self.watermark:
up_path = await self.proceed_watermark(
@@ -256,6 +266,7 @@ async def on_download_complete(self):
self.clear()
if self.name_sub:
+ LOGGER.info(f"Start Name Substitution {up_path}")
up_path = await self.substitute(up_path)
if self.is_cancelled:
return
@@ -400,13 +411,6 @@ async def on_download_complete(self):
del yt
elif self.up_dest == "gofile":
LOGGER.info(f"GoFile Upload Name: {self.name}")
- from bot.helper.mirror_leech_utils.gofile_utils.upload import (
- GoFileUpload,
- )
- from bot.helper.mirror_leech_utils.status_utils.gofile_status import (
- GoFileStatus,
- )
-
gofile = GoFileUpload(self, up_path)
async with task_dict_lock:
task_dict[self.mid] = GoFileStatus(self, gofile, gid, "up")
@@ -647,12 +651,10 @@ async def on_upload_complete(
elif Config.INDEX_URL:
INDEX_URL = Config.INDEX_URL
if INDEX_URL:
- share_url = f"{INDEX_URL}/findpath?id={dir_id}"
+ share_url = f"{INDEX_URL}findpath?id={dir_id}"
buttons.url_button("Index Link", share_url)
if mime_type.startswith(("image", "video", "audio")):
- share_urls = (
- f"{INDEX_URL}/findpath?id={dir_id}&view=true"
- )
+ share_urls = f"{INDEX_URL}findpath?id={dir_id}&view=true"
buttons.url_button("🌐 View Link", share_urls)
button = buttons.build_menu(2)
else:
diff --git a/bot/helper/mirror_leech_utils/download_utils/aria2_download.py b/bot/helper/mirror_leech_utils/download_utils/aria2_download.py
index 0e5c27cdd..6b96cc909 100644
--- a/bot/helper/mirror_leech_utils/download_utils/aria2_download.py
+++ b/bot/helper/mirror_leech_utils/download_utils/aria2_download.py
@@ -70,8 +70,10 @@ async def add_aria2_download(listener, dpath, header, ratio, seed_time):
if add_to_queue:
LOGGER.info(f"Added to Queue/Download: {name}. Gid: {gid}")
if (
- not listener.select or "bittorrent" not in download
- ) and listener.multi <= 1:
+ (not listener.select or "bittorrent" not in download)
+ and listener.multi <= 1
+ and not listener.is_rss
+ ):
await send_status_message(listener.message)
else:
LOGGER.info(f"Aria2Download started: {name}. Gid: {gid}")
@@ -82,6 +84,7 @@ async def add_aria2_download(listener, dpath, header, ratio, seed_time):
not add_to_queue
and (not listener.select or not Config.BASE_URL)
and listener.multi <= 1
+ and not listener.is_rss
):
await send_status_message(listener.message)
elif listener.select and "bittorrent" in download and not is_metadata(download):
diff --git a/bot/helper/mirror_leech_utils/download_utils/direct_downloader.py b/bot/helper/mirror_leech_utils/download_utils/direct_downloader.py
index 5b5b13c9c..29625f2bc 100644
--- a/bot/helper/mirror_leech_utils/download_utils/direct_downloader.py
+++ b/bot/helper/mirror_leech_utils/download_utils/direct_downloader.py
@@ -34,7 +34,7 @@ async def add_direct_download(listener, path):
async with task_dict_lock:
task_dict[listener.mid] = QueueStatus(listener, gid, "dl")
await listener.on_download_start()
- if listener.multi <= 1:
+ if listener.multi <= 1 and not listener.is_rss:
await send_status_message(listener.message)
await event.wait()
if listener.is_cancelled:
@@ -54,7 +54,7 @@ async def add_direct_download(listener, path):
else:
LOGGER.info(f"Download from Direct Download: {listener.name}")
await listener.on_download_start()
- if listener.multi <= 1:
+ if listener.multi <= 1 and not listener.is_rss:
await send_status_message(listener.message)
await directListener.download(contents)
diff --git a/bot/helper/mirror_leech_utils/download_utils/jd_download.py b/bot/helper/mirror_leech_utils/download_utils/jd_download.py
index d59368cb6..4d15d7972 100644
--- a/bot/helper/mirror_leech_utils/download_utils/jd_download.py
+++ b/bot/helper/mirror_leech_utils/download_utils/jd_download.py
@@ -166,8 +166,10 @@ async def add_jd_download(listener, path):
)
await sleep(1)
+ LOGGER.info(f"JDownloader Collecting Data: {listener.link}")
while await jdownloader.device.linkgrabber.is_collecting():
- pass
+ await sleep(0.5)
+ LOGGER.info(f"JDownloader Finished Collecting Data: {listener.link}")
start_time = time()
online_packages = []
corrupted_packages = []
diff --git a/bot/helper/mirror_leech_utils/download_utils/qbit_download.py b/bot/helper/mirror_leech_utils/download_utils/qbit_download.py
index e7d2ab242..45327ed2c 100644
--- a/bot/helper/mirror_leech_utils/download_utils/qbit_download.py
+++ b/bot/helper/mirror_leech_utils/download_utils/qbit_download.py
@@ -111,7 +111,7 @@ async def add_qb_torrent(listener, path, ratio, seed_time):
SBUTTONS = bt_selection_buttons(ext_hash)
msg = "Your download paused. Choose files then press Done Selecting button to start downloading."
await send_message(listener.message, msg, SBUTTONS)
- elif listener.multi <= 1:
+ elif listener.multi <= 1 and not listener.is_rss:
await send_status_message(listener.message)
if event is not None:
diff --git a/bot/helper/mirror_leech_utils/download_utils/telegram_download.py b/bot/helper/mirror_leech_utils/download_utils/telegram_download.py
index 5721f95d4..c0b4f4ac7 100644
--- a/bot/helper/mirror_leech_utils/download_utils/telegram_download.py
+++ b/bot/helper/mirror_leech_utils/download_utils/telegram_download.py
@@ -5,7 +5,7 @@
from pyrogram.errors import FloodPremiumWait, FloodWait
from bot import LOGGER, task_dict, task_dict_lock
-from bot.core.aeon_client import TgClient
+from bot.core.telegram_manager import TgClient
from bot.helper.ext_utils.task_manager import (
check_running_tasks,
stop_duplicate_check,
diff --git a/bot/helper/mirror_leech_utils/download_utils/yt_dlp_download.py b/bot/helper/mirror_leech_utils/download_utils/yt_dlp_download.py
index 22d624429..640cc4f45 100644
--- a/bot/helper/mirror_leech_utils/download_utils/yt_dlp_download.py
+++ b/bot/helper/mirror_leech_utils/download_utils/yt_dlp_download.py
@@ -1,4 +1,4 @@
-# ruff: noqa: ARG005, B023
+import builtins
import contextlib
from logging import getLogger
from os import listdir
@@ -27,11 +27,9 @@ def __init__(self, obj, listener):
self._listener = listener
def debug(self, msg):
+ # Hack to fix changing extension
if not self._obj.is_playlist and (
- match := re_search(
- r".Merger..Merging formats into..(.*?).$",
- msg,
- )
+ match := re_search(r".Merger..Merging formats into..(.*?).$", msg)
or re_search(r".ExtractAudio..Destination..(.*?)$", msg)
):
LOGGER.info(msg)
@@ -60,6 +58,7 @@ def __init__(self, listener):
self._gid = ""
self._ext = ""
self.is_playlist = False
+ self.keep_thumb = False
self.opts = {
"progress_hooks": [self._on_download_progress],
"logger": MyLogger(self, self._listener),
@@ -76,10 +75,10 @@ def __init__(self, listener):
"fragment_retries": 10,
"retries": 10,
"retry_sleep_functions": {
- "http": lambda n: 3,
- "fragment": lambda n: 3,
- "file_access": lambda n: 3,
- "extractor": lambda n: 3,
+ "http": lambda _: 3,
+ "fragment": lambda _: 3,
+ "file_access": lambda _: 3,
+ "extractor": lambda _: 3,
},
}
@@ -123,19 +122,17 @@ def _on_download_progress(self, d):
self._listener.size = d["total_bytes_estimate"] or 0
self._downloaded_bytes = d["downloaded_bytes"] or 0
self._eta = d.get("eta", "-") or "-"
- with contextlib.suppress(Exception):
+ with contextlib.suppress(builtins.BaseException):
self._progress = (self._downloaded_bytes / self._listener.size) * 100
async def _on_download_start(self, from_queue=False):
async with task_dict_lock:
task_dict[self._listener.mid] = YtDlpStatus(
- self._listener,
- self,
- self._gid,
+ self._listener, self, self._gid
)
if not from_queue:
await self._listener.on_download_start()
- if self._listener.multi <= 1:
+ if self._listener.multi <= 1 and not self._listener.is_rss:
await send_status_message(self._listener.message)
def _on_download_error(self, error):
@@ -163,21 +160,22 @@ def _extract_meta_data(self):
if not self._listener.name:
outtmpl_ = "%(series,playlist_title,channel)s%(season_number& |)s%(season_number&S|)s%(season_number|)02d.%(ext)s"
self._listener.name, ext = ospath.splitext(
- ydl.prepare_filename(entry, outtmpl=outtmpl_),
+ ydl.prepare_filename(entry, outtmpl=outtmpl_)
)
if not self._ext:
self._ext = ext
- return None
- outtmpl_ = "%(title,fulltitle,alt_title)s%(season_number& |)s%(season_number&S|)s%(season_number|)02d%(episode_number&E|)s%(episode_number|)02d%(height& |)s%(height|)s%(height&p|)s%(fps|)s%(fps&fps|)s%(tbr& |)s%(tbr|)d.%(ext)s"
- realName = ydl.prepare_filename(result, outtmpl=outtmpl_)
- ext = ospath.splitext(realName)[-1]
- self._listener.name = (
- f"{self._listener.name}{ext}" if self._listener.name else realName
- )
- if not self._ext:
- self._ext = ext
- return None
- return None
+ else:
+ outtmpl_ = "%(title,fulltitle,alt_title)s%(season_number& |)s%(season_number&S|)s%(season_number|)02d%(episode_number&E|)s%(episode_number|)02d%(height& |)s%(height|)s%(height&p|)s%(fps|)s%(fps&fps|)s%(tbr& |)s%(tbr|)d.%(ext)s"
+ realName = ydl.prepare_filename(result, outtmpl=outtmpl_)
+ ext = ospath.splitext(realName)[-1]
+ self._listener.name = (
+ f"{self._listener.name}{ext}"
+ if self._listener.name
+ else realName
+ )
+ if not self._ext:
+ self._ext = ext
+ return None
def _download(self, path):
try:
@@ -192,7 +190,7 @@ def _download(self, path):
not ospath.exists(path) or len(listdir(path)) == 0
):
self._on_download_error(
- "No video available to download from this playlist. Check logs for more details",
+ "No video available to download from this playlist. Check logs for more details"
)
return
if self._listener.is_cancelled:
@@ -217,7 +215,7 @@ async def add_download(self, path, qual, playlist, options):
"add_infojson": "if_exists",
"add_metadata": True,
"key": "FFmpegMetadata",
- },
+ }
]
if qual.startswith("ba/b-"):
@@ -230,7 +228,7 @@ async def add_download(self, path, qual, playlist, options):
"key": "FFmpegExtractAudio",
"preferredcodec": audio_format,
"preferredquality": rate,
- },
+ }
)
if audio_format == "vorbis":
self._ext = ".ogg"
@@ -239,6 +237,9 @@ async def add_download(self, path, qual, playlist, options):
else:
self._ext = f".{audio_format}"
+ if not self._listener.is_leech or self._listener.thumbnail_layout:
+ self.opts["writethumbnail"] = False
+
if options:
self._set_options(options)
@@ -258,15 +259,16 @@ async def add_download(self, path, qual, playlist, options):
)
base_name = ospath.splitext(self._listener.name)[0]
+ start_path = path if self.keep_thumb else f"{path}/yt-dlp-thumb"
if self.is_playlist:
self.opts["outtmpl"] = {
"default": f"{path}/{self._listener.name}/%(title,fulltitle,alt_title)s%(season_number& |)s%(season_number&S|)s%(season_number|)02d%(episode_number&E|)s%(episode_number|)02d%(height& |)s%(height|)s%(height&p|)s%(fps|)s%(fps&fps|)s%(tbr& |)s%(tbr|)d.%(ext)s",
- "thumbnail": f"{path}/yt-dlp-thumb/%(title,fulltitle,alt_title)s%(season_number& |)s%(season_number&S|)s%(season_number|)02d%(episode_number&E|)s%(episode_number|)02d%(height& |)s%(height|)s%(height&p|)s%(fps|)s%(fps&fps|)s%(tbr& |)s%(tbr|)d.%(ext)s",
+ "thumbnail": f"{start_path}/%(title,fulltitle,alt_title)s%(season_number& |)s%(season_number&S|)s%(season_number|)02d%(episode_number&E|)s%(episode_number|)02d%(height& |)s%(height|)s%(height&p|)s%(fps|)s%(fps&fps|)s%(tbr& |)s%(tbr|)d.%(ext)s",
}
elif "download_ranges" in options:
self.opts["outtmpl"] = {
"default": f"{path}/{base_name}/%(section_number|)s%(section_number&.|)s%(section_title|)s%(section_title&-|)s%(title,fulltitle,alt_title)s %(section_start)s to %(section_end)s.%(ext)s",
- "thumbnail": f"{path}/yt-dlp-thumb/%(section_number|)s%(section_number&.|)s%(section_title|)s%(section_title&-|)s%(title,fulltitle,alt_title)s %(section_start)s to %(section_end)s.%(ext)s",
+ "thumbnail": f"{start_path}/%(section_number|)s%(section_number&.|)s%(section_title|)s%(section_title&-|)s%(title,fulltitle,alt_title)s %(section_start)s to %(section_end)s.%(ext)s",
}
elif any(
key in options
@@ -276,31 +278,32 @@ async def add_download(self, path, qual, playlist, options):
"writeannotations",
"writedesktoplink",
"writewebloclink",
+ "writelink",
"writeurllink",
"writesubtitles",
- "writeautomaticsub",
+ "write_all_thumbnails",
]
):
self.opts["outtmpl"] = {
"default": f"{path}/{base_name}/{self._listener.name}",
- "thumbnail": f"{path}/yt-dlp-thumb/{base_name}.%(ext)s",
+ "thumbnail": f"{start_path}/{base_name}.%(ext)s",
}
else:
self.opts["outtmpl"] = {
"default": f"{path}/{self._listener.name}",
- "thumbnail": f"{path}/yt-dlp-thumb/{base_name}.%(ext)s",
+ "thumbnail": f"{start_path}/{base_name}.%(ext)s",
}
if qual.startswith("ba/b"):
self._listener.name = f"{base_name}{self._ext}"
- if self._listener.is_leech and not self._listener.thumbnail_layout:
+ if self.opts["writethumbnail"]:
self.opts["postprocessors"].append(
{
"format": "jpg",
"key": "FFmpegThumbnailsConvertor",
"when": "before_dl",
- },
+ }
)
if self._ext in [
".mp3",
@@ -316,15 +319,10 @@ async def add_download(self, path, qual, playlist, options):
]:
self.opts["postprocessors"].append(
{
- "already_have_thumbnail": bool(
- self._listener.is_leech
- and not self._listener.thumbnail_layout,
- ),
+ "already_have_thumbnail": self.opts["writethumbnail"],
"key": "EmbedThumbnail",
- },
+ }
)
- elif not self._listener.is_leech:
- self.opts["writethumbnail"] = False
msg, button = await stop_duplicate_check(self._listener)
if msg:
@@ -336,9 +334,7 @@ async def add_download(self, path, qual, playlist, options):
LOGGER.info(f"Added to Queue/Download: {self._listener.name}")
async with task_dict_lock:
task_dict[self._listener.mid] = QueueStatus(
- self._listener,
- self._gid,
- "dl",
+ self._listener, self._gid, "dl"
)
await event.wait()
if self._listener.is_cancelled:
@@ -365,6 +361,8 @@ def _set_options(self, options):
self.opts[key].append(value)
elif key == "download_ranges":
if isinstance(value, list):
- self.opts[key] = lambda info, ytdl: value
+ self.opts[key] = lambda _, __, value=value: value
else:
+ if key == "writethumbnail" and value is True:
+ self.keep_thumb = True
self.opts[key] = value
diff --git a/bot/helper/mirror_leech_utils/gdrive_utils/clone.py b/bot/helper/mirror_leech_utils/gdrive_utils/clone.py
index f43a8e4cc..d9f94cca7 100644
--- a/bot/helper/mirror_leech_utils/gdrive_utils/clone.py
+++ b/bot/helper/mirror_leech_utils/gdrive_utils/clone.py
@@ -121,11 +121,20 @@ def _clone_folder(self, folder_name, folder_id, dest_id):
current_dir_id = self.create_directory(file.get("name"), dest_id)
self._clone_folder(file_path, file.get("id"), current_dir_id)
elif (
- not file.get("name")
+ self.listener.included_extensions
+ and not file.get("name")
+ .strip()
+ .lower()
+ .endswith(tuple(self.listener.included_extensions))
+ ) or (
+ not self.listener.included_extensions
+ and file.get("name")
.strip()
.lower()
.endswith(tuple(self.listener.excluded_extensions))
):
+ continue
+ else:
self.total_files += 1
self._copy_file(file.get("id"), dest_id)
self.proc_bytes += int(file.get("size", 0))
diff --git a/bot/helper/mirror_leech_utils/gdrive_utils/download.py b/bot/helper/mirror_leech_utils/gdrive_utils/download.py
index 6c65415cb..c692744a2 100644
--- a/bot/helper/mirror_leech_utils/gdrive_utils/download.py
+++ b/bot/helper/mirror_leech_utils/gdrive_utils/download.py
@@ -86,11 +86,23 @@ def _download_folder(self, folder_id, path, folder_name):
mime_type = item.get("mimeType")
if mime_type == self.G_DRIVE_DIR_MIME_TYPE:
self._download_folder(file_id, path, filename)
- elif not ospath.isfile(
- f"{path}{filename}",
- ) and not filename.strip().lower().endswith(
- tuple(self.listener.excluded_extensions),
+ elif (
+ ospath.isfile(f"{path}{filename}")
+ or (
+ self.listener.included_extensions
+ and not filename.strip()
+ .lower()
+ .endswith(tuple(self.listener.included_extensions))
+ )
+ or (
+ not self.listener.included_extensions
+ and filename.strip()
+ .lower()
+ .endswith(tuple(self.listener.excluded_extensions))
+ )
):
+ continue
+ else:
self._download_file(file_id, path, filename, mime_type)
if self.listener.is_cancelled:
break
diff --git a/bot/helper/mirror_leech_utils/gdrive_utils/search.py b/bot/helper/mirror_leech_utils/gdrive_utils/search.py
index 3e10a99c0..b0866b490 100644
--- a/bot/helper/mirror_leech_utils/gdrive_utils/search.py
+++ b/bot/helper/mirror_leech_utils/gdrive_utils/search.py
@@ -116,7 +116,8 @@ def drive_list(self, file_name, target_id="", user_id=""):
else:
drives = zip(drives_names, drives_ids, index_urls, strict=False)
if (
- not target_id.startswith("mtp:") and len(drives_ids) > 1
+ target_id.startswith("mtp:")
+ or (not target_id.startswith("mtp:") and len(drives_ids) > 1)
) or target_id.startswith("tp:"):
self.use_sa = False
@@ -145,7 +146,7 @@ def drive_list(self, file_name, target_id="", user_id=""):
msg += f"📁 {file.get('name')}
(folder)
"
msg += f"Drive Link"
if index_url:
- url = f"{index_url}/findpath?id={file.get('id')}"
+ url = f"{index_url}findpath?id={file.get('id')}"
msg += f' | Index Link'
elif mime_type == "application/vnd.google-apps.shortcut":
furl = self.G_DRIVE_DIR_BASE_DOWNLOAD_URL.format(file.get("id"))
@@ -158,11 +159,11 @@ def drive_list(self, file_name, target_id="", user_id=""):
msg += f"📄 {file.get('name')}
({get_readable_file_size(int(file.get('size', 0)))})
"
msg += f"Drive Link"
if index_url:
- url = f"{index_url}/findpath?id={file.get('id')}"
+ url = f"{index_url}findpath?id={file.get('id')}"
msg += f' | Index Link'
if mime_type.startswith(("image", "video", "audio")):
urlv = (
- f"{index_url}/findpath?id={file.get('id')}&view=true"
+ f"{index_url}findpath?id={file.get('id')}&view=true"
)
msg += f' | View Link'
msg += "
"
diff --git a/bot/helper/mirror_leech_utils/gdrive_utils/upload.py b/bot/helper/mirror_leech_utils/gdrive_utils/upload.py
index 5534f792c..c012703ea 100644
--- a/bot/helper/mirror_leech_utils/gdrive_utils/upload.py
+++ b/bot/helper/mirror_leech_utils/gdrive_utils/upload.py
@@ -13,6 +13,7 @@
wait_exponential,
)
+from bot import intervals
from bot.core.config_manager import Config
from bot.helper.ext_utils.bot_utils import SetInterval, async_to_sync
from bot.helper.ext_utils.files_utils import get_mime_type
@@ -119,6 +120,11 @@ def _upload_dir(self, input_directory, dest_id):
new_id = None
for item in list_dirs:
current_file_name = ospath.join(input_directory, item)
+ if not ospath.exists(current_file_name):
+ if intervals["stopAll"]:
+ return None
+ LOGGER.error(f"{current_file_name} not exists! Continue uploading!")
+ continue
if ospath.isdir(current_file_name):
current_dir_id = self.create_directory(item, dest_id)
new_id = self._upload_dir(
diff --git a/bot/helper/mirror_leech_utils/gofile_utils/upload.py b/bot/helper/mirror_leech_utils/gofile_utils/upload.py
index 6ed074dcf..92a8942db 100644
--- a/bot/helper/mirror_leech_utils/gofile_utils/upload.py
+++ b/bot/helper/mirror_leech_utils/gofile_utils/upload.py
@@ -18,6 +18,7 @@
wait_exponential,
)
+from bot import user_data
from bot.core.config_manager import Config
from bot.helper.ext_utils.bot_utils import SetInterval, sync_to_async
@@ -53,8 +54,6 @@ def __init__(self, listener, path):
self.update_interval = 3
# Get user-specific token or fall back to global config
- from bot import user_data
-
user_dict = user_data.get(self.listener.user_id, {})
self.token = user_dict.get("GOFILE_TOKEN") or Config.GOFILE_API
self.folder_id = (
@@ -111,9 +110,11 @@ async def __resp_handler(self, response):
)
async def __getServer(self):
- async with ClientSession() as session:
- async with session.get(f"{self.api_url}servers") as resp:
- return await self.__resp_handler(await resp.json())
+ async with (
+ ClientSession() as session,
+ session.get(f"{self.api_url}servers") as resp,
+ ):
+ return await self.__resp_handler(await resp.json())
async def __getAccount(self, check_account=False):
if self.token is None:
@@ -174,23 +175,25 @@ async def upload_aiohttp(self, url, file_path, req_file, data):
filename=file_path, read_callback=self.__progress_callback
) as file:
data[req_file] = file
- async with ClientSession() as session:
- async with session.post(url, data=data) as resp:
- if resp.status == 200:
- try:
- return await resp.json()
- except ContentTypeError:
- return {
- "status": "ok",
- "data": {"downloadPage": "Uploaded"},
- }
- except JSONDecodeError:
- return {
- "status": "ok",
- "data": {"downloadPage": "Uploaded"},
- }
- else:
- raise Exception(f"HTTP {resp.status}: {await resp.text()}")
+ async with (
+ ClientSession() as session,
+ session.post(url, data=data) as resp,
+ ):
+ if resp.status == 200:
+ try:
+ return await resp.json()
+ except ContentTypeError:
+ return {
+ "status": "ok",
+ "data": {"downloadPage": "Uploaded"},
+ }
+ except JSONDecodeError:
+ return {
+ "status": "ok",
+ "data": {"downloadPage": "Uploaded"},
+ }
+ else:
+ raise Exception(f"HTTP {resp.status}: {await resp.text()}")
return None
async def create_folder(self, parentFolderId, folderName):
@@ -340,7 +343,7 @@ async def upload(self):
if (
self.listener.is_cancelled and not self._is_errored
) or self._is_errored:
- return
+ pass
async def _upload_process(self):
if not await self.is_goapi(self.token):
diff --git a/bot/helper/mirror_leech_utils/rclone_utils/transfer.py b/bot/helper/mirror_leech_utils/rclone_utils/transfer.py
index 01699ff7c..c71e4c7ba 100644
--- a/bot/helper/mirror_leech_utils/rclone_utils/transfer.py
+++ b/bot/helper/mirror_leech_utils/rclone_utils/transfer.py
@@ -1,5 +1,5 @@
import contextlib
-from asyncio import create_subprocess_exec, gather, sleep, wait_for
+from asyncio import create_subprocess_exec, gather, wait_for
from asyncio.subprocess import PIPE
from configparser import RawConfigParser
from json import loads
@@ -33,7 +33,6 @@ def __init__(self, listener):
self._sa_index = 0
self._sa_number = 0
self._use_service_accounts = Config.USE_SERVICE_ACCOUNTS
- self._rclone_select = False
@property
def transferred_size(self):
@@ -79,7 +78,6 @@ async def _progress(self):
self._speed,
self._eta,
) = data[0]
- await sleep(0.5)
def _switch_service_account(self):
if self._sa_index == self._sa_number - 1:
@@ -473,11 +471,10 @@ def _get_updated_command(
destination,
method,
):
+ rclone_select = False
if source.split(":")[-1].startswith("rclone_select"):
source = f"{source.split(':')[0]}:"
- self._rclone_select = True
- else:
- ext = "*.{" + ",".join(self._listener.excluded_extensions) + "}"
+ rclone_select = True
cmd = [
"xone",
method,
@@ -495,9 +492,13 @@ def _get_updated_command(
"1",
"-M",
]
- if self._rclone_select:
+ if rclone_select:
cmd.extend(("--files-from", self._listener.link))
+ elif self._listener.included_extensions:
+ ext = "*.{" + ",".join(self._listener.included_extensions) + "}"
+ cmd.extend(("--include", ext))
else:
+ ext = "*.{" + ",".join(self._listener.excluded_extensions) + "}"
cmd.extend(("--exclude", ext))
if rcflags := self._listener.rc_flags:
rcflags = rcflags.split("|")
diff --git a/bot/helper/mirror_leech_utils/status_utils/nzb_status.py b/bot/helper/mirror_leech_utils/status_utils/nzb_status.py
index 550c1673b..063737e4a 100644
--- a/bot/helper/mirror_leech_utils/status_utils/nzb_status.py
+++ b/bot/helper/mirror_leech_utils/status_utils/nzb_status.py
@@ -10,6 +10,8 @@
async def get_download(nzo_id, old_info=None):
+ if old_info is None:
+ old_info = {}
try:
queue = await sabnzbd_client.get_downloads(nzo_ids=nzo_id)
if res := queue["queue"]["slots"]:
@@ -56,26 +58,30 @@ def __init__(self, listener, gid, queued=False):
self.queued = queued
self.listener = listener
self._gid = gid
- self._info = None
+ self._info = {}
self.tool = "sabnzbd"
async def update(self):
self._info = await get_download(self._gid, self._info)
def progress(self):
- return f"{self._info['percentage']}%"
+ return f"{self._info.get('percentage', '0')}%"
def processed_raw(self):
- return (float(self._info["mb"]) - float(self._info["mbleft"])) * 1048576
+ return (
+ float(self._info.get("mb", "0")) - float(self._info.get("mbleft", "0"))
+ ) * 1048576
def processed_bytes(self):
return get_readable_file_size(self.processed_raw())
def speed_raw(self):
- if self._info["mb"] == self._info["mbleft"]:
+ if self._info.get("mb", "0") == self._info.get("mbleft", "0"):
return 0
try:
- return int(float(self._info["mbleft"]) * 1048576) / self.eta_raw()
+ return (
+ int(float(self._info.get("mbleft", "0")) * 1048576) / self.eta_raw()
+ )
except Exception:
return 0
@@ -83,22 +89,22 @@ def speed(self):
return f"{get_readable_file_size(self.speed_raw())}/s"
def name(self):
- return self._info["filename"]
+ return self._info.get("filename", "")
def size(self):
- return self._info["size"]
+ return self._info.get("size", 0)
def eta_raw(self):
- return int(time_to_seconds(self._info["timeleft"]))
+ return int(time_to_seconds(self._info.get("timeleft", "0")))
def eta(self):
return get_readable_time(self.eta_raw())
async def status(self):
await self.update()
- if self._info["mb"] == self._info["mbleft"]:
+ if self._info.get("mb", "0") == self._info.get("mbleft", "0"):
return MirrorStatus.STATUS_QUEUEDL
- state = self._info["status"]
+ state = self._info.get("status")
if state == "Paused" and self.queued:
return MirrorStatus.STATUS_QUEUEDL
if state in [
diff --git a/bot/helper/mirror_leech_utils/telegram_uploader.py b/bot/helper/mirror_leech_utils/telegram_uploader.py
index cdb4dbf61..5d37ac383 100644
--- a/bot/helper/mirror_leech_utils/telegram_uploader.py
+++ b/bot/helper/mirror_leech_utils/telegram_uploader.py
@@ -30,8 +30,9 @@
wait_exponential,
)
-from bot.core.aeon_client import TgClient
+from bot import intervals
from bot.core.config_manager import Config
+from bot.core.telegram_manager import TgClient
from bot.helper.aeon_utils.caption_gen import generate_caption
from bot.helper.ext_utils.bot_utils import sync_to_async
from bot.helper.ext_utils.files_utils import (
@@ -113,7 +114,6 @@ async def _msg_to_reply(self):
self._sent_msg = await TgClient.user.send_message(
chat_id=self._listener.up_dest,
text=msg,
- disable_web_page_preview=True,
message_thread_id=self._listener.chat_thread_id,
disable_notification=True,
)
@@ -121,7 +121,6 @@ async def _msg_to_reply(self):
self._sent_msg = await self._listener.client.send_message(
chat_id=self._listener.up_dest,
text=msg,
- disable_web_page_preview=True,
message_thread_id=self._listener.chat_thread_id,
disable_notification=True,
)
@@ -139,7 +138,6 @@ async def _msg_to_reply(self):
self._sent_msg = await TgClient.user.send_message(
chat_id=self._listener.message.chat.id,
text="Deleted Cmd Message! Don't delete the cmd message again!",
- disable_web_page_preview=True,
disable_notification=True,
)
else:
@@ -249,6 +247,8 @@ async def upload(self):
self._error = ""
self._up_path = f_path = ospath.join(dirpath, file_)
if not await aiopath.exists(self._up_path):
+ if intervals["stopAll"]:
+ return
LOGGER.error(f"{self._up_path} not exists! Continue uploading!")
continue
try:
@@ -339,7 +339,7 @@ async def upload(self):
return
if self._total_files == 0:
await self._listener.on_upload_error(
- "No files to upload. In case you have filled EXCLUDED_EXTENSIONS, then check if all files have those extensions or not.",
+ "No files to upload. In case you have filled EXCLUDED/INCLUDED EXTENSIONS, then check if all files have those extensions or not.",
)
return
if self._total_files <= self._corrupted:
@@ -378,6 +378,8 @@ async def _upload_file(self, cap_mono, file, o_path, force_document=False):
thumb_path = f"{self._path}/yt-dlp-thumb/{file_name}.jpg"
if await aiopath.isfile(thumb_path):
thumb = thumb_path
+ elif await aiopath.isfile(thumb_path.replace("/yt-dlp-thumb", "")):
+ thumb = thumb_path.replace("/yt-dlp-thumb", "")
elif is_audio and not is_video:
thumb = await get_audio_thumbnail(self._up_path)
diff --git a/bot/helper/telegram_helper/message_utils.py b/bot/helper/telegram_helper/message_utils.py
index 7320ac720..8a3669316 100644
--- a/bot/helper/telegram_helper/message_utils.py
+++ b/bot/helper/telegram_helper/message_utils.py
@@ -20,8 +20,8 @@
task_dict_lock,
user_data,
)
-from bot.core.aeon_client import TgClient
from bot.core.config_manager import Config
+from bot.core.telegram_manager import TgClient
from bot.helper.ext_utils.bot_utils import SetInterval
from bot.helper.ext_utils.exceptions import TgLinkException
from bot.helper.ext_utils.status_utils import get_readable_message
@@ -43,7 +43,6 @@ async def send_message(
return await TgClient.bot.send_message(
chat_id=message,
text=text,
- disable_web_page_preview=True,
disable_notification=True,
reply_markup=buttons,
parse_mode=parse_mode,
@@ -60,7 +59,6 @@ async def send_message(
return await message.reply(
text=text,
quote=True,
- disable_web_page_preview=True,
disable_notification=True,
reply_markup=buttons,
parse_mode=parse_mode,
@@ -100,7 +98,6 @@ async def edit_message(
)
await message.edit(
text=text,
- disable_web_page_preview=True,
reply_markup=buttons,
# parse_mode=parse_mode,
)
@@ -141,7 +138,6 @@ async def send_rss(text, chat_id, thread_id):
return await app.send_message(
chat_id=chat_id,
text=text,
- disable_web_page_preview=True,
message_thread_id=thread_id,
disable_notification=True,
)
diff --git a/bot/modules/bot_settings.py b/bot/modules/bot_settings.py
index d6caf1141..baf70c8f6 100644
--- a/bot/modules/bot_settings.py
+++ b/bot/modules/bot_settings.py
@@ -22,6 +22,7 @@
drives_ids,
drives_names,
excluded_extensions,
+ included_extensions,
index_urls,
intervals,
jd_listener_lock,
@@ -30,10 +31,10 @@
sudo_users,
task_dict,
)
-from bot.core.aeon_client import TgClient
from bot.core.config_manager import Config
from bot.core.jdownloader_booter import jdownloader
from bot.core.startup import update_nzb_options, update_variables
+from bot.core.telegram_manager import TgClient
from bot.core.torrent_manager import TorrentManager
from bot.helper.ext_utils.bot_utils import SetInterval, new_task
from bot.helper.ext_utils.db_handler import database
@@ -216,6 +217,12 @@ async def edit_variable(_, message, pre_message, key):
for x in fx:
x = x.lstrip(".")
excluded_extensions.append(x.strip().lower())
+ elif key == "INCLUDED_EXTENSIONS":
+ fx = value.split()
+ included_extensions.clear()
+ for x in fx:
+ x = x.lstrip(".")
+ included_extensions.append(x.strip().lower())
elif key == "GDRIVE_ID":
if drives_names and drives_names[0] == "Main":
drives_ids[0] = value
@@ -223,9 +230,9 @@ async def edit_variable(_, message, pre_message, key):
drives_ids.insert(0, value)
elif key == "INDEX_URL":
if drives_names and drives_names[0] == "Main":
- index_urls[0] = value.strip("/")
+ index_urls[0] = value
else:
- index_urls.insert(0, value.strip("/"))
+ index_urls.insert(0, value)
elif key == "AUTHORIZED_CHATS":
aid = value.split()
auth_chats.clear()
@@ -400,7 +407,7 @@ async def update_private_file(_, message, pre_message):
drives_ids.append(temp[1])
drives_names.append(temp[0].replace("_", " "))
if len(temp) > 2:
- index_urls.append(temp[2]).strip("/")
+ index_urls.append(temp[2])
else:
index_urls.append("")
elif file_name in [".netrc", "netrc"]:
@@ -466,7 +473,7 @@ async def edit_bot_settings(client, query):
)
return
await query.answer(
- "Syncronization Started. JDownloader will get restarted. It takes up to 10 sec!",
+ "Synchronization Started. JDownloader will get restarted. It takes up to 10 sec!",
show_alert=True,
)
await sync_jdownloader()
@@ -479,12 +486,24 @@ async def edit_bot_settings(client, query):
await update_buttons(message, data[1])
elif data[1] == "resetvar":
await query.answer()
- value = ""
+ expected_type = type(getattr(Config, data[2]))
+ if expected_type is bool:
+ value = False
+ elif expected_type is int:
+ value = 0
+ elif expected_type is str:
+ value = ""
+ elif expected_type is list:
+ value = []
+ elif expected_type is dict:
+ value = {}
if data[2] in DEFAULT_VALUES:
value = DEFAULT_VALUES[data[2]]
elif data[2] == "EXCLUDED_EXTENSIONS":
excluded_extensions.clear()
excluded_extensions.extend(["aria2", "!qB"])
+ elif data[2] == "INCLUDED_EXTENSIONS":
+ included_extensions.clear()
elif data[2] == "TORRENT_TIMEOUT":
await TorrentManager.change_aria2_option("bt-stop-timeout", "0")
await database.update_aria2("bt-stop-timeout", "0")
@@ -542,7 +561,7 @@ async def edit_bot_settings(client, query):
await database.update_nzb_config()
elif data[1] == "syncnzb":
await query.answer(
- "Syncronization Started. It takes up to 2 sec!",
+ "Synchronization Started. It takes up to 2 sec!",
show_alert=True,
)
nzb_options.clear()
diff --git a/bot/modules/cancel_task.py b/bot/modules/cancel_task.py
index 1adc72ec5..42cb3404f 100644
--- a/bot/modules/cancel_task.py
+++ b/bot/modules/cancel_task.py
@@ -1,7 +1,7 @@
from asyncio import sleep
from bot import multi_tags, task_dict, task_dict_lock, user_data
-from bot.core.aeon_client import Config
+from bot.core.telegram_manager import Config
from bot.helper.ext_utils.bot_utils import new_task
from bot.helper.ext_utils.status_utils import (
MirrorStatus,
diff --git a/bot/modules/clone.py b/bot/modules/clone.py
index 27b96c0cd..399159642 100644
--- a/bot/modules/clone.py
+++ b/bot/modules/clone.py
@@ -97,9 +97,9 @@ async def new_event(self):
if not isinstance(is_bulk, bool):
dargs = is_bulk.split(":")
- bulk_start = dargs[0] or 0
+ bulk_start = dargs[0] or "0"
if len(dargs) == 2:
- bulk_end = dargs[1] or 0
+ bulk_end = dargs[1] or "0"
is_bulk = True
if is_bulk:
diff --git a/bot/modules/exec.py b/bot/modules/exec.py
index 971884623..ba3341f1e 100644
--- a/bot/modules/exec.py
+++ b/bot/modules/exec.py
@@ -8,7 +8,7 @@
from aiofiles import open as aiopen
from bot import LOGGER
-from bot.core.aeon_client import TgClient
+from bot.core.telegram_manager import TgClient
from bot.helper.ext_utils.bot_utils import new_task, sync_to_async
from bot.helper.telegram_helper.message_utils import send_file, send_message
diff --git a/bot/modules/file_selector.py b/bot/modules/file_selector.py
index def7385df..a91646100 100644
--- a/bot/modules/file_selector.py
+++ b/bot/modules/file_selector.py
@@ -50,7 +50,7 @@ async def select(_, message):
await send_message(message, "This task is not for you!")
return
if not iscoroutinefunction(task.status):
- await send_message(message, "The task have finshed the download stage!")
+ await send_message(message, "The task have finished the download stage!")
return
if await task.status() not in [
MirrorStatus.STATUS_DOWNLOAD,
diff --git a/bot/modules/force_start.py b/bot/modules/force_start.py
index e416e7082..719258b03 100644
--- a/bot/modules/force_start.py
+++ b/bot/modules/force_start.py
@@ -37,7 +37,7 @@ async def remove_from_queue(_, message):
elif len(msg) in {1, 2}:
msg = f"""Reply to an active Command message which was used to start the download/upload.
/{BotCommands.ForceStartCommand[0]} fd (to remove it from download queue) or fu (to remove it from upload queue) or nothing to start remove it from both download and upload queue.
-Also send /{BotCommands.ForceStartCommand[0]} GID fu|fd or obly gid to force start by removeing the task rom queue!
+Also send /{BotCommands.ForceStartCommand[0]} GID fu|fd or obly gid to force start by removing the task rom queue!
Examples:
/{BotCommands.ForceStartCommand[1]} GID fu (force upload)
/{BotCommands.ForceStartCommand[1]} GID (force download and upload)
diff --git a/bot/modules/mediainfo.py b/bot/modules/mediainfo.py
index 88888768d..0b180b888 100644
--- a/bot/modules/mediainfo.py
+++ b/bot/modules/mediainfo.py
@@ -10,7 +10,7 @@
from aiofiles.os import remove as aioremove
from bot import LOGGER
-from bot.core.aeon_client import TgClient
+from bot.core.telegram_manager import TgClient
from bot.helper.aeon_utils.access_check import token_check
from bot.helper.ext_utils.bot_utils import cmd_exec
from bot.helper.ext_utils.telegraph_helper import telegraph
diff --git a/bot/modules/mirror_leech.py b/bot/modules/mirror_leech.py
index cecf76074..4baac8938 100644
--- a/bot/modules/mirror_leech.py
+++ b/bot/modules/mirror_leech.py
@@ -9,7 +9,7 @@
from truelink.types import FolderResult, LinkResult
from bot import DOWNLOAD_DIR, LOGGER, bot_loop, task_dict_lock
-from bot.core.aeon_client import TgClient
+from bot.core.telegram_manager import TgClient
from bot.helper.aeon_utils.access_check import error_check
from bot.helper.ext_utils.bot_utils import (
COMMAND_USAGE,
@@ -220,9 +220,9 @@ async def new_event(self):
if not isinstance(is_bulk, bool):
dargs = is_bulk.split(":")
- bulk_start = dargs[0] or 0
+ bulk_start = dargs[0] or "0"
if len(dargs) == 2:
- bulk_end = dargs[1] or 0
+ bulk_end = dargs[1] or "0"
is_bulk = True
if not is_bulk:
diff --git a/bot/modules/restart.py b/bot/modules/restart.py
index f4ca8cecd..31f94676d 100644
--- a/bot/modules/restart.py
+++ b/bot/modules/restart.py
@@ -8,9 +8,9 @@
from aiofiles.os import remove
from bot import LOGGER, intervals, sabnzbd_client, scheduler
-from bot.core.aeon_client import TgClient
from bot.core.config_manager import Config
from bot.core.jdownloader_booter import jdownloader
+from bot.core.telegram_manager import TgClient
from bot.core.torrent_manager import TorrentManager
from bot.helper.ext_utils.bot_utils import new_task
from bot.helper.ext_utils.db_handler import database
@@ -39,14 +39,12 @@ async def send_incomplete_task_message(cid, msg_id, msg):
chat_id=cid,
message_id=msg_id,
text=msg,
- disable_web_page_preview=True,
)
await remove(".restartmsg")
else:
await TgClient.bot.send_message(
chat_id=cid,
text=msg,
- disable_web_page_preview=True,
disable_notification=True,
)
except Exception as e:
diff --git a/bot/modules/rss.py b/bot/modules/rss.py
index 0a1acbd3f..48791b892 100644
--- a/bot/modules/rss.py
+++ b/bot/modules/rss.py
@@ -91,7 +91,7 @@ async def rss_sub(_, message, pre_event):
if len(args) < 2:
await send_message(
message,
- f"{item}. Wrong Input format. Read help message before adding new subcription!",
+ f"{item}. Wrong Input format. Read help message before adding new subscription!",
)
continue
title = args[0].strip()
@@ -136,10 +136,7 @@ async def rss_sub(_, message, pre_event):
stv = False
try:
async with AsyncClient(
- headers=headers,
- follow_redirects=True,
- timeout=60,
- verify=False,
+ headers=headers, follow_redirects=True, timeout=60, verify=False
) as client:
res = await client.get(feed_link)
html = res.text
@@ -194,10 +191,10 @@ async def rss_sub(_, message, pre_event):
"command": cmd,
"sensitive": stv,
"tag": tag,
- },
+ }
}
LOGGER.info(
- f"Rss Feed Added: id: {user_id} - title: {title} - link: {feed_link} - c: {cmd} - inf: {inf} - exf: {exf} - stv: {stv}",
+ f"Rss Feed Added: id: {user_id} - title: {title} - link: {feed_link} - c: {cmd} - inf: {inf} - exf: {exf} - stv: {stv}"
)
except (IndexError, AttributeError) as e:
emsg = f"The link: {feed_link} doesn't seem to be a RSS feed or it's region-blocked!"
@@ -291,7 +288,7 @@ async def rss_list(query, start, all_users=False):
index = 0
for titles in rss_dict.values():
for index, (title, data) in enumerate(
- list(titles.items())[start : 5 + start],
+ list(titles.items())[start : 5 + start]
):
list_feed += f"\n\nTitle: {title}\n"
list_feed += f"Feed Url: {data['link']}\n"
@@ -320,9 +317,7 @@ async def rss_list(query, start, all_users=False):
if keysCount > 5:
for x in range(0, keysCount, 5):
buttons.data_button(
- f"{int(x / 5)}",
- f"rss list {user_id} {x}",
- position="footer",
+ f"{int(x / 5)}", f"rss list {user_id} {x}", position="footer"
)
button = buttons.build_menu(2)
if query.message.text.html == list_feed:
@@ -338,7 +333,7 @@ async def rss_get(_, message, pre_event):
if len(args) < 2:
await send_message(
message,
- f"{args}. Wrong Input format. You should add number of the items you want to get. Read help message before adding new subcription!",
+ f"{args}. Wrong Input format. You should add number of the items you want to get. Read help message before adding new subscription!",
)
await update_rss_menu(pre_event)
return
@@ -349,14 +344,10 @@ async def rss_get(_, message, pre_event):
if data and count > 0:
try:
msg = await send_message(
- message,
- f"Getting the last {count} item(s) from {title}",
+ message, f"Getting the last {count} item(s) from {title}"
)
async with AsyncClient(
- headers=headers,
- follow_redirects=True,
- timeout=60,
- verify=False,
+ headers=headers, follow_redirects=True, timeout=60, verify=False
) as client:
res = await client.get(data["link"])
html = res.text
@@ -380,8 +371,7 @@ async def rss_get(_, message, pre_event):
except IndexError as e:
LOGGER.error(str(e))
await edit_message(
- msg,
- "Parse depth exceeded. Try again with a lower value.",
+ msg, "Parse depth exceeded. Try again with a lower value."
)
except Exception as e:
LOGGER.error(str(e))
@@ -470,12 +460,11 @@ async def event_filter(_, __, event):
return bool(
user.id == user_id
and event.chat.id == query.message.chat.id
- and event.text,
+ and event.text
)
handler = client.add_handler(
- MessageHandler(pfunc, create(event_filter)),
- group=-1,
+ MessageHandler(pfunc, create(event_filter)), group=-1
)
while handler_dict[user_id]:
await sleep(0.5)
@@ -492,8 +481,7 @@ async def rss_listener(client, query):
data = query.data.split()
if int(data[2]) != user_id and not await CustomFilters.sudo("", query):
await query.answer(
- text="You don't have permission to use these buttons!",
- show_alert=True,
+ text="You don't have permission to use these buttons!", show_alert=True
)
elif data[1] == "close":
await query.answer()
@@ -596,13 +584,13 @@ async def rss_listener(client, query):
await update_rss_menu(query)
elif data[1].endswith("pause"):
async with rss_dict_lock:
- for title in list(rss_dict[int(data[2])].keys()):
- rss_dict[int(data[2])][title]["paused"] = True
+ for info in rss_dict[int(data[2])].values():
+ info["paused"] = True
await database.rss_update(int(data[2]))
elif data[1].endswith("resume"):
async with rss_dict_lock:
- for title in list(rss_dict[int(data[2])].keys()):
- rss_dict[int(data[2])][title]["paused"] = False
+ for info in rss_dict[int(data[2])].values():
+ info["paused"] = False
if scheduler.state == 2:
scheduler.resume()
await database.rss_update(int(data[2]))
@@ -619,22 +607,23 @@ async def rss_listener(client, query):
await update_rss_menu(query)
elif data[1].endswith("pause"):
async with rss_dict_lock:
- for user in list(rss_dict.keys()):
- for title in list(rss_dict[user].keys()):
- rss_dict[int(data[2])][title]["paused"] = True
+ for user_feeds in rss_dict.values():
+ for feed in user_feeds.values():
+ feed["paused"] = True
if scheduler.running:
scheduler.pause()
await database.rss_update_all()
elif data[1].endswith("resume"):
async with rss_dict_lock:
- for user in list(rss_dict.keys()):
- for title in list(rss_dict[user].keys()):
- rss_dict[int(data[2])][title]["paused"] = False
+ for user_feeds in rss_dict.values():
+ for feed in user_feeds.values():
+ feed["paused"] = False
if scheduler.state == 2:
scheduler.resume()
elif not scheduler.running:
add_job()
scheduler.start()
+ await update_rss_menu(query)
await database.rss_update_all()
elif data[1] == "deluser":
if len(rss_dict) == 0:
@@ -695,10 +684,10 @@ async def rss_monitor():
rss_chat_id = int(chat)
for user, items in list(rss_dict.items()):
for title, data in items.items():
+ if data["paused"]:
+ continue
+ tries = 0
try:
- if data["paused"]:
- continue
- tries = 0
while True:
try:
async with AsyncClient(
@@ -716,13 +705,21 @@ async def rss_monitor():
raise
continue
rss_d = feed_parse(html)
- try:
- last_link = rss_d.entries[0]["links"][1]["href"]
- except IndexError:
- last_link = rss_d.entries[0]["link"]
- finally:
- all_paused = False
- last_title = rss_d.entries[0]["title"]
+ if not rss_d.entries:
+ LOGGER.warning(
+ f"No entries found for > Feed Title: {title} - Feed Link: {data['link']}"
+ )
+ continue
+ entry0 = rss_d.entries[0]
+ links = entry0.get("links", [])
+ if len(links) > 1:
+ last_link = links[1].get("href")
+ elif links:
+ last_link = links[0].get("href")
+ else:
+ last_link = entry0.get("link")
+ last_title = entry0.get("title")
+ all_paused = False
if (
data["last_feed"] == last_link
or data["last_title"] == last_title
@@ -732,8 +729,8 @@ async def rss_monitor():
while True:
try:
await sleep(10)
- except Exception:
- raise RssShutdownException("Rss Monitor Stopped!") from None
+ except Exception as e:
+ raise RssShutdownException("Rss Monitor Stopped!") from e
try:
item_title = rss_d.entries[feed_count]["title"]
try:
@@ -756,7 +753,7 @@ async def rss_monitor():
size = 0
except IndexError:
LOGGER.warning(
- f"Reached Max index no. {feed_count} for this feed: {title}. Maybe you need to use less RSS_DELAY to not miss some torrents",
+ f"Reached Max index no. {feed_count} for this feed: {title}. Maybe you need to use less RSS_DELAY to not miss some torrents"
)
break
parse = True
@@ -815,14 +812,11 @@ async def rss_monitor():
if user not in rss_dict or not rss_dict[user].get(title, False):
continue
rss_dict[user][title].update(
- {"last_feed": last_link, "last_title": last_title},
+ {"last_feed": last_link, "last_title": last_title}
)
await database.rss_update(user)
LOGGER.info(f"Feed Name: {title}")
LOGGER.info(f"Last item: {last_link}")
- except RssShutdownException as ex:
- LOGGER.info(ex)
- break
except Exception as e:
LOGGER.error(f"{e} - Feed Name: {title} - Feed Link: {data['link']}")
continue
diff --git a/bot/modules/services.py b/bot/modules/services.py
index 84f0b092a..93f6a25a4 100644
--- a/bot/modules/services.py
+++ b/bot/modules/services.py
@@ -5,8 +5,8 @@
from aiofiles import open as aiopen
from bot import LOGGER, user_data
-from bot.core.aeon_client import TgClient
from bot.core.config_manager import Config
+from bot.core.telegram_manager import TgClient
from bot.helper.ext_utils.bot_utils import new_task
from bot.helper.ext_utils.db_handler import database
from bot.helper.ext_utils.status_utils import get_readable_time
diff --git a/bot/modules/speedtest.py b/bot/modules/speedtest.py
index 7512850bd..19cfed9b8 100644
--- a/bot/modules/speedtest.py
+++ b/bot/modules/speedtest.py
@@ -1,7 +1,7 @@
from speedtest import Speedtest
from bot import LOGGER
-from bot.core.aeon_client import TgClient
+from bot.core.telegram_manager import TgClient
from bot.helper.ext_utils.bot_utils import new_task
from bot.helper.ext_utils.status_utils import get_readable_file_size
from bot.helper.telegram_helper.message_utils import (
diff --git a/bot/modules/stats.py b/bot/modules/stats.py
index b75e3ebe2..32258776b 100644
--- a/bot/modules/stats.py
+++ b/bot/modules/stats.py
@@ -42,6 +42,10 @@ async def bot_stats(_, message):
total, used, free, disk = disk_usage("/")
swap = swap_memory()
memory = virtual_memory()
+ per_cpu = cpu_percent(interval=1, percpu=True)
+ per_cpu_str = " | ".join(
+ [f"CPU{i + 1}: {round(p)}%" for i, p in enumerate(per_cpu)]
+ )
stats = f"""
Commit Date: {commands["commit"]}
@@ -54,7 +58,8 @@ async def bot_stats(_, message):
Upload: {get_readable_file_size(net_io_counters().bytes_sent)}
Download: {get_readable_file_size(net_io_counters().bytes_recv)}
-CPU: {cpu_percent(interval=0.5)}%
+CPU: {cpu_percent(interval=1)}%
+CPU Cores: {per_cpu_str}
RAM: {memory.percent}%
DISK: {disk}%
diff --git a/bot/modules/users_settings.py b/bot/modules/users_settings.py
index 3adca4736..4389ca7ad 100644
--- a/bot/modules/users_settings.py
+++ b/bot/modules/users_settings.py
@@ -11,9 +11,15 @@
from pyrogram.filters import create
from pyrogram.handlers import MessageHandler
-from bot import auth_chats, excluded_extensions, sudo_users, user_data
-from bot.core.aeon_client import TgClient
+from bot import (
+ auth_chats,
+ excluded_extensions,
+ included_extensions,
+ sudo_users,
+ user_data,
+)
from bot.core.config_manager import Config
+from bot.core.telegram_manager import TgClient
from bot.helper.ext_utils.bot_utils import (
get_size_bytes,
new_task,
@@ -289,7 +295,7 @@ async def get_user_settings(from_user, stype="main"):
and Config.UPLOAD_PATHS
):
upload_paths = Config.UPLOAD_PATHS
- else:
+ if not upload_paths:
upload_paths = "None"
buttons.data_button("Upload Paths", f"userset {user_id} menu UPLOAD_PATHS")
@@ -332,9 +338,23 @@ async def get_user_settings(from_user, stype="main"):
else:
ex_ex = "None"
- ns_msg = "Added" if user_dict.get("NAME_SUBSTITUTE", False) else "None"
buttons.data_button(
- "Name Subtitute",
+ "Included Extensions", f"userset {user_id} menu INCLUDED_EXTENSIONS"
+ )
+ if user_dict.get("INCLUDED_EXTENSIONS", False):
+ inc_ex = user_dict["INCLUDED_EXTENSIONS"]
+ elif "INCLUDED_EXTENSIONS" not in user_dict:
+ inc_ex = included_extensions
+ else:
+ inc_ex = "None"
+ if user_dict.get("NAME_SUBSTITUTE", False) or (
+ "NAME_SUBSTITUTE" not in user_dict and Config.NAME_SUBSTITUTE
+ ):
+ ns_msg = "Added"
+ else:
+ ns_msg = "None"
+ buttons.data_button(
+ "Name Substitute",
f"userset {user_id} menu NAME_SUBSTITUTE",
)
if user_dict.get("NAME_PREFIX", False):
@@ -392,6 +412,7 @@ async def get_user_settings(from_user, stype="main"):
Name substitution is {ns_msg}
Name prefix is {np_msg}
Excluded Extensions is {ex_ex}
+Included Extensions is {inc_ex}
YT-DLP Options is {ytopt}
FFMPEG Commands is {ffc}
Metadata is {mdt}
@@ -486,6 +507,12 @@ async def set_option(_, message, option):
for x in fx:
x = x.lstrip(".")
value.append(x.strip().lower())
+ elif option == "INCLUDED_EXTENSIONS":
+ fx = value.split()
+ value = []
+ for x in fx:
+ x = x.lstrip(".")
+ value.append(x.strip().lower())
elif option in ["UPLOAD_PATHS", "FFMPEG_CMDS", "YT_DLP_OPTIONS"]:
if value.startswith("{") and value.endswith("}"):
try:
@@ -579,7 +606,7 @@ async def ffmpeg_variables(
if ffc:
buttons = ButtonMaker()
if key is None:
- msg = "Choose which key you want to fill/edit varibales in it:"
+ msg = "Choose which key you want to fill/edit variables in it:"
for k, v in list(ffc.items()):
add = False
for i in v:
diff --git a/bot/modules/ytdlp.py b/bot/modules/ytdlp.py
index 64e62ed1c..57051d873 100644
--- a/bot/modules/ytdlp.py
+++ b/bot/modules/ytdlp.py
@@ -244,7 +244,7 @@ async def audio_quality(self, format):
buttons.data_button("Back", "ytq aq back")
buttons.data_button("Cancel", "ytq aq cancel")
subbuttons = buttons.build_menu(5)
- msg = f"Choose Audio{i} Qaulity:\n0 is best and 10 is worst\nTimeout: {get_readable_time(self._timeout - (time() - self._time))}"
+ msg = f"Choose Audio{i} Quality:\n0 is best and 10 is worst\nTimeout: {get_readable_time(self._timeout - (time() - self._time))}"
await edit_message(self._reply_to, msg, subbuttons)
diff --git a/config_sample.py b/config_sample.py
index 2fd037a3d..99e05f810 100644
--- a/config_sample.py
+++ b/config_sample.py
@@ -21,12 +21,13 @@
EXCLUDED_EXTENSIONS = (
"" # Space separated file extensions to exclude (e.g., .log .exe)
)
+INCLUDED_EXTENSIONS = ""
INCOMPLETE_TASK_NOTIFIER = (
False # Notify for incomplete tasks on restart (requires DATABASE_URL)
)
YT_DLP_OPTIONS = {} # Dictionary of yt-dlp options, e.g., {"format": "bestvideo+bestaudio/best"}
USE_SERVICE_ACCOUNTS = False
-NAME_SUBSTITUTE = "" # Replace/remove words: "source1/target1|source2/target2"
+NAME_SUBSTITUTE = r"" # Replace/remove words: "source1/target1|source2/target2"
FFMPEG_CMDS = {} # Predefined FFmpeg commands, e.g., {"preset_name": ["-vf", "scale=1280:-1"]}
UPLOAD_PATHS = {} # Named upload paths, e.g., {"movies": "remote:movies/", "tv": "gdrive_id_tv_folder"}
diff --git a/docs/CONFIGURATIONS.md b/docs/CONFIGURATIONS.md
index d020f8b8c..1d63d11d8 100644
--- a/docs/CONFIGURATIONS.md
+++ b/docs/CONFIGURATIONS.md
@@ -19,6 +19,7 @@
| `SUDO_USERS` | `str` | User IDs with sudo permission. Separate by spaces. |
| `UPLOAD_PATHS` | `dict` | Dict with upload paths. Example: `{"path 1": "remote:", "path 2": "gdrive id", ...}` |
| `DEFAULT_UPLOAD` | `str` | `rc` for `RCLONE_PATH`, `gd` for `GDRIVE_ID`. Default: `rc`. [Read More](https://github.com/anasty17/mirror-leech-telegram-bot/tree/master#upload). |
+| `INCLUDED_EXTENSIONS` | `str` | File extensions to be uploaded/cloned. `EXCLUDED_EXTENSIONS` will be ignore if you filled this ! Separate them by spaces. |
| `EXCLUDED_EXTENSIONS` | `str` | File extensions to skip during processing. Separate by spaces. |
| `INCOMPLETE_TASK_NOTIFIER`| `bool` | Notify after restart for incomplete tasks. Requires `DATABASE_URL` and the bot to be in a supergroup. Default: `False`. |
| `FILELION_API` | `str` | API key from [FileLion](https://vidhide.com/?op=my_account). |
diff --git a/myjd/myjdapi.py b/myjd/myjdapi.py
index af7bdc8c2..0584818f3 100644
--- a/myjd/myjdapi.py
+++ b/myjd/myjdapi.py
@@ -685,7 +685,7 @@ async def solve(self, captcha_id, solution):
class Jddevice:
def __init__(self, jd):
- """This functions initializates the device instance.
+ """This functions initializes the device instance.
It uses the provided dictionary to create the device.
:param device_dict: Device dictionary
diff --git a/sabnzbd/SABnzbd.ini b/sabnzbd/SABnzbd.ini
index 1c1408309..0bf183955 100644
--- a/sabnzbd/SABnzbd.ini
+++ b/sabnzbd/SABnzbd.ini
@@ -35,9 +35,9 @@ api_key = mltb
nzb_key = ""
socks5_proxy_url = ""
permissions = ""
-download_dir = /usr/src/app/downloads
+download_dir = /app/downloads
download_free = ""
-complete_dir = /usr/src/app/downloads
+complete_dir = /app/downloads
complete_free = ""
fulldisk_autoresume = 0
script_dir = ""
@@ -284,4 +284,4 @@ nscript_prio_new_login = 0
nscript_prio_warning = 0
nscript_prio_error = 0
nscript_prio_queue_done = 0
-nscript_prio_other = 1
\ No newline at end of file
+nscript_prio_other = 1