From e2611b2c5a8d8daa08ffe9dcabfcb18464c9456d Mon Sep 17 00:00:00 2001 From: sTiKyt <35602029+sTiKyt@users.noreply.github.com> Date: Fri, 29 Nov 2024 02:57:08 +0200 Subject: [PATCH 01/13] Base of the cross-distro installer, some fixes (#102) * Ensure root execution Added a check to ensure the script runs with root privileges, and prompt for the root password if necessary. Package manager detection Automatic package manager detection and installation commands. This change simplifies the installation process by automating the detection of the package manager and installing necessary packages accordingly. Added support for multiple package managers such as apt, apk, yum, and pacman. Add repository cloning and environment setup in install.sh Refactored install.sh to improve virtual environment setup, forbid it from executing apt commands without verifying apt presence, added loops for database and installation options. Add repository cloning and environment setup in install.sh Refactored install.sh to improve virtual environment setup, forbid it from executing apt commands without verifying apt presence, added loops for database and installation options. * Update README format and streamline installation instructions Reformatted sections for better readability, removed unnecessary
, replaced weird symbols with spaces * spacing * enhnace PM_PERMIT comment * enhance git install instrunction * Enhance repo existence check in installation script Updated the condition to verify both the presence of the directory and essential files (.env.dist, main.py, modules) before proceeding in the existing repository path. This change ensures the script runs only if all required files are available, preventing errors during installation. * Add user prompt for virtual environment creation Introduce a prompt to let the user decide whether to create a virtual environment, providing guidance and the option to skip if needed. * Fixed a typo in options for db_type * Reorder script execution for better flow Moved the execution of `install.py` to ensure configuration prompts occur before running the script. * Update README.md --------- Co-authored-by: Abhi <85984486+AbhiTheModder@users.noreply.github.com> --- README.md | 50 ++++---- install.sh | 331 ++++++++++++++++++++++++++++++++++------------------- 2 files changed, 238 insertions(+), 143 deletions(-) mode change 100644 => 100755 install.sh diff --git a/README.md b/README.md index 2acd35a7..af84f038 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ [](https://github.com/The-MoonTg-project/Moon-Userbot/blob/main/LICENSE) [](https://makeapullrequest.com) - + ***A Simple, Fast, Customizable, Ai powered Userbot for Telegram made after Dragon-Userbot abandoned*** @@ -129,22 +129,10 @@ If you're using Docker Compose version 2.x, use the following commands to start > Make Sure you add appropriate env vars ## 🖥️ Local Host -## Linux, Windows [only wsl] - -### Update the packages - -```shell -sudo apt update && sudo apt upgrade -y -``` +## 🐧 Linux (WSL compatible) ### Install Git - -> [!TIP] -> Ignore if already installed - -```shell -sudo apt install git -``` +There are instructions for installing on several different Unix distributions on the Git website, at https://git-scm.com/download/linux ### Clone the repo @@ -152,15 +140,25 @@ sudo apt install git git clone https://github.com/The-MoonTg-project/Moon-Userbot.git ``` -### Setup +### Installation ```shell -cd Moon-Userbot/ && sudo bash install.sh +cd Moon-Userbot +chmod +x install.sh +./install.sh ``` +**Installer tested on:** +- Arch +- Debian +- Ubuntu +- WSL (APT based distros) + +Feel free to test on other distros and let us know! + #### 📱 Termux > [!TIP] -> use [GitHub](https://github.com/termux/termux-app/releases) version +> Use [GitHub](https://github.com/termux/termux-app/releases) version ------------------------------------------------------------------------------- > **Full Installation instruction [Given here](https://telegra.ph/Moon-Userbot-Installation---Termux-02-09)** @@ -198,15 +196,15 @@ Contributions of any type are welcome like `custom_modules` etc. Feel free to do ## Licence ```plaintext - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 - Copyright (C) 2007 Free Software Foundation, Inc." + formatted_content + "
" - - data = {"title": title, "content": formatted_content, "author_name": user_name} - - response = requests.post( - url=f"{url}/telegraph/text", headers=headers, json=data, timeout=5 - ) - - result = response.json() - - return result["url"] - - -async def voice_characters(): - response = requests.get(url=f"{url}/speech/characters", headers=headers, timeout=5) - - result = response.json() - - return ", ".join(result["characters"]) - - -async def make_rayso(code: str, title: str, theme: str): - data = { - "code": code, - "title": title, - "theme": theme, - "padding": 64, - "language": "auto", - "darkMode": False, - } - response = requests.post(f"{url}/rayso", data=data, headers=headers) - if response.status_code != 200: - return None - result = response.json() - try: - if result["error"] is not None: - return None - except KeyError: - pass - image_data = result["image"] - file_name = "rayso.png" - with open(file_name, "wb") as f: - f.write(base64.b64decode(image_data)) - return file_name - - -@Client.on_message(filters.command("asq", prefix) & filters.me) -async def asq(_, message: Message): - if len(message.command) > 1: - query = message.text.split(maxsplit=1)[1] - else: - await message.edit_text("Query not provided!") - return - await message.edit_text("Processing...") - response = requests.get(url=f"{url}/asq?query={query}", headers=headers, timeout=5) - if response.status_code != 200: - await message.edit_text("Something went wrong!") - return - - result = response.json() - - ans = result["answer"] - await message.edit_text( - f"Q. {query}\n A. {ans}", parse_mode=enums.ParseMode.MARKDOWN - ) - - -@Client.on_message(filters.command("sgemini", prefix) & filters.me) -async def sgemini(_, message: Message): - if len(message.command) > 1: - prompt = message.text.split(maxsplit=1)[1] - else: - await message.edit_text("prompt not provided!") - return - await message.edit_text("Processing...") - response = requests.get(url=f"{url}/bard?query={prompt}", headers=headers) - if response.status_code != 200: - await message.edit_text("Something went wrong!") - return - - result = response.json() - - ans = result["message"] - await message.edit_text( - f"Prompt: {prompt}\n Ans: {ans}", parse_mode=enums.ParseMode.MARKDOWN - ) - - -@Client.on_message(filters.command("app", prefix) & filters.me) -async def app(client: Client, message: Message): - try: - chat_id = message.chat.id - await message.edit_text("Processing...") - if len(message.command) > 1: - query = message.text.split(maxsplit=1)[1] - else: - message.edit_text( - "What should i search? You didn't provided me with any value to search" - ) - - response = requests.get( - url=f"{url}/apps?query={query}&limit=1", headers=headers, timeout=5 - ) - if response.status_code != 200: - await message.edit_text("Something went wrong") - return - - result = response.json() - - try: - coverImage_url = result["results"][0]["icon"] - coverImage = requests.get(url=coverImage_url).content - async with aiofiles.open("coverImage.jpg", mode="wb") as f: - await f.write(coverImage) - - except Exception: - coverImage = None - - description = result["results"][0]["description"] - developer = result["results"][0]["developer"] - IsFree = result["results"][0]["free"] - genre = result["results"][0]["genre"] - package_name = result["results"][0]["id"] - title = result["results"][0]["title"] - price = result["results"][0]["price"] - link = result["results"][0]["link"] - rating = result["results"][0]["rating"] - - await message.delete() - await client.send_media_group( - chat_id, - [ - InputMediaPhoto( - "coverImage.jpg", - caption=f"Title:{title}\nRating: {rating}\nIsFree: {IsFree}\nPrice: {price}\nPackage Name: {package_name}\nGenres: {genre}\nDeveloper: {developer}\nDescription: {description}\nLink: {link}",
- )
- ],
- )
-
- except MediaCaptionTooLong:
- description = description[:850]
- await message.delete()
- await client.send_media_group(
- chat_id,
- [
- InputMediaPhoto(
- "coverImage.jpg",
- caption=f"Title: {title}\nRating: {rating}\nIsFree: {IsFree}\nPrice: {price}\nPackage Name: {package_name}\nGenres: {genre}\nDeveloper: {developer}\nDescription: {description}\nLink: {link}",
- )
- ],
- )
- except Exception as e:
- await message.edit_text(format_exc(e))
- finally:
- if os.path.exists("coverImage.jpg"):
- os.remove("coverImage.jpg")
-
-
-@Client.on_message(filters.command("tsearch", prefix) & filters.me)
-async def tsearch(client: Client, message: Message):
- try:
- chat_id = message.chat.id
- limit = 10
- await message.edit_text("Processing...")
- if len(message.command) > 1:
- query = message.text.split(maxsplit=1)[1]
- else:
- message.edit_text(
- "What should i search? You didn't provided me with any value to search"
- )
-
- response = requests.get(
- url=f"{url}/torrent?query={query}&limit={limit}", headers=headers
- )
- if response.status_code != 200:
- await message.edit_text("Something went wrong")
- return
-
- result = response.json()
-
- coverImage_url = result["results"][0]["thumbnail"]
- description = result["results"][0]["description"]
- genre = result["results"][0]["genre"]
- category = result["results"][0]["category"]
- title = result["results"][0]["name"]
- link = result["results"][0]["magnetLink"]
- link_result = await telegraph(
- title=title, user_name=message.from_user.first_name, content=link
- )
- language = result["results"][0]["language"]
- size = result["results"][0]["size"]
-
- results = []
-
- for i in range(min(limit, len(result["results"]))):
- descriptions = result["results"][i]["description"]
- genres = result["results"][i]["genre"]
- categorys = result["results"][i]["category"]
- titles = result["results"][i]["name"]
- links = result["results"][i]["magnetLink"]
- languages = result["results"][i]["language"]
- sizes = result["results"][i]["size"]
-
- r = f"Title: {titles}\nCategory: {categorys}\nLanguage: {languages}\nSize: {sizes}\nGenres: {genres}\nDescription: {descriptions}\nMagnet Link: {links}
"
- results.append(r)
-
- all_results_content = "
".join(results)
-
- link_results = await telegraph(
- title="Search Results",
- user_name=message.from_user.first_name,
- content=all_results_content,
- )
-
- if coverImage_url is not None:
- coverImage = requests.get(url=coverImage_url).content
- async with aiofiles.open("coverImage.jpg", mode="wb") as f:
- await f.write(coverImage)
-
- await message.delete()
- await client.send_media_group(
- chat_id,
- [
- InputMediaPhoto(
- "coverImage.jpg",
- caption=f"Title: {title}\nCategory: {category}\nLanguage: {language}\nSize: {size}\nGenres: {genre}\nDescription: {description}\nMagnet Link: Click Here\nMore Results: Click Here",
- )
- ],
- )
- else:
- await message.edit_text(
- f"Title: {title}\nCategory: {category}\nLanguage: {language}\nSize: {size}\nGenres: {genre}\nDescription: {description}\nMagnet Link: Click Here\nMore Results: Click Here",
- disable_web_page_preview=True,
- )
-
- except MediaCaptionTooLong:
- description = description[:850]
- await message.delete()
- await client.send_media_group(
- chat_id,
- [
- InputMediaPhoto(
- "coverImage.jpg",
- caption=f"Title: {title}\nCategory: {category}\nLanguage: {language}\nSize: {size}\nGenres: {genre}\nDescription: {description}\nMagnet Link: Click Here",
- )
- ],
- )
-
- except MessageTooLong:
- description = description[:150]
- await message.edit_text(
- f"Title: {title}\nCategory: {category}\nLanguage: {language}\nSize: {size}\nGenres: {genre}\nDescription: {description}\nMagnet Link: Click Here",
- disable_web_page_preview=True,
- )
-
- except Exception as e:
- await message.edit_text(format_exc(e))
- finally:
- if os.path.exists("coverImage.jpg"):
- os.remove("coverImage.jpg")
-
-
-@Client.on_message(filters.command("tts", prefix) & filters.me)
-async def tts(client: Client, message: Message):
- characters = await voice_characters()
- await message.edit_text("Please Wait...")
- try:
- if len(message.command) > 2:
- character, prompt = message.text.split(maxsplit=2)[1:]
- if character not in characters:
- await message.edit_text(
- f"Usage: {prefix}tts [character]* [text/reply to text]*\n Available Characters: {characters}
"
- )
- return
-
- elif message.reply_to_message and len(message.command) > 1:
- character = message.text.split(maxsplit=1)[1]
- if character in characters:
- prompt = message.reply_to_message.text
- else:
- await message.edit_text(
- f"Usage: {prefix}tts [character]* [text/reply to text]*\n Available Characters: {characters}
"
- )
- return
-
- else:
- await message.edit_text(
- f"Usage: {prefix}tts [character]* [text/reply to text]*\n Available Characters: {characters}
"
- )
- return
-
- data = {"text": prompt, "character": character}
- response = requests.post(url=f"{url}/speech", headers=headers, json=data)
- if response.status_code != 200:
- await message.edit_text("Something went wrong")
- return
-
- result = response.json()
- audio_data = result["audio"]
- audio_data = base64.b64decode(audio_data)
- async with aiofiles.open(f"{prompt}.mp3", mode="wb") as f:
- await f.write(audio_data)
-
- await message.delete()
- await client.send_audio(
- chat_id=message.chat.id,
- audio=f"{prompt}.mp3",
- caption=f"Characters: {character}\nPrompt: {prompt}",
- )
- if os.path.exists(f"{prompt}.mp3"):
- os.remove(f"{prompt}.mp3")
-
- except KeyError:
- try:
- error = result["error"]
- await message.edit_text(error)
- except KeyError:
- await message.edit_text(
- f"Usage: {prefix}tts [character]* [text/reply to text]*\n Available Characters: {characters}
"
- )
- except Exception as e:
- await message.edit_text(format_exc(e))
-
-
-@Client.on_message(
- filters.command(["carbonnowsh", "carboon", "carbon", "cboon"], prefix) & filters.me
-)
-async def carbon(client: Client, message: Message):
- if message.reply_to_message:
- text = message.reply_to_message.text
- message_id = message.reply_to_message.id
- elif len(message.command) > 1:
- message_id = None
- text = message.text.split(maxsplit=1)[1]
- else:
- await message.edit_text("Query not provided!")
- return
- await message.edit_text("Processing...")
-
- image_file = await make_carbon(text)
-
- await message.delete()
- try:
- await client.send_photo(
- chat_id=message.chat.id,
- photo=image_file,
- caption=f"Text: {text}",
- reply_to_message_id=message_id,
- )
- except MediaCaptionTooLong:
- cap = text[:850]
- await client.send_photo(
- chat_id=message.chat.id,
- photo=image_file,
- caption=f"Text: {cap}",
- reply_to_message_id=message_id,
- )
- except Exception as e:
- await message.edit_text(format_exc(e))
- if os.path.exists("carbon.png"):
- os.remove("carbon.png")
-
-
-@Client.on_message(filters.command("ccgen", prefix) & filters.me)
-async def ccgen(_, message: Message):
- if len(message.command) > 1:
- bins = message.text.split(maxsplit=1)[1]
- else:
- await message.edit_text("Code not provided!")
- return
- await message.edit_text("Processing...")
- response = requests.get(url=f"{url}/ccgen?bins={bins}", headers=headers)
- if response.status_code != 200:
- await message.edit_text("Something went wrong")
- return
-
- result = response.json()
-
- cards = result["results"][0]["cards"]
- cards_str = "\n".join([f'"{card}"' for card in cards])
- bins = result["results"][0]["bin"]
- await message.edit_text(
- f"Bins: {bins}\nTotal: {len(cards)}\nCards: \n{cards_str}"
- )
-
-
-@Client.on_message(filters.command("rayso", prefix) & filters.me)
-async def rayso(client: Client, message: Message):
- title = "Untitled"
- themes = [
- "vercel",
- "supabase",
- "tailwind",
- "clerk",
- "mintlify",
- "prisma",
- "bitmap",
- "noir",
- "ice",
- "sand",
- "forest",
- "mono",
- "breeze",
- "candy",
- "crimson",
- "falcon",
- "meadow",
- "midnight",
- "raindrop",
- "sunset",
- ]
- if message.reply_to_message:
- text = message.reply_to_message.text
- message_id = message.reply_to_message.id
- if 2 <= len(message.command) <= 3:
- title = message.text.split(maxsplit=2)[1]
- theme = message.text.split(maxsplit=2)[2].lower()
- if theme not in themes:
- theme = "breeze"
- elif len(message.command) > 1:
- message_id = message.id
- title = message.text.split(maxsplit=3)[1]
- theme = message.text.split(maxsplit=3)[2]
- if theme not in themes:
- theme = "breeze"
- text = message.text.split(maxsplit=3)[3]
- else:
- await message.edit_text("Query not provided!")
- return
- await message.edit_text("Processing...")
-
- image_file = await make_rayso(text, title, theme)
-
- if image_file is None:
- await message.edit_text("Something went wrong")
- return
- try:
- await client.send_photo(
- chat_id=message.chat.id,
- photo=image_file,
- caption=f"Text: {text}",
- reply_to_message_id=message_id,
- )
- await message.delete()
- except MediaCaptionTooLong:
- cap = text[:850]
- await client.send_photo(
- chat_id=message.chat.id,
- photo=image_file,
- caption=f"Text: {cap}",
- reply_to_message_id=message_id,
- )
- await message.delete()
- except Exception as e:
- await message.edit_text(format_exc(e))
- if os.path.exists(image_file):
- os.remove(image_file)
-
-
-modules_help["safone"] = {
- "asq [query]*": "Asq",
- "app [query]*": "Search for an app on Play Store",
- "tsearch [query]*": "Search Torrent",
- "tts [character]* [text/reply to text]*": "Convert Text to Speech",
- "sgemini [prompt]*": "Gemini Model through safone api",
- "carbon [code/file/reply]": "Create beautiful image with your code",
- "ccgen [bins]*": "Generate credit cards",
- "rayso [title]* [theme]* [text/reply to text]*": "Create beautiful image with your text",
-}
diff --git a/utils/scripts.py b/utils/scripts.py
index ac45ed88..21f3a0c4 100644
--- a/utils/scripts.py
+++ b/utils/scripts.py
@@ -216,25 +216,6 @@ def text(message: Message) -> str:
return message.text if message.text else message.caption
-async def make_carbon(code):
- url = "https://carbonara.solopov.dev/api/cook"
-
- async with aiohttp.ClientSession() as session:
- async with session.post(url, json={"code": code}) as resp:
- image_data = await resp.read()
-
- carbon_image = Image.open(BytesIO(image_data))
-
- enhancer = ImageEnhance.Brightness(carbon_image)
- bright_image = enhancer.enhance(1.0)
-
- output_image = BytesIO()
- bright_image.save(output_image, format="PNG", quality=95)
- output_image.name = "carbon.png"
-
- return output_image
-
-
def restart() -> None:
music_bot_pid = db.get("custom.musicbot", "music_bot_pid", None)
if music_bot_pid is not None:
From 6289d3aad83c4b5145dc5a3bbde851f56f9cda5e Mon Sep 17 00:00:00 2001
From: Abhi <85984486+AbhiTheModder@users.noreply.github.com>
Date: Fri, 29 Nov 2024 19:19:11 +0530
Subject: [PATCH 04/13] format
---
install.sh | 14 +++++++-------
1 file changed, 7 insertions(+), 7 deletions(-)
diff --git a/install.sh b/install.sh
index 5eaffd8e..867f2196 100755
--- a/install.sh
+++ b/install.sh
@@ -328,18 +328,18 @@ EOL
systemctl enable Moon
printf "${GREEN}============================\\n"
- printf "Great! Moon-Userbot installed successfully and running now!"
- printf "Installation type: Systemd service"
- printf "Start with: \"sudo systemctl start Moon\""
- printf "Stop with: \"sudo systemctl stop Moon\""
+ printf "Great! Moon-Userbot installed successfully and running now!\n"
+ printf "Installation type: Systemd service\n"
+ printf "Start with: \"sudo systemctl start Moon\"\n"
+ printf "Stop with: \"sudo systemctl stop Moon\"\n"
printf "============================${NC}\n"
break
;;
3)
printf "${GREEN}============================\\n"
- printf "Great! Moon-Userbot installed successfully!"
- printf "Installation type: Custom"
- printf "Start with: \"python3 main.py\""
+ printf "Great! Moon-Userbot installed successfully!\n"
+ printf "Installation type: Custom\n"
+ printf "Start with: \"python3 main.py\"\n"
printf "============================${NC}\n"
break
;;
From 6a228170b9d5f55b79790c0e54118ea5f2438022 Mon Sep 17 00:00:00 2001
From: Abhi <85984486+AbhiTheModder@users.noreply.github.com>
Date: Fri, 29 Nov 2024 21:37:26 +0530
Subject: [PATCH 05/13] fix
---
start | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/start b/start
index 6701a2c8..cb333fff 100755
--- a/start
+++ b/start
@@ -1,8 +1,8 @@
#!/usr/bin/env bash
-if [ -d ".venv"]; then
+if [ -d ".venv" ]; then
. .venv/bin/activate
-elif [ -d "venv"]; then
+elif [ -d "venv" ]; then
. venv/bin/activate
fi
From add54827a19f3f10c7018123bd404d494278427a Mon Sep 17 00:00:00 2001
From: Abhi <85984486+AbhiTheModder@users.noreply.github.com>
Date: Fri, 29 Nov 2024 22:25:37 +0530
Subject: [PATCH 06/13] refactor docker
---
.github/workflows/cloud-image.yml | 27 +++++++++++++++++++++++++++
.github/workflows/docker-image.yml | 1 +
Cloudfile | 8 ++++++++
README.md | 8 +++++++-
compose.yml | 4 +++-
docker-compose.yml | 4 +++-
6 files changed, 49 insertions(+), 3 deletions(-)
create mode 100644 .github/workflows/cloud-image.yml
create mode 100644 Cloudfile
diff --git a/.github/workflows/cloud-image.yml b/.github/workflows/cloud-image.yml
new file mode 100644
index 00000000..7b1299ec
--- /dev/null
+++ b/.github/workflows/cloud-image.yml
@@ -0,0 +1,27 @@
+name: Cloud Docker Image CI
+
+on:
+ push:
+ branches:
+ - main
+jobs:
+ push_to_registry:
+ name: Cloud Docker Image CI
+ runs-on: ubuntu-latest
+ steps:
+ - name: Check out the repo
+ uses: actions/checkout@v3
+
+ - name: Login to Docker Hub
+ uses: docker/login-action@v2
+ with:
+ username: ${{ secrets.DOCKERHUB_USERNAME }}
+ password: ${{ secrets.DOCKERHUB_TOKEN }}
+
+ - name: Build and push Docker image
+ uses: docker/build-push-action@v4
+ with:
+ context: ./
+ file: ./Cloudfile
+ push: true
+ tags: qbtaumai/moonubcloud:latest-cloud
diff --git a/.github/workflows/docker-image.yml b/.github/workflows/docker-image.yml
index 7d3c5431..18e096f7 100644
--- a/.github/workflows/docker-image.yml
+++ b/.github/workflows/docker-image.yml
@@ -22,5 +22,6 @@ jobs:
uses: docker/build-push-action@v4
with:
context: ./
+ file: ./Dockerfile
push: true
tags: qbtaumai/moonuserbot:latest
diff --git a/Cloudfile b/Cloudfile
new file mode 100644
index 00000000..f5d8283f
--- /dev/null
+++ b/Cloudfile
@@ -0,0 +1,8 @@
+FROM python:3.11
+WORKDIR /app
+COPY . /app
+RUN apt-get -qq update && apt-get -qq install -y git wget ffmpeg mediainfo \
+ && apt-get clean \
+ && rm -rf /var/lib/apt/lists/*
+RUN pip install --no-cache-dir -r requirements.txt
+CMD ["bash", "cloud.sh"]
\ No newline at end of file
diff --git a/README.md b/README.md
index af84f038..c4ae8563 100644
--- a/README.md
+++ b/README.md
@@ -90,14 +90,20 @@ You can either use `docker run` or `docker compose`.
- Put your environment vars in `.env` file check [.env.dist](/.env.dist) for example format
### 👷♂️`docker run`:
+We also push images to [Docker Hub](https://hub.docker.com/), so you can use the following commands to start and update the service:
- Start:
+ 1. If you want to use normal image:
```shell
docker run --env-file ./.env -d qbtaumai/moonuserbot:latest
```
+ 2. If you want to use image with flask web (only recommended for heroku/koyeb/render etc.):
+ ```shell
+ docker run --env-file ./.env -d qbtaumai/moonubcloud:latest-cloud
+ ```
- Updating:
```shell
- docker stop $(docker ps -q) && docker rm $(docker ps -a -q)
+ docker stop $(docker ps -q)
```
then re-run the start command
diff --git a/compose.yml b/compose.yml
index 86b92cbc..5c01f341 100644
--- a/compose.yml
+++ b/compose.yml
@@ -1,6 +1,8 @@
services:
moonuserbot:
- image: qbtaumai/moonuserbot:latest
+ build:
+ context: .
+ dockerfile: Dockerfile
container_name: moonuserbot
restart: unless-stopped
env_file:
diff --git a/docker-compose.yml b/docker-compose.yml
index cf04c726..604020bc 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -1,7 +1,9 @@
version: "3"
services:
moonuserbot:
- image: qbtaumai/moonuserbot:latest
+ build:
+ context: .
+ dockerfile: Dockerfile
container_name: moonuserbot
restart: unless-stopped
env_file:
From d54d78e677bf67983f46a7ca6f9689f0bea3b5e9 Mon Sep 17 00:00:00 2001
From: Abhi <85984486+AbhiTheModder@users.noreply.github.com>
Date: Sat, 30 Nov 2024 01:21:42 +0530
Subject: [PATCH 07/13] Create DISCLAIMER.md
---
DISCLAIMER.md | 6 ++++++
1 file changed, 6 insertions(+)
create mode 100644 DISCLAIMER.md
diff --git a/DISCLAIMER.md b/DISCLAIMER.md
new file mode 100644
index 00000000..c5bf3976
--- /dev/null
+++ b/DISCLAIMER.md
@@ -0,0 +1,6 @@
+## Disclaimer
+> [!WARNING]
+> The use of this Telegram Userbot is entirely at your own risk. The developer of this Userbot is not responsible for any misuse, damage, or legal consequences that may arise from your use of this software.
+>> It is your responsibility to ensure that you use this Userbot in accordance with all applicable laws and regulations, and that you do not engage in any activities that may cause harm to others or violate their privacy. This includes, but is not limited to, the use of this Userbot to send spam, harass others, or engage in any other form of unlawful or malicious activity.
+>> The developer of this Userbot does not endorse or condone any such activities, and any such use of this software is strictly prohibited. By using this Userbot, you acknowledge that you are solely responsible for your own actions and that the developer of this Userbot shall not be held liable for any damages or consequences that may arise from your use of this software.
+>> It is your responsibility to ensure that you have obtained all necessary permissions and consents before using this Userbot to interact with others, and that you respect their privacy and rights. The developer of this Userbot shall not be held liable for any breach of privacy or rights that may occur as a result of your use of this software.
From 4b4e33686ae9a1e00e23ace8f8f2216561b34fd5 Mon Sep 17 00:00:00 2001
From: Abhi <85984486+AbhiTheModder@users.noreply.github.com>
Date: Sat, 30 Nov 2024 02:03:03 +0530
Subject: [PATCH 08/13] remove unused music handler from install (#104)
* remove unused music handler from install
---
.env.dist | 3 ---
install.sh | 54 +++++++++++++++++++++++-------------------------------
2 files changed, 23 insertions(+), 34 deletions(-)
diff --git a/.env.dist b/.env.dist
index 7722fb75..c8e60b89 100644
--- a/.env.dist
+++ b/.env.dist
@@ -16,9 +16,6 @@ STRINGSESSION={@string_session}
# Set if you want to use music bot
SECOND_SESSION={@second_session}
-# Music handler for music bot
-MUSIC_HANDLER={@music_handler}
-
# PM LIMIT for AntiPM plugin
PM_LIMIT={@pm_limit}
diff --git a/install.sh b/install.sh
index 867f2196..fcc74427 100755
--- a/install.sh
+++ b/install.sh
@@ -12,11 +12,11 @@ PACKAGE_MANAGER=""
# Ensure the script is run with root privileges
if [[ $UID != 0 ]]; then
- printf "${YELLOW}This script requires root privileges.${NC}\n"
+ printf "${YELLOW}This script requires root privileges.${NC}\n" # skipcq
printf "Please enter the root password to continue.\n"
exec sudo "$0" "$@"
else
- printf "${YELLOW}Running with root privileges${NC}\n"
+ printf "${YELLOW}Running with root privileges${NC}\n" # skipcq
fi
# Detect available package manager
@@ -29,12 +29,12 @@ elif command -v yum &>/dev/null; then
elif command -v pacman &>/dev/null; then
PACKAGE_MANAGER="pacman"
else
- printf "${RED}Unsupported package manager. Please use a compatible distribution or update the installer script.${NC}\n"
+ printf "${RED}Unsupported package manager. Please use a compatible distribution or update the installer script.${NC}\n" # skipcq
exit 1
fi
if command -v termux-setup-storage; then
- printf "${RED}For termux, please use https://raw.githubusercontent.com/The-MoonTg-project/Moon-Userbot/main/termux-install.sh${NC}\n"
+ printf "${RED}For termux, please use https://raw.githubusercontent.com/The-MoonTg-project/Moon-Userbot/main/termux-install.sh${NC}\n" # skipcq
exit 1
fi
@@ -61,22 +61,22 @@ esac
if [[ -d "Moon-Userbot" && "$(basename "$PWD")" != "Moon-Userbot" ]]; then
cd Moon-Userbot || exit 2
elif [[ "$(basename "$PWD")" == "Moon-Userbot" && -f ".env.dist" && -f "main.py" && -d "modules" ]]; then
- printf "${BLUE}Already inside the Moon-Userbot repo, proceeding...${NC}\n"
+ printf "${BLUE}Already inside the Moon-Userbot repo, proceeding...${NC}\n" # skipcq
else
git clone https://github.com/The-MoonTg-project/Moon-Userbot || exit 2
cd Moon-Userbot || exit 2
fi
if [[ -f ".env" ]] && [[ -f "my_account.session" ]]; then
- printf "${GREEN}It seems that Moon-Userbot is already installed. Exiting...${NC}\n"
+ printf "${GREEN}It seems that Moon-Userbot is already installed. Exiting...${NC}\n" # skipcq
exit
fi
# Prompt user if they want to proceed with creating a virtual environment
-printf "${YELLOW}It's recommended to use a virtual environment for Python projects.${NC}\n"
+printf "${YELLOW}It's recommended to use a virtual environment for Python projects.${NC}\n" # skipcq
printf "Note: If your drive resources are very limited, you might consider not creating a virtual environment, but it shouldn't be rejected otherwise unless you know what you're doing.\n"
printf "If you're unsure, it's better to create a virtual environment.\n"
-printf "${INPUT}Would you like to create a virtual environment? (Y/n)${NC} > "
+printf "${INPUT}Would you like to create a virtual environment? (Y/n)${NC} > " # skipcq
read -r create_venv
if [[ "$create_venv" != "n" ]] && [[ "$create_venv" != "N" ]]; then
@@ -99,19 +99,19 @@ pip install -U -r requirements.txt || exit 2
# Prompt for API_ID and API_HASH
printf "Enter API_ID and API_HASH\n"
printf "You can get it here -> https://my.telegram.org/\n"
-printf "Leave empty to use defaults (please note that using default keys is a ${RED}very bad idea${NC} and significantly increases your ban chances)\n"
+printf "Leave empty to use defaults (please note that using default keys is a ${RED}very bad idea${NC} and significantly increases your ban chances)\n" # skipcq
read -r -p "API_ID > " api_id
# Default API_ID and API_HASH
if [[ $api_id = "" ]]; then
- printf "${RED}You have chosen to use the default API_ID and API_HASH, which is strongly discouraged.${NC}\n"
- printf "${YELLOW}Please type${NC} '${BLUE}I agree${NC}'${YELLOW} to confirm that you understand the risks and still wish to proceed.${NC}\n"
+ printf "${RED}You have chosen to use the default API_ID and API_HASH, which is strongly discouraged.${NC}\n" # skipcq
+ printf "${YELLOW}Please type${NC} '${BLUE}I agree${NC}'${YELLOW} to confirm that you understand the risks and still wish to proceed.${NC}\n" # skipcq
read -r -p "Confirmation > " confirmation
if [[ $confirmation = "I agree" ]]; then
api_id="2040"
api_hash="b18441a1ff607e10a989891a5462e627"
else
- printf "${RED}Confirmation not provided. Exiting...${NC}\n"
+ printf "${RED}Confirmation not provided. Exiting...${NC}\n" # skipcq
exit 1
fi
else
@@ -121,7 +121,7 @@ fi
# PM PERMIT warn limit is the number of messages a user can receive from others before giving them a warning, requires `antipm` plugin to be enabled
printf "SET PM PERMIT warn limit\n"
# Now below is more clear version:
-printf "The number of messages others can send you before receiving a warning, and eventually a ban or leave empty for default (3), requires $(antipm) plugin to be enabled\n"
+printf "The number of messages others can send you before receiving a warning, and eventually a ban or leave empty for default (3), requires antipm plugin to be enabled\n"
read -r -p "PM_LIMIT warn limit > " pm_limit
if [[ $pm_limit = "" ]]; then
@@ -138,13 +138,6 @@ if [[ $musicbot = "y" ]]; then
if [[ $second_session = "" ]]; then
printf "SECOND_SESSION not provided by user\n"
second_session=""
- else
- printf "Please provide handler to be used by musicbotn\n"
- read -r -p "MUSIC_HANDLER > " music_handler
- if [[ $music_handler = "" ]]; then
- printf "MUSIC_HANDLER not provided by user\n"
- music_handler=""
- fi
fi
fi
@@ -199,7 +192,7 @@ fi
while true; do
# Prompt for database type and database URL if MongoDB is selected
- printf "${YELLOW}Choose database type:${NC}\n"
+ printf "${YELLOW}Choose database type:${NC}\n" # skipcq
printf "[1] MongoDB db_url\n"
printf "[2] MongoDB localhost\n"
printf "[3] Sqlite (default)\n"
@@ -224,7 +217,7 @@ while true; do
if systemctl status mongodb; then
wget -qO - https://www.mongodb.org/static/pgp/server-5.0.asc | apt-key add -
source /etc/os-release
- printf "deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu ${UBUNTU_CODENAME}/mongodb-org/5.0 multiverse\n" | tee /etc/apt/sources.list.d/mongodb-org-5.0.list
+ printf "deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu %s/mongodb-org/5.0 multiverse\n" "${UBUNTU_CODENAME}" | tee /etc/apt/sources.list.d/mongodb-org-5.0.list
apt update
apt install mongodb -y
systemctl daemon-reload
@@ -243,7 +236,7 @@ while true; do
break
;;
*)
- printf "${RED}Invalid choice!${NC}\n"
+ printf "${RED}Invalid choice!${NC}\n" # skipcq
;;
esac
done
@@ -267,7 +260,6 @@ VCA_API_KEY=${vca_api_key}
COHERE_KEY=${cohere_key}
PM_LIMIT=${pm_limit}
SECOND_SESSION=${second_session}
-MUSIC_HANDLER=${music_handler}
EOL
# Adjust the ownership of the Moon-Userbot directory
@@ -276,7 +268,7 @@ chown -R $SUDO_USER:$SUDO_USER .
# Configure the bot based on selected installation type
while true; do
# Prompt for installation type and execute accordingly
- printf "${YELLOW}Choose installation type:${NC}\n"
+ printf "${YELLOW}Choose installation type:${NC}\n" # skipcq
printf "[1] PM2\n"
printf "[2] Systemd service\n"
printf "[3] Custom (default)\n"
@@ -300,13 +292,13 @@ while true; do
su -c "pm2 start main.py --name Moon --interpreter python3" $SUDO_USER
su -c "pm2 save" $SUDO_USER
- printf "${GREEN}============================\\n"
+ printf "${GREEN}============================\\n" # skipcq
printf "Great! Moon-Userbot installed successfully and running now!\n"
printf "Installation type: PM2\n"
printf "Start with: \"pm2 start Moon\"\n"
printf "Stop with: \"pm2 stop Moon\"\n"
printf "Process name: Moon\n"
- printf "============================${NC}\n"
+ printf "============================${NC}\n" # skipcq
break
;;
2)
@@ -327,20 +319,20 @@ EOL
systemctl start Moon
systemctl enable Moon
- printf "${GREEN}============================\\n"
+ printf "${GREEN}============================\\n" # skipcq
printf "Great! Moon-Userbot installed successfully and running now!\n"
printf "Installation type: Systemd service\n"
printf "Start with: \"sudo systemctl start Moon\"\n"
printf "Stop with: \"sudo systemctl stop Moon\"\n"
- printf "============================${NC}\n"
+ printf "============================${NC}\n" # skipcq
break
;;
3)
- printf "${GREEN}============================\\n"
+ printf "${GREEN}============================\\n" # skipcq
printf "Great! Moon-Userbot installed successfully!\n"
printf "Installation type: Custom\n"
printf "Start with: \"python3 main.py\"\n"
- printf "============================${NC}\n"
+ printf "============================${NC}\n" # skipcq
break
;;
*)
From 36fd906bb2090c6466dd9be05fc5e650d4d53427 Mon Sep 17 00:00:00 2001
From: Abhi <85984486+AbhiTheModder@users.noreply.github.com>
Date: Sat, 30 Nov 2024 03:30:01 +0530
Subject: [PATCH 09/13] Update README.md
---
README.md | 2 ++
1 file changed, 2 insertions(+)
diff --git a/README.md b/README.md
index c4ae8563..b9a68b6e 100644
--- a/README.md
+++ b/README.md
@@ -79,6 +79,8 @@
- **YT Video [How to deploy on Koyeb]**:
+**For Detailed Guide refer to [wiki](https://github.com/The-MoonTg-project/Moon-Userbot/wiki/Installation#koyeb-free)**
+
## 🐳 Docker
You can either use `docker run` or `docker compose`.
From 5fdbe84aed06ccced60bf6bbb8dda6939cb83b49 Mon Sep 17 00:00:00 2001
From: Abhi <85984486+AbhiTheModder@users.noreply.github.com>
Date: Sat, 30 Nov 2024 05:50:16 +0530
Subject: [PATCH 10/13] set custom afk & pm permit (#105)
* set custom afk message
* set custom antipm message
---
modules/afk.py | 54 +++++++++++++++++++++++++++++++++++++++++------
modules/antipm.py | 50 +++++++++++++++++++++++++++++++++++++++++--
2 files changed, 95 insertions(+), 9 deletions(-)
diff --git a/modules/afk.py b/modules/afk.py
index effaf717..ab171199 100644
--- a/modules/afk.py
+++ b/modules/afk.py
@@ -23,6 +23,7 @@
from utils.misc import modules_help, prefix
from utils.scripts import ReplyCheck
+from utils.db import db
# Variables
AFK = False
@@ -59,13 +60,18 @@ async def collect_afk_messages(bot: Client, message: Message):
CHAT_TYPE = GROUPS if is_group else USERS
if GetChatID(message) not in CHAT_TYPE:
- text = (
- f"Beep boop. This is an automated message.\n"
- f"I am not available right now.\n"
- f"Last seen: {last_seen}\n"
- f"Reason: {AFK_REASON.upper()}\n"
- f"See you after I'm done doing whatever I'm doing."
- )
+ text = db.get("core.afk", "afk_msg", None)
+ if text is None:
+ text = (
+ f"Beep boop. This is an automated message.\n"
+ f"I am not available right now.\n"
+ f"Last seen: {last_seen}\n"
+ f"Reason: {AFK_REASON.upper()}\n"
+ f"See you after I'm done doing whatever I'm doing."
+ )
+ else:
+ last_seen = last_seen.replace("ago", "").strip()
+ text = text.format(last_seen=last_seen, reason=AFK_REASON)
await bot.send_message(
chat_id=GetChatID(message),
text=text,
@@ -144,6 +150,39 @@ async def afk_unset(_, message: Message):
await message.delete()
+@Client.on_message(filters.command("setafkmsg", prefix) & filters.me, group=3)
+async def set_afk_msg(_, message: Message):
+ if not message.reply_to_message:
+ return await message.edit("Reply to a message to set it as your AFK message.")
+
+ msg = message.reply_to_message
+ afk_msg = msg.text or msg.caption
+
+ if not afk_msg:
+ return await message.edit(
+ "Reply to a text or caption message to set it as your AFK message."
+ )
+
+ if len(afk_msg) > 200:
+ return await message.edit(
+ "AFK message is too long. It should be less than 200 characters."
+ )
+ if "{reason}" not in afk_msg:
+ return await message.edit(
+ "AFK message should contain {reason} to indicate where the reason will be placed."
+ )
+ if "{last_seen}" not in afk_msg:
+ return await message.edit(
+ "AFK message should contain {last_seen} to indicate where the last seen time will be placed."
+ )
+
+ old_afk_msg = db.get("core.afk", "afk_msg", None)
+ if old_afk_msg:
+ db.remove("core.afk", "afk_msg")
+ db.set("core.afk", "afk_msg", afk_msg)
+ await message.edit(f"AFK message set to:\n\n{afk_msg}")
+
+
@Client.on_message(filters.me, group=3)
async def auto_afk_unset(_, message: Message):
global AFK, AFK_TIME, AFK_REASON, USERS, GROUPS
@@ -166,4 +205,5 @@ async def auto_afk_unset(_, message: Message):
modules_help["afk"] = {
"afk [reason]": "Go to AFK mode with reason as anything after .afk\nUsage: .afk ",
"unafk": "Get out of AFK",
+ "setafkmsg [reply to message]*": "Set your AFK message. Use {reason} and {last_seen} to indicate where the reason and last seen time will be placed.",
}
diff --git a/modules/antipm.py b/modules/antipm.py
index be51996c..6823d869 100644
--- a/modules/antipm.py
+++ b/modules/antipm.py
@@ -52,14 +52,18 @@ async def anti_pm_handler(client: Client, message: Message):
user = await client.get_users(ids)
u_f = user.first_name
user_info = await client.resolve_peer(ids)
- default_text = f"""Hello, {u_f}!
+ default_text = db.get("core.antipm", "antipm_msg", None)
+ if default_text is None:
+ default_text = f"""Hello, {u_f}!
This is the Assistant Of {u_n}.
My Boss is away or busy as of now, You can wait for him to respond.
Do not spam further messages else I may have to block you!
This is an automated message by the assistant.
Currently You Have {warns} Warnings.
-"""
+ """
+ else:
+ default_text = default_text.format(user=u_f, my_name=u_n, warns=warns)
if db.get("core.antipm", "spamrep", False):
await client.invoke(functions.messages.ReportSpam(peer=user_info))
if db.get("core.antipm", "block", False):
@@ -179,10 +183,52 @@ async def del_contact(_, message: Message):
await message.edit("User DisApproved!")
+@Client.on_message(filters.command(["setantipmmsg", "sam"], prefix) & filters.me)
+async def set_antipm_msg(_, message: Message):
+ if not message.reply_to_message:
+ return await message.edit(
+ "Reply to a message to set it as your antipm message."
+ )
+
+ msg = message.reply_to_message
+ afk_msg = msg.text or msg.caption
+
+ if not afk_msg:
+ return await message.edit(
+ "Reply to a text or caption message to set it as your antipm message."
+ )
+
+ if len(afk_msg) > 200:
+ return await message.edit(
+ "antipm message is too long. It should be less than 200 characters."
+ )
+
+ if "{user}" not in afk_msg:
+ return await message.edit(
+ "antipm message must contain {user} to mention the user."
+ )
+ if "{my_name}" not in afk_msg:
+ return await message.edit(
+ "antipm message must contain {my_name} to mention your name."
+ )
+ if "{warns}" not in afk_msg:
+ return await message.edit(
+ "antipm message must contain {warns} to mention the warns count."
+ )
+
+ old_afk_msg = db.get("core.antipm", "antipm_msg", None)
+ if old_afk_msg:
+ db.remove("core.antipm", "antipm_msg")
+ db.set("core.antipm", "antipm_msg", afk_msg)
+ await message.edit(f"antipm message set to:\n\n{afk_msg}")
+
+
modules_help["antipm"] = {
"antipm [enable|disable]*": "Enable Pm permit",
"antipm_report [enable|disable]*": "Enable spam reporting",
"antipm_block [enable|disable]*": "Enable user blocking",
+ "setantipmmsg [reply to message]*": "Set antipm message. Use {user} to mention the user and {my_name} to mention your name and {warns} to mention the warns count.",
+ "sam [reply to message]*": "Set antipm message. Use {user} to mention the user and {my_name} to mention your name and {warns} to mention the warns count.",
"a": "Approve User",
"d": "DisApprove User",
}
From fdd3546e9f534dad136e251f852b8be31b0e1a90 Mon Sep 17 00:00:00 2001
From: Abhi <85984486+AbhiTheModder@users.noreply.github.com>
Date: Wed, 4 Dec 2024 22:04:29 +0530
Subject: [PATCH 11/13] implement plugins load with category
---
modules/loader.py | 60 ++++++++++++++++++++++++++++++++---------------
1 file changed, 41 insertions(+), 19 deletions(-)
diff --git a/modules/loader.py b/modules/loader.py
index 7c5ad3b6..56ba1e0d 100644
--- a/modules/loader.py
+++ b/modules/loader.py
@@ -29,6 +29,22 @@
BASE_PATH = os.path.abspath(os.getcwd())
+CATEGORIES = [
+ "ai",
+ "dl",
+ "admin",
+ "anime",
+ "fun",
+ "images",
+ "info",
+ "misc",
+ "music",
+ "news",
+ "paste",
+ "rev",
+ "tts",
+ "utils",
+]
@Client.on_message(filters.command(["modhash", "mh"], prefix) & filters.me)
@@ -73,25 +89,31 @@ async def loadmod(_, message: Message):
module_name = url.lower()
url = f"https://raw.githubusercontent.com/The-MoonTg-project/custom_modules/main/{module_name}.py"
else:
- modules_hashes = requests.get(
- "https://raw.githubusercontent.com/The-MoonTg-project/custom_modules/main/modules_hashes.txt"
- ).text
- resp = requests.get(url)
-
- if not resp.ok:
- await message.edit(
- f"Troubleshooting with downloading module {url}",
- )
- return
-
- if hashlib.sha256(resp.content).hexdigest() not in modules_hashes:
- return await message.edit(
- "Only "
- "verified modules or from the official "
- ""
- "custom_modules repository are supported!",
- disable_web_page_preview=True,
- )
+ if "/" in url:
+ for category in CATEGORIES:
+ if url.startswith(f"{category}/"):
+ url = f"https://raw.githubusercontent.com/The-MoonTg-project/custom_modules/main/{url}.py"
+ break
+ else:
+ modules_hashes = requests.get(
+ "https://raw.githubusercontent.com/The-MoonTg-project/custom_modules/main/modules_hashes.txt"
+ ).text
+ resp = requests.get(url)
+
+ if not resp.ok:
+ await message.edit(
+ f"Troubleshooting with downloading module {url}",
+ )
+ return
+
+ if hashlib.sha256(resp.content).hexdigest() not in modules_hashes:
+ return await message.edit(
+ "Only "
+ "verified modules or from the official "
+ ""
+ "custom_modules repository are supported!",
+ disable_web_page_preview=True,
+ )
module_name = url.split("/")[-1].split(".")[0]
From 1394aec513ecf6c2481ac6b7b2e746b0d2bad187 Mon Sep 17 00:00:00 2001
From: Abhi <85984486+AbhiTheModder@users.noreply.github.com>
Date: Wed, 4 Dec 2024 22:46:57 +0530
Subject: [PATCH 12/13] resolve dependabot issues (#106)
---
modules/help.py | 12 +++++-------
utils/scripts.py | 4 +---
2 files changed, 6 insertions(+), 10 deletions(-)
diff --git a/modules/help.py b/modules/help.py
index a0edcbb9..d76894e5 100644
--- a/modules/help.py
+++ b/modules/help.py
@@ -21,13 +21,13 @@
total_pages = 0
-async def send_page(message, module_list, page, total_pages):
+async def send_page(message, module_list, page, total_page):
start_index = (page - 1) * 10
end_index = start_index + 10
page_modules = module_list[start_index:end_index]
- text = f"Help for Moon-Userbot\n"
+ text = "Help for Moon-Userbot\n"
text += f"For more help on how to use a command, type {prefix}help [module]\n\n"
- text += f"Page {page}/{total_pages}\n\n"
+ text += f"Page {page}/{total_page}\n\n"
for module_name in page_modules:
commands = modules_help[module_name]
text += f"• {module_name.title()}: {', '.join([f'{prefix + cmd_name.split()[0]}' for cmd_name in commands.keys()])}\n"
@@ -77,8 +77,7 @@ async def handle_navigation(_, message: Message):
message, list(modules_help.keys()), current_page, total_pages
)
return await message.reply_to_message.delete()
- else:
- await message.edit("No more pages available.")
+ await message.edit("No more pages available.")
elif message.command[0].lower() == "pp":
if current_page > 1:
current_page -= 1
@@ -86,8 +85,7 @@ async def handle_navigation(_, message: Message):
message, list(modules_help.keys()), current_page, total_pages
)
return await message.reply_to_message.delete()
- else:
- return await message.edit("This is the first page.")
+ return await message.edit("This is the first page.")
elif message.command[0].lower() == "pq":
await message.reply_to_message.delete()
return await message.edit("Help closed.")
diff --git a/utils/scripts.py b/utils/scripts.py
index 21f3a0c4..89813ba3 100644
--- a/utils/scripts.py
+++ b/utils/scripts.py
@@ -24,13 +24,11 @@
import sys
import time
import traceback
-from PIL import Image, ImageEnhance
+from PIL import Image
from io import BytesIO
-import aiohttp
from types import ModuleType
from typing import Dict, Tuple
-from PIL import Image
import psutil
from pyrogram import Client, errors, enums
from pyrogram.errors import FloodWait, MessageNotModified, UserNotParticipant
From 728d97250dad050ea50c70d135fdb154a269a883 Mon Sep 17 00:00:00 2001
From: Abhi <85984486+AbhiTheModder@users.noreply.github.com>
Date: Wed, 4 Dec 2024 22:54:49 +0530
Subject: [PATCH 13/13] ensure help page change when it's actually help message
---
modules/help.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/modules/help.py b/modules/help.py
index d76894e5..7c0ff3de 100644
--- a/modules/help.py
+++ b/modules/help.py
@@ -27,7 +27,7 @@ async def send_page(message, module_list, page, total_page):
page_modules = module_list[start_index:end_index]
text = "Help for Moon-Userbot\n"
text += f"For more help on how to use a command, type {prefix}help [module]\n\n"
- text += f"Page {page}/{total_page}\n\n"
+ text += f"Help Page No: {page}/{total_page}\n\n"
for module_name in page_modules:
commands = modules_help[module_name]
text += f"• {module_name.title()}: {', '.join([f'{prefix + cmd_name.split()[0]}' for cmd_name in commands.keys()])}\n"
@@ -68,7 +68,7 @@ async def help_cmd(_, message: Message):
@Client.on_message(filters.command(["pn", "pp", "pq"], prefix) & filters.me)
@with_reply
async def handle_navigation(_, message: Message):
- if message.reply_to_message:
+ if message.reply_to_message and "Help Page No:" in message.reply_to_message.text:
global current_page
if message.command[0].lower() == "pn":
if current_page < total_pages: