Skip to content
4 changes: 2 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
FROM 5hojib/aeon:latest

WORKDIR /usr/src/app
RUN chmod 777 /usr/src/app
WORKDIR /app
RUN chmod 777 /app

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

security-medium medium

Using chmod 777 is insecure as it gives read, write, and execute permissions to everyone on the /app directory. This could lead to security vulnerabilities. It's better to use more restrictive permissions. For example, if the application needs to be run by a non-root user, you could change the ownership of the directory and set more appropriate permissions.


RUN uv venv
COPY requirements.txt .
Expand Down
7 changes: 5 additions & 2 deletions bot/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,11 @@ def format(self, record: LogRecord) -> str:

LOGGER = getLogger(__name__)

cpu_no = os.cpu_count()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (bug_risk): Hard‑coding cpu_no, threads, and cores reduces portability and may misconfigure ffmpeg usage.

These fixed values are now fed directly into ffmpeg/taskset. On machines with different core counts, this can oversubscribe CPUs or reference non‑existent cores, causing failures. Please derive them from os.cpu_count() (optionally with a config override) and compute threads/cores dynamically with sensible limits.

Suggested implementation:

LOGGER = getLogger(__name__)

_cpu_count = os.cpu_count() or 1

# Allow overriding detected CPU count via environment, but never exceed the real count
cpu_no = int(os.getenv("CPU_NO", _cpu_count))
if cpu_no > _cpu_count:
    cpu_no = _cpu_count

# Default threads: do not exceed detected/overridden CPU count; allow env override
_default_threads = max(1, min(cpu_no, _cpu_count))
threads = int(os.getenv("FFMPEG_THREADS", _default_threads))
if threads > cpu_no:
    threads = cpu_no

# Core pinning: allow explicit override, otherwise pin to the first `threads` cores
_cores_override = os.getenv("FFMPEG_CORES")
if _cores_override:
    cores = _cores_override
else:
    cores = ",".join(str(i) for i in range(min(threads, _cpu_count)))
  1. Ensure import os is present near the top of bot/__init__.py:
    • If missing, add import os alongside the other imports.
  2. If your project uses a configuration system instead of environment variables, you may want to replace the os.getenv(...) calls with the appropriate config accessors (e.g., settings.CPU_NO, etc.) while keeping the same fallback and clamping logic.

cpu_no = 8
threads = 4
cores = "0,1,2,3"
Comment on lines +73 to +75

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Hardcoding CPU-related values like cpu_no, threads, and cores makes the application less portable and might not be optimal for all environments. The previous implementation using os.cpu_count() was more dynamic. Consider making these values configurable through environment variables or reverting to dynamic detection to ensure better performance and compatibility across different systems.

Suggested change
cpu_no = 8
threads = 4
cores = "0,1,2,3"
cpu_no = os.cpu_count()
threads = cpu_no // 2 if cpu_no else 2
cores = ",".join(str(i) for i in range(threads))


DOWNLOAD_DIR = "/usr/src/app/downloads/"
DOWNLOAD_DIR = "/app/downloads/"
intervals = {
"status": {},
"qb": "",
Expand All @@ -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 = []
Expand Down
2 changes: 1 addition & 1 deletion bot/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand Down
3 changes: 2 additions & 1 deletion bot/core/config_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 = ""
Expand All @@ -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
Expand Down
2 changes: 1 addition & 1 deletion bot/core/handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -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():
Expand Down
2 changes: 1 addition & 1 deletion bot/core/jdownloader_booter.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
Expand Down
25 changes: 20 additions & 5 deletions bot/core/startup.py
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -14,6 +14,7 @@
drives_ids,
drives_names,
excluded_extensions,
included_extensions,
index_urls,
nzb_options,
qbit_options,
Expand All @@ -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)
Expand All @@ -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)
Expand All @@ -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():
Expand Down Expand Up @@ -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)
Expand All @@ -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])

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

Removing .strip("/") makes the URL construction fragile. If a user provides an INDEX_URL without a trailing slash, the generated links will be broken (e.g., http://example.comfindpath...). To make this more robust, you should normalize the URL here. A good approach is to ensure the URL always has a single trailing slash.

Suggested change
index_urls.append(temp[2])
index_urls.append(temp[2].rstrip('/') + '/')

else:
index_urls.append("")

Expand Down
11 changes: 10 additions & 1 deletion bot/core/aeon_client.py → bot/core/telegram_manager.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from asyncio import Lock

from pyrogram import Client, enums
from pyrogram.types import LinkPreviewOptions

from bot import LOGGER

Expand All @@ -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
Expand All @@ -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
Expand Down
2 changes: 1 addition & 1 deletion bot/helper/aeon_utils/access_check.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading