Revert "refactor: extract userbot to standalone repo, add as git submodule"
This reverts commit 3c383db9a7.
This commit is contained in:
-1
Submodule userbot deleted from 7fb0a0e179
@@ -0,0 +1,10 @@
|
||||
version = 1
|
||||
|
||||
[[analyzers]]
|
||||
name = "shell"
|
||||
|
||||
[[analyzers]]
|
||||
name = "python"
|
||||
|
||||
[analyzers.meta]
|
||||
runtime_version = "3.x.x"
|
||||
@@ -0,0 +1,12 @@
|
||||
.unused
|
||||
Downloads
|
||||
.venv
|
||||
volumes
|
||||
.env
|
||||
.env.*
|
||||
my_account.session
|
||||
.gitignore
|
||||
README.md
|
||||
.git
|
||||
uv.lock
|
||||
.deepsource.toml
|
||||
@@ -0,0 +1,3 @@
|
||||
API_ID=""
|
||||
API_HASH=""
|
||||
STRINGSESSION=""
|
||||
@@ -0,0 +1,14 @@
|
||||
# apiflash api key only for webshot plugin
|
||||
APIFLASH_KEY=""
|
||||
# gemini api key only for gemini plugin
|
||||
GEMINI_KEY=""
|
||||
# VT api key only for VirusTotal plugin
|
||||
VT_KEY=""
|
||||
# rmbg api key only for removebg plugin
|
||||
RMBG_KEY=""
|
||||
# cohere api key only for cohere plugin
|
||||
COHERE_KEY=""
|
||||
# sqlite/sqlite3 or mongo/mongodb
|
||||
DATABASE_TYPE=""
|
||||
# file name for sqlite3, database name for mongodb
|
||||
DATABASE_NAME=""
|
||||
@@ -0,0 +1,19 @@
|
||||
.DS_Store
|
||||
.gitattributes
|
||||
|
||||
.vscode
|
||||
/modules/__pycache__/
|
||||
__pycache__/
|
||||
*.session
|
||||
*.session-old
|
||||
*.db
|
||||
*.sqlite3
|
||||
*-journal
|
||||
/venv/
|
||||
.venv/
|
||||
/downloads/
|
||||
/Downloads/
|
||||
config.ini
|
||||
|
||||
k8s/*/*secret*.yaml
|
||||
!k8s/account-secrets.yaml.example
|
||||
@@ -0,0 +1,5 @@
|
||||
git
|
||||
wget
|
||||
ffmpeg
|
||||
mediainfo
|
||||
yt-dlp
|
||||
@@ -0,0 +1,10 @@
|
||||
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 python -m venv --copies /opt/venv
|
||||
ENV PATH="/opt/venv/bin:$PATH"
|
||||
RUN pip install --no-cache-dir -r requirements.txt
|
||||
CMD ["bash", "cloud.sh"]
|
||||
@@ -0,0 +1 @@
|
||||
web: bash cloud.sh
|
||||
@@ -0,0 +1,82 @@
|
||||
{
|
||||
"name": "Moon-userbot",
|
||||
"description": "A Simple, Fast, Customizable, Ai powered Userbot for Telegram with most easiest installation.",
|
||||
"logo": "https://camo.githubusercontent.com/1efdfa6416b3cd08471d865ca9ebf0fbdd38602ea95425f18a9bec6aeeefe49b/68747470733a2f2f74656c656772612e70682f66696c652f3063333763326662306631393463633163303334342e6a7067",
|
||||
"keywords": ["telegram", "Moon-userbot", "bot", "python", "pyrogram"],
|
||||
"env": {
|
||||
"API_ID": {
|
||||
"description": "Get it from my.telegram.org",
|
||||
"required": true
|
||||
},
|
||||
"API_HASH": {
|
||||
"description": "Get it from my.telegram.org",
|
||||
"required": true
|
||||
},
|
||||
"PM_LIMIT": {
|
||||
"description": "set your pm permit warn limit, default is 4",
|
||||
"value": "4",
|
||||
"required": true
|
||||
},
|
||||
"SECOND_SESSION": {
|
||||
"description": "Pyrorogram v2 session string for music bot, only fill this if you want to use music bot feature",
|
||||
"required": false
|
||||
},
|
||||
"DATABASE_URL": {
|
||||
"description": "ONLY for MongoDB, get it from https://cloud.mongodb.com",
|
||||
"required": false
|
||||
},
|
||||
"DATABASE_NAME": {
|
||||
"description": "set database name, if using sqlite then change it to `db.sqlite3`",
|
||||
"value": "moonub",
|
||||
"required": true
|
||||
},
|
||||
"DATABASE_TYPE": {
|
||||
"description": "set to sqlite3 if want to use sqlite3 db",
|
||||
"value": "mongodb",
|
||||
"required": true
|
||||
},
|
||||
"STRINGSESSION": {
|
||||
"description": "Pyrogram V2 Session String. Don't use bots or else you'll be responsible for your actions. Gen yourself https://github.com/The-MoonTg-project/Moon-Userbot?tab=readme-ov-file#-optional-vars.",
|
||||
"required": true
|
||||
},
|
||||
"APIFLASH_KEY": {
|
||||
"description": "ONLY, If you want to use web screenshot plugin You can get it from https://apiflash.com/dashboard/access_keys",
|
||||
"value": "123456779:ABCDE",
|
||||
"required": true
|
||||
},
|
||||
"RMBG_KEY": {
|
||||
"description": "ONLY, If you want to use removbg plugin You can get it from https://www.remove.bg/dashboard#api-key",
|
||||
"value": "123456779:ABCDE",
|
||||
"required": true
|
||||
},
|
||||
"VT_KEY": {
|
||||
"description": "ONLY, If you want to use VirusTotal plugin You can get it from https://www.virustotal.com/gui/",
|
||||
"value": "123456779:ABCDE",
|
||||
"required": true
|
||||
},
|
||||
"GEMINI_KEY": {
|
||||
"description": "ONLY, If you want to use gemini ai plugin You can get it from https://makersuite.google.com/app/apikey",
|
||||
"value": "123456779:ABCDE",
|
||||
"required": true
|
||||
},
|
||||
"COHERE_KEY": {
|
||||
"description": "ONLY, If you want to use cohere ai plugin You can get it from https://dashboard.cohere.com/api-keys",
|
||||
"value": "123456779:ABCDE",
|
||||
"required": true
|
||||
}
|
||||
},
|
||||
"buildpacks": [
|
||||
{
|
||||
"url": "heroku/python"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/heroku/heroku-buildpack-apt"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/heroku/heroku-buildpack-activestorage-preview"
|
||||
},
|
||||
{
|
||||
"url": "https://github.com/The-MoonTg-project/heroku-buildpack-yt-dlp"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
from flask import Flask
|
||||
|
||||
app = Flask(__name__)
|
||||
|
||||
|
||||
@app.route('/')
|
||||
def hello_world():
|
||||
return 'This is Moon'
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
app.run()
|
||||
@@ -0,0 +1,17 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
cat <<'EOF'
|
||||
_ ____ ____ _
|
||||
/ \__/|/ _ \/ _ \/ \ /|
|
||||
| |\/||| / \|| / \|| |\ ||
|
||||
| | ||| \_/|| \_/|| | \||
|
||||
\_/ \|\____/\____/\_/ \|
|
||||
|
||||
Copyright (C) 2020-2023 by MoonTg-project@Github, < https://github.com/The-MoonTg-project >.
|
||||
This file is part of < https://github.com/The-MoonTg-project/Moon-Userbot > project,
|
||||
and is released under the "GNU v3.0 License Agreement".
|
||||
Please see < https://github.com/The-MoonTg-project/Moon-Userbot/blob/main/LICENSE >
|
||||
All rights reserved.
|
||||
EOF
|
||||
|
||||
gunicorn app:app --daemon && python main.py
|
||||
@@ -0,0 +1,17 @@
|
||||
services:
|
||||
- type: worker
|
||||
name: Moon-Userbot
|
||||
runtime: docker
|
||||
repo: https://github.com/The-MoonTg-project/Moon-Userbot
|
||||
plan: starter
|
||||
envVars:
|
||||
- key: STABILITY_KEY
|
||||
sync: false
|
||||
- key: CLARIFAI_PAT
|
||||
sync: false
|
||||
- key: .env
|
||||
sync: false
|
||||
region: oregon
|
||||
dockerContext: .
|
||||
dockerfilePath: ./Dockerfile
|
||||
version: "1"
|
||||
@@ -0,0 +1 @@
|
||||
gunicorn app:app & python3 main.py
|
||||
@@ -0,0 +1,28 @@
|
||||
FROM python:3.11-slim AS builder
|
||||
|
||||
WORKDIR /src
|
||||
COPY requirements.txt .
|
||||
RUN pip install --no-cache-dir --user -r requirements.txt
|
||||
|
||||
FROM python:3.11-slim
|
||||
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
git \
|
||||
mediainfo \
|
||||
wget \
|
||||
xz-utils \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
RUN wget -qO- https://johnvansickle.com/ffmpeg/releases/ffmpeg-release-amd64-static.tar.xz | \
|
||||
tar xJ && \
|
||||
cp ffmpeg-*-static/ffmpeg /usr/local/bin/ && \
|
||||
cp ffmpeg-*-static/ffprobe /usr/local/bin/ && \
|
||||
rm -rf ffmpeg-*
|
||||
|
||||
COPY --from=builder /root/.local /usr/local
|
||||
COPY . /app
|
||||
WORKDIR /app
|
||||
|
||||
ENV PYTHONUNBUFFERED=1
|
||||
|
||||
CMD ["python", "-u", "main.py"]
|
||||
@@ -0,0 +1,35 @@
|
||||
services:
|
||||
forust:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
image: gcr.forust.xyz/forust/userbot:latest
|
||||
pull_policy: build
|
||||
restart: unless-stopped
|
||||
env_file:
|
||||
- .env
|
||||
- .env.forust
|
||||
volumes:
|
||||
- ./volumes/data_forust:/app/data
|
||||
- ./Downloads:/app/downloads
|
||||
- ./volumes/logs_forust:/app/logs
|
||||
dns:
|
||||
- 8.8.8.8
|
||||
- 1.1.1.1
|
||||
|
||||
anna:
|
||||
image: gcr.forust.xyz/forust/userbot:latest
|
||||
pull_policy: build
|
||||
depends_on:
|
||||
- forust
|
||||
restart: unless-stopped
|
||||
env_file:
|
||||
- .env
|
||||
- .env.anna
|
||||
volumes:
|
||||
- ./volumes/data_anna:/app/data
|
||||
- ./Downloads:/app/downloads
|
||||
- ./volumes/logs_anna:/app/logs
|
||||
dns:
|
||||
- 8.8.8.8
|
||||
- 1.1.1.1
|
||||
@@ -0,0 +1,110 @@
|
||||
import random
|
||||
import re
|
||||
from io import BytesIO
|
||||
|
||||
import requests
|
||||
from bs4 import BeautifulSoup as BS
|
||||
from pyrogram import Client, filters
|
||||
from pyrogram.errors import RPCError
|
||||
from pyrogram.types import InputMediaPhoto, Message
|
||||
from utils.misc import modules_help, prefix
|
||||
|
||||
|
||||
@Client.on_message(filters.command('icon', prefix) & filters.me)
|
||||
async def search_icon(_, message: Message):
|
||||
if len(message.command) != 2:
|
||||
return await message.edit_text('Please provide some text to search icons from Flaticon.com.')
|
||||
query = message.text.split(maxsplit=1)[1]
|
||||
|
||||
await message.edit_text('Searching for icons...')
|
||||
search_query = query.replace(' ', '%20')
|
||||
url = f'https://www.flaticon.com/search?word={search_query}'
|
||||
|
||||
try:
|
||||
html_content = requests.get(url, timeout=10).text
|
||||
soup = BS(html_content, 'html.parser')
|
||||
results = soup.find_all(
|
||||
'img',
|
||||
src=re.compile(r'https://cdn-icons-png.flaticon.com/128/[0-9]+/[0-9]+.png'),
|
||||
)
|
||||
|
||||
if not results:
|
||||
return await message.edit('No results found.')
|
||||
|
||||
random.shuffle(results)
|
||||
icons = []
|
||||
for i in range(5):
|
||||
icons.append(results[i]['src'].replace('128', '512'))
|
||||
|
||||
for icon in icons:
|
||||
await message.reply_document(icon)
|
||||
|
||||
return await message.delete()
|
||||
except Exception as e:
|
||||
await message.edit(f'An error occurred: {e}')
|
||||
print(f'Error: {e}')
|
||||
|
||||
|
||||
@Client.on_message(filters.command('freepik', prefix) & filters.me)
|
||||
async def freepik_search(client: Client, message: Message):
|
||||
parts = message.text.split(' ', 1)
|
||||
if len(parts) < 2:
|
||||
await message.edit_text('Please provide a search query!')
|
||||
return
|
||||
|
||||
query = parts[1]
|
||||
limit = 5
|
||||
if ' ; ' in query:
|
||||
match, limit_str = query.split(' ; ', 1)
|
||||
try:
|
||||
limit = int(limit_str)
|
||||
except ValueError:
|
||||
await message.edit_text('Invalid limit! Using the default value of 5.')
|
||||
else:
|
||||
match = query
|
||||
|
||||
match = match.replace(' ', '%20')
|
||||
await message.edit_text('Searching Freepik...')
|
||||
|
||||
try:
|
||||
url = f'https://www.freepik.com/api/regular/search?locale=en&term={match}'
|
||||
json_content = requests.get(url, timeout=10).json()
|
||||
results = []
|
||||
for i in json_content['items']:
|
||||
results.append(i['preview']['url'])
|
||||
|
||||
if results is None:
|
||||
return await message.edit_text('No results found.')
|
||||
|
||||
random.shuffle(results)
|
||||
img_urls = results[:limit]
|
||||
|
||||
media_group = []
|
||||
for img_url in img_urls:
|
||||
icon = requests.get(img_url, timeout=10)
|
||||
if icon.status_code == 200:
|
||||
media_group.append(InputMediaPhoto(media=BytesIO(icon.content)))
|
||||
|
||||
if not media_group:
|
||||
await message.edit_text('No images could be downloaded.')
|
||||
return
|
||||
|
||||
try:
|
||||
await client.send_media_group(chat_id=message.chat.id, media=media_group)
|
||||
except RPCError:
|
||||
await message.edit_text('Failed to send some images. Retrying individually...')
|
||||
for media in media_group:
|
||||
try:
|
||||
await message.reply_photo(photo=media.media)
|
||||
except Exception as e:
|
||||
await message.edit_text(f'Error sending image: {e}')
|
||||
|
||||
except Exception as e:
|
||||
await message.edit_text(f'Failed to fetch data: {e}')
|
||||
print(f'Error: {e}')
|
||||
|
||||
|
||||
modules_help['icons'] = {
|
||||
'icon [query]': 'Search for icons on Flaticon.',
|
||||
'freepik [query] [limit]': 'Search for images on Freepik. Limit is optional and defaults to 5.',
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
import base64
|
||||
|
||||
import requests
|
||||
from pyrogram import Client, filters
|
||||
from pyrogram.types import Message
|
||||
from utils.misc import modules_help, prefix
|
||||
|
||||
|
||||
@Client.on_message(filters.command(['imgur'], prefix) & filters.me)
|
||||
async def imgur(_, message: Message):
|
||||
# Check if a reply exists
|
||||
msg = await message.edit_text('🎉 Please wait. trying to upload...')
|
||||
if message.reply_to_message and message.reply_to_message.photo:
|
||||
# Download the photo
|
||||
photo_path = await message.reply_to_message.download()
|
||||
# Read the photo file and encode as base64
|
||||
with open(photo_path, 'rb') as file:
|
||||
data = file.read()
|
||||
base64_data = base64.b64encode(data)
|
||||
# Set API endpoint and headers for image upload
|
||||
url = 'https://api.imgur.com/3/image'
|
||||
headers = {'Authorization': 'Client-ID a10ad04550b0648'}
|
||||
# Upload image to Imgur and get URL
|
||||
response = requests.post(url, headers=headers, data={'image': base64_data}, timeout=10)
|
||||
result = response.json()
|
||||
await msg.edit_text(result['data']['link'])
|
||||
elif message.reply_to_message and message.reply_to_message.animation:
|
||||
# Download the animation (GIF)
|
||||
animation_path = await message.reply_to_message.download()
|
||||
# Read the animation file and encode as base64
|
||||
with open(animation_path, 'rb') as file:
|
||||
data = file.read()
|
||||
base64_data = base64.b64encode(data)
|
||||
# Set API endpoint and headers for animation upload
|
||||
url = 'https://api.imgur.com/3/image'
|
||||
headers = {'Authorization': 'Client-ID a10ad04550b0648'}
|
||||
# Upload animation to Imgur and get URL
|
||||
response = requests.post(url, headers=headers, data={'image': base64_data}, timeout=10)
|
||||
result = response.json()
|
||||
await msg.edit_text(result['data']['link'])
|
||||
else:
|
||||
await msg.edit_text('Please reply to a photo or animation (GIF) to upload to Imgur.')
|
||||
|
||||
|
||||
modules_help['imgur'] = {
|
||||
'imgur [img]*': 'upload a photo or animation (GIF) to imgur',
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
import os
|
||||
|
||||
import pygments
|
||||
from pygments.formatters import ImageFormatter
|
||||
from pygments.lexers import Python3Lexer
|
||||
from pyrogram import Client, filters
|
||||
from pyrogram.errors import MessageNotModified
|
||||
from pyrogram.types import Message
|
||||
from utils.misc import modules_help, prefix
|
||||
|
||||
|
||||
@Client.on_message(filters.command('ncode', prefix) & filters.me)
|
||||
async def coder_print(client, message: Message):
|
||||
if message.reply_to_message:
|
||||
reply_message = message.reply_to_message
|
||||
if reply_message.media:
|
||||
download_path = await client.download_media(reply_message)
|
||||
with open(download_path) as file:
|
||||
code = file.read()
|
||||
if os.path.exists(download_path):
|
||||
os.remove(download_path)
|
||||
pygments.highlight(
|
||||
f'{code}',
|
||||
Python3Lexer(),
|
||||
ImageFormatter(font_name='DejaVu Sans Mono', line_numbers=True),
|
||||
'result.png',
|
||||
)
|
||||
try:
|
||||
sent_message = await message.edit_text('Pasting this code on my page...')
|
||||
await client.send_document(
|
||||
chat_id=message.chat.id,
|
||||
document='result.png',
|
||||
caption='Code highlighted by Pygments',
|
||||
reply_to_message_id=message.id,
|
||||
)
|
||||
except MessageNotModified:
|
||||
pass
|
||||
await sent_message.delete()
|
||||
if os.path.exists('result.png'):
|
||||
os.remove('result.png')
|
||||
else:
|
||||
return await message.reply_text('Please reply to a text or a file.')
|
||||
else:
|
||||
return await message.reply_text('Please reply to a text or a file.')
|
||||
|
||||
|
||||
modules_help['ncode'] = {'ncode': 'Highlight the code using Pygments and send it as an image.'}
|
||||
@@ -0,0 +1,91 @@
|
||||
import asyncio
|
||||
from io import BytesIO
|
||||
|
||||
import requests
|
||||
from PIL import Image
|
||||
from pyrogram import Client, enums, filters
|
||||
from pyrogram.types import InputMediaPhoto, Message
|
||||
from utils.misc import modules_help, prefix
|
||||
|
||||
# Pinterest API URL
|
||||
API_URL = 'https://bk9.fun/pinterest/search?q='
|
||||
|
||||
|
||||
def resize_image(image_bytes):
|
||||
try:
|
||||
with Image.open(image_bytes) as img:
|
||||
max_size = (1280, 1280)
|
||||
if img.size > max_size:
|
||||
img.thumbnail(max_size)
|
||||
output = BytesIO()
|
||||
img.save(output, format='JPEG')
|
||||
output.seek(0)
|
||||
return output
|
||||
image_bytes.seek(0) # Reset pointer if not resized
|
||||
return image_bytes
|
||||
except Exception as e:
|
||||
print(f'Error resizing image: {e}')
|
||||
return image_bytes
|
||||
|
||||
|
||||
async def download_image(url):
|
||||
try:
|
||||
response = requests.get(url, timeout=10)
|
||||
if response.status_code == 200:
|
||||
img_bytes = BytesIO(response.content)
|
||||
return resize_image(img_bytes)
|
||||
except Exception as e:
|
||||
print(f'Error downloading image: {e}')
|
||||
return None
|
||||
|
||||
|
||||
@Client.on_message(filters.command('pinterest', prefix) & filters.me)
|
||||
async def pinterest_search(client: Client, message: Message):
|
||||
if len(message.command) < 2:
|
||||
await message.edit('Usage: `pinterest [number] <query>`', parse_mode=enums.ParseMode.MARKDOWN)
|
||||
return
|
||||
|
||||
num_pics = int(message.command[1]) if message.command[1].isdigit() else 10
|
||||
query = ' '.join(message.command[2:])
|
||||
|
||||
# Update status
|
||||
status_message = await message.edit('Searching for images...', parse_mode=enums.ParseMode.MARKDOWN)
|
||||
|
||||
url = f'{API_URL}{query}'
|
||||
response = requests.get(url, timeout=10)
|
||||
|
||||
if response.status_code == 200:
|
||||
data = response.json()
|
||||
if data.get('status'):
|
||||
urls = [item['images_url'] for item in data.get('BK9', [])[:num_pics]]
|
||||
images = [download_image(img_url) for img_url in urls]
|
||||
|
||||
# Download images
|
||||
downloaded_images = await asyncio.gather(*images)
|
||||
|
||||
media = [InputMediaPhoto(media=img_bytes) for img_bytes in downloaded_images if img_bytes]
|
||||
|
||||
if media:
|
||||
await status_message.edit('Uploading pictures...', parse_mode=enums.ParseMode.MARKDOWN)
|
||||
while media:
|
||||
batch = media[:10]
|
||||
media = media[10:]
|
||||
await message.reply_media_group(batch)
|
||||
await status_message.delete() # Delete status message after uploading
|
||||
else:
|
||||
await status_message.edit('No valid images found.', parse_mode=enums.ParseMode.MARKDOWN)
|
||||
else:
|
||||
await status_message.edit(
|
||||
'No images found for the given query.',
|
||||
parse_mode=enums.ParseMode.MARKDOWN,
|
||||
)
|
||||
else:
|
||||
await status_message.edit(
|
||||
'An error occurred, please try again later.',
|
||||
parse_mode=enums.ParseMode.MARKDOWN,
|
||||
)
|
||||
|
||||
|
||||
modules_help['pinterest'] = {
|
||||
'pinterest [number]* [query]': 'Get images from Pinterest. Default number of images is 10',
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
import os
|
||||
|
||||
import requests
|
||||
from modules.url import generate_screenshot
|
||||
from pyrogram import Client, filters
|
||||
from pyrogram.types import Message
|
||||
from utils.misc import modules_help, prefix
|
||||
|
||||
# API endpoints for reverse image search engines
|
||||
SEARCH_ENGINES = {
|
||||
'lens': 'https://lens.google.com/uploadbyurl?url={image}',
|
||||
'reverse': 'https://www.google.com/searchbyimage?sbisrc=4chanx&image_url={image}&safe=off',
|
||||
'tineye': 'https://www.tineye.com/search?url={image}',
|
||||
'bing': 'https://www.bing.com/images/search?view=detailv2&iss=sbi&form=SBIVSP&sbisrc=UrlPaste&q=imgurl:{image}',
|
||||
'yandex': 'https://yandex.com/images/search?source=collections&&url={image}&rpt=imageview',
|
||||
'saucenao': 'https://saucenao.com/search.php?db=999&url={image}',
|
||||
}
|
||||
|
||||
|
||||
@Client.on_message(filters.command('risearch', prefix) & filters.reply)
|
||||
async def reverse_image_search(client: Client, message: Message):
|
||||
if not message.reply_to_message or not message.reply_to_message.photo:
|
||||
await message.reply_text(
|
||||
f'Please reply to an image with <code>{prefix}risearch [engine]</code> or <code>{prefix}risearch</code>.'
|
||||
)
|
||||
return
|
||||
|
||||
command_parts = message.text.split(maxsplit=1)
|
||||
engines_to_use = (
|
||||
[command_parts[1].strip().lower()]
|
||||
if len(command_parts) > 1 and command_parts[1].strip()
|
||||
else list(SEARCH_ENGINES.keys())
|
||||
)
|
||||
|
||||
invalid_engines = [engine for engine in engines_to_use if engine not in SEARCH_ENGINES]
|
||||
if invalid_engines:
|
||||
await message.reply_text(
|
||||
f'Invalid engine(s): {", ".join(invalid_engines)}. Available: {", ".join(SEARCH_ENGINES.keys())}'
|
||||
)
|
||||
return
|
||||
|
||||
processing_message = await message.edit_text('Processing the image...')
|
||||
|
||||
try:
|
||||
# Download and upload the image
|
||||
photo_path = await message.reply_to_message.download()
|
||||
img_url = upload_image(photo_path)
|
||||
print(img_url)
|
||||
if not img_url:
|
||||
await processing_message.edit('Error: Could not upload the image.')
|
||||
return
|
||||
|
||||
# Perform searches for the selected engines
|
||||
for engine in engines_to_use:
|
||||
search_url = SEARCH_ENGINES[engine].format(image=img_url)
|
||||
await send_screenshot(client, message, search_url, engine)
|
||||
except Exception as e:
|
||||
await processing_message.edit(f'An error occurred: {e}')
|
||||
finally:
|
||||
if photo_path and os.path.exists(photo_path):
|
||||
os.remove(photo_path)
|
||||
|
||||
|
||||
def upload_image(photo_path):
|
||||
"""Uploads an image to tmpfiles.org and returns the direct download URL."""
|
||||
try:
|
||||
with open(photo_path, 'rb') as image_file:
|
||||
response = requests.post('https://tmpfiles.org/api/v1/upload', files={'file': image_file}, timeout=10)
|
||||
if response.status_code == 200:
|
||||
data = response.json()
|
||||
url = data['data']['url']
|
||||
pic_url = url.split('/')[-2] + '/' + url.split('/')[-1]
|
||||
direct_download_url = url.replace(f'/{pic_url}', f'/dl/{pic_url}')
|
||||
print(direct_download_url)
|
||||
return direct_download_url
|
||||
else:
|
||||
return None
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
|
||||
async def send_screenshot(client, message, url, engine_name):
|
||||
"""Takes a screenshot of the URL and sends it to the chat."""
|
||||
screenshot_data = generate_screenshot(url)
|
||||
if screenshot_data:
|
||||
await client.send_photo(
|
||||
message.chat.id,
|
||||
screenshot_data,
|
||||
caption=f'<b>{engine_name.capitalize()} Result</b>\nURL: <code>{url}</code>',
|
||||
reply_to_message_id=message.id,
|
||||
)
|
||||
else:
|
||||
await message.reply(f'Failed to take screenshot for {engine_name.capitalize()}.')
|
||||
|
||||
|
||||
# Add module details to help
|
||||
modules_help['risearch'] = {
|
||||
'risearch': f'Reply to a photo with `{prefix}risearch [engine]` (e.g., `{prefix}risearch lens`, `{prefix}risearch bing`) '
|
||||
f'\nor use `{prefix}risearch` to analyze the image with all engines.',
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
import asyncio
|
||||
import os
|
||||
import shutil
|
||||
|
||||
import aiohttp
|
||||
import requests
|
||||
from pyrogram import Client, enums, filters
|
||||
from pyrogram.types import Message
|
||||
from utils.misc import modules_help, prefix
|
||||
|
||||
|
||||
class AioHttp:
|
||||
async def get_json(self, link):
|
||||
headers = {
|
||||
'accept': '*/*',
|
||||
'accept-language': 'en-US',
|
||||
'cache-control': 'no-cache',
|
||||
'client-geo-region': 'global',
|
||||
'dnt': '1',
|
||||
'pragma': 'no-cache',
|
||||
'priority': 'u=1, i',
|
||||
'sec-ch-ua': '"Chromium";v="130", "Microsoft Edge";v="130", "Not?A_Brand";v="99"',
|
||||
'sec-ch-ua-mobile': '?0',
|
||||
'sec-ch-ua-platform': '"Windows"',
|
||||
'sec-fetch-dest': 'empty',
|
||||
'sec-fetch-mode': 'cors',
|
||||
'sec-fetch-site': 'same-origin',
|
||||
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36 Edg/130.0.0.0',
|
||||
}
|
||||
|
||||
async with aiohttp.ClientSession() as session, session.get(link, headers=headers) as resp:
|
||||
return await resp.json()
|
||||
|
||||
|
||||
@Client.on_message(filters.command('unsplash', prefix) & filters.me)
|
||||
async def unsplash(client: Client, message: Message):
|
||||
if len(message.command) > 1 and isinstance(message.command[1], str):
|
||||
keyword = message.command[1]
|
||||
unsplash_dir = 'downloads/unsplash/'
|
||||
if not os.path.exists(unsplash_dir):
|
||||
os.makedirs(unsplash_dir)
|
||||
|
||||
if len(message.command) > 2 and 2 <= int(message.command[2]) <= 10:
|
||||
await message.edit('<b>Getting Pictures</b>', parse_mode=enums.ParseMode.HTML)
|
||||
count = int(message.command[2])
|
||||
images = []
|
||||
data = await AioHttp().get_json(
|
||||
f'https://unsplash.com/napi/search/photos?page=1&per_page={count}&query={keyword}'
|
||||
)
|
||||
while len(images) < count:
|
||||
for ia in range(len(images), count):
|
||||
img = data['results'][ia]['urls']['raw']
|
||||
if img.startswith('https://images.unsplash.com/photo'):
|
||||
image_content = requests.get(img, timeout=10).content
|
||||
with open(f'{unsplash_dir}/unsplash_{ia}.jpg', 'wb') as f:
|
||||
f.write(image_content)
|
||||
imgr = f'{unsplash_dir}/unsplash_{ia}.jpg'
|
||||
images.append(imgr)
|
||||
else:
|
||||
images.append(img)
|
||||
if len(images) == count:
|
||||
break
|
||||
|
||||
for img in images:
|
||||
await client.send_document(message.chat.id, img)
|
||||
|
||||
await message.delete()
|
||||
shutil.rmtree(unsplash_dir)
|
||||
return
|
||||
else:
|
||||
await message.edit('<b>Getting Picture</b>', parse_mode=enums.ParseMode.HTML)
|
||||
data = await AioHttp().get_json(
|
||||
f'https://unsplash.com/napi/search/photos?page=1&per_page=1&query={keyword}'
|
||||
)
|
||||
img = data['results'][0]['urls']['raw']
|
||||
await asyncio.gather(message.delete(), client.send_document(message.chat.id, str(img)))
|
||||
|
||||
|
||||
modules_help['unsplash'] = {
|
||||
'unsplash': '[keyword]* [number of results you want]*\n'
|
||||
'Makes a request to <code>unsplash.com</code> and sends the image with the keyword you provided.\n\n'
|
||||
'<b>Note:</b>\n1. The number of results you can get is limited to 10.\n'
|
||||
'2. Keyword is required and should be of one word only!.\n'
|
||||
'3. Images are sent as document to maintain quality.',
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
import asyncio
|
||||
from io import BytesIO
|
||||
|
||||
import requests
|
||||
from PIL import Image
|
||||
from pyrogram import Client, enums, filters
|
||||
from pyrogram.types import InputMediaPhoto, Message
|
||||
from utils.misc import modules_help, prefix
|
||||
|
||||
API_URL = 'https://bk9.fun/search/unsplash?q='
|
||||
|
||||
|
||||
def resize_image(image_bytes):
|
||||
try:
|
||||
with Image.open(image_bytes) as img:
|
||||
max_size = (1280, 1280)
|
||||
if img.size > max_size:
|
||||
img.thumbnail(max_size)
|
||||
output = BytesIO()
|
||||
img.save(output, format='JPEG')
|
||||
output.seek(0)
|
||||
return output
|
||||
image_bytes.seek(0) # Reset pointer if not resized
|
||||
return image_bytes
|
||||
except Exception as e:
|
||||
print(f'Error resizing image: {e}')
|
||||
return image_bytes
|
||||
|
||||
|
||||
async def download_image(url):
|
||||
try:
|
||||
response = requests.get(url, timeout=10)
|
||||
if response.status_code == 200:
|
||||
img_bytes = BytesIO(response.content)
|
||||
resized_img_bytes = resize_image(img_bytes)
|
||||
return resized_img_bytes
|
||||
except Exception as e:
|
||||
print(f'Error downloading image: {e}')
|
||||
return None
|
||||
|
||||
|
||||
@Client.on_message(filters.command(['unsplash2', 'usp2'], prefix) & filters.me)
|
||||
async def imgsearch(client: Client, message: Message):
|
||||
if len(message.command) < 2:
|
||||
await message.edit('Usage: `img [number] <query>`', parse_mode=enums.ParseMode.MARKDOWN)
|
||||
return
|
||||
|
||||
num_pics = int(message.command[1]) if message.command[1].isdigit() else 10
|
||||
query = ' '.join(message.command[2:])
|
||||
|
||||
# Update status
|
||||
status_message = await message.edit('Searching for images...', parse_mode=enums.ParseMode.MARKDOWN)
|
||||
|
||||
url = f'{API_URL}{query}'
|
||||
response = requests.get(url, timeout=10)
|
||||
|
||||
if response.status_code == 200:
|
||||
data = response.json()
|
||||
if data.get('status'):
|
||||
urls = data.get('BK9', [])[:num_pics]
|
||||
images = [download_image(img_url) for img_url in urls]
|
||||
|
||||
# Download images
|
||||
downloaded_images = await asyncio.gather(*images)
|
||||
|
||||
media = [InputMediaPhoto(media=img_bytes) for img_bytes in downloaded_images if img_bytes]
|
||||
|
||||
if media:
|
||||
await status_message.edit('Uploading pictures...', parse_mode=enums.ParseMode.MARKDOWN)
|
||||
while media:
|
||||
batch = media[:10]
|
||||
media = media[10:]
|
||||
await message.reply_media_group(batch)
|
||||
await status_message.delete() # Delete status message after uploading
|
||||
else:
|
||||
await status_message.edit('No valid images found.', parse_mode=enums.ParseMode.MARKDOWN)
|
||||
else:
|
||||
await status_message.edit(
|
||||
'No images found for the given query.',
|
||||
parse_mode=enums.ParseMode.MARKDOWN,
|
||||
)
|
||||
else:
|
||||
await status_message.edit(
|
||||
'An error occurred, please try again later.',
|
||||
parse_mode=enums.ParseMode.MARKDOWN,
|
||||
)
|
||||
|
||||
|
||||
modules_help['unsplash2'] = {
|
||||
'unsplash2 [number]* [query]': 'Get HD images. Default number of images is 10',
|
||||
'usp2 [number]* [query]': 'Get HD images. Default number of images is 10',
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
import sys
|
||||
from datetime import datetime
|
||||
|
||||
from pyrogram import Client
|
||||
from utils import config
|
||||
|
||||
common_params = {
|
||||
'api_id': config.api_id,
|
||||
'api_hash': config.api_hash,
|
||||
'hide_password': True,
|
||||
'test_mode': config.test_server,
|
||||
}
|
||||
|
||||
if __name__ == '__main__':
|
||||
if config.STRINGSESSION:
|
||||
common_params['session_string'] = config.STRINGSESSION
|
||||
|
||||
app = Client('my_account', **common_params)
|
||||
|
||||
if config.db_type in ['mongo', 'mongodb']:
|
||||
from pymongo import MongoClient, errors
|
||||
|
||||
db = MongoClient(config.db_url)
|
||||
try:
|
||||
db.server_info()
|
||||
except errors.ConnectionFailure as e:
|
||||
raise RuntimeError(
|
||||
"MongoDB server isn't available! "
|
||||
f'Provided url: {config.db_url}. '
|
||||
'Enter valid URL and restart installation'
|
||||
) from e
|
||||
|
||||
install_type = sys.argv[1] if len(sys.argv) > 1 else '3'
|
||||
if install_type == '1':
|
||||
restart = 'pm2 restart Moon'
|
||||
elif install_type == '2':
|
||||
restart = 'sudo systemctl restart Moon'
|
||||
else:
|
||||
restart = 'cd Moon-Userbot/ && python main.py'
|
||||
|
||||
app.start()
|
||||
try:
|
||||
app.send_message(
|
||||
'me',
|
||||
f'<b>[{datetime.now()}] Userbot launched! \n'
|
||||
'Custom modules: @moonub_modules\n'
|
||||
f'For restart, enter:</b>\n'
|
||||
f'<code>{restart}</code>',
|
||||
)
|
||||
except Exception as e:
|
||||
print(f'[ERROR]: Sending Message to me failed! {e}')
|
||||
app.stop()
|
||||
@@ -0,0 +1,7 @@
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: userbot-common-config
|
||||
data:
|
||||
DATABASE_TYPE: ""
|
||||
DATABASE_NAME: ""
|
||||
@@ -0,0 +1,9 @@
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
|
||||
resources:
|
||||
- userbots.yaml
|
||||
- common-secret.yaml
|
||||
- common-config.yaml
|
||||
- forust-secrets.yaml
|
||||
- anna-secrets.yaml
|
||||
@@ -0,0 +1,114 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: forust-userbot-deployment
|
||||
labels:
|
||||
app: forust-userbot
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: forust-userbot
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: forust-userbot
|
||||
spec:
|
||||
containers:
|
||||
- name: forust-userbot
|
||||
image: gcr.forust.xyz/forust/userbot:latest
|
||||
imagePullPolicy: Always
|
||||
resources:
|
||||
limits:
|
||||
memory: "1.5Gi"
|
||||
cpu: "300m"
|
||||
requests:
|
||||
memory: "512Mi"
|
||||
cpu: "80m"
|
||||
envFrom:
|
||||
- secretRef:
|
||||
name: userbot-common-secrets
|
||||
- configMapRef:
|
||||
name: userbot-common-config
|
||||
- secretRef:
|
||||
name: userbot-forust-secrets
|
||||
volumeMounts:
|
||||
- name: forust-storage
|
||||
mountPath: /app/data
|
||||
subPath: data
|
||||
- name: forust-storage
|
||||
mountPath: /app/logs
|
||||
subPath: logs
|
||||
volumes:
|
||||
- name: forust-storage
|
||||
persistentVolumeClaim:
|
||||
claimName: forust-pvc
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: forust-pvc
|
||||
spec:
|
||||
resources:
|
||||
requests:
|
||||
storage: 1Gi
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: anna-userbot-deployment
|
||||
labels:
|
||||
app: anna-userbot
|
||||
spec:
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: anna-userbot
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: anna-userbot
|
||||
spec:
|
||||
containers:
|
||||
- name: anna-userbot
|
||||
image: gcr.forust.xyz/forust/userbot:latest
|
||||
imagePullPolicy: Always
|
||||
resources:
|
||||
limits:
|
||||
memory: "1.5Gi"
|
||||
cpu: "300m"
|
||||
requests:
|
||||
memory: "512Mi"
|
||||
cpu: "80m"
|
||||
envFrom:
|
||||
- secretRef:
|
||||
name: userbot-common-secrets
|
||||
- configMapRef:
|
||||
name: userbot-common-config
|
||||
- secretRef:
|
||||
name: userbot-anna-secrets
|
||||
volumeMounts:
|
||||
- name: anna-storage
|
||||
mountPath: /app/data
|
||||
subPath: data
|
||||
- name: anna-storage
|
||||
mountPath: /app/logs
|
||||
subPath: logs
|
||||
volumes:
|
||||
- name: anna-storage
|
||||
persistentVolumeClaim:
|
||||
claimName: anna-pvc
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: anna-pvc
|
||||
spec:
|
||||
resources:
|
||||
requests:
|
||||
storage: 1Gi
|
||||
accessModes:
|
||||
- ReadWriteOnce
|
||||
@@ -0,0 +1,8 @@
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
|
||||
resources:
|
||||
- ../../base
|
||||
|
||||
patches:
|
||||
- path: patch-downloads.yaml
|
||||
@@ -0,0 +1,35 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: forust-userbot-deployment
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: forust-userbot
|
||||
volumeMounts:
|
||||
- name: downloads
|
||||
mountPath: /app/downloads
|
||||
volumes:
|
||||
- name: downloads
|
||||
hostPath:
|
||||
path: /home/user/projects/homelab/userbot/Downloads
|
||||
type: DirectoryOrCreate
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: anna-userbot-deployment
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: anna-userbot
|
||||
volumeMounts:
|
||||
- name: downloads
|
||||
mountPath: /app/downloads
|
||||
volumes:
|
||||
- name: downloads
|
||||
hostPath:
|
||||
path: /home/user/projects/homelab/userbot/Downloads
|
||||
type: DirectoryOrCreate
|
||||
@@ -0,0 +1,8 @@
|
||||
apiVersion: kustomize.config.k8s.io/v1beta1
|
||||
kind: Kustomization
|
||||
|
||||
resources:
|
||||
- ../../base
|
||||
|
||||
patches:
|
||||
- path: patch-downloads.yaml
|
||||
@@ -0,0 +1,35 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: forust-userbot-deployment
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: forust-userbot
|
||||
volumeMounts:
|
||||
- name: downloads
|
||||
mountPath: /app/downloads
|
||||
volumes:
|
||||
- name: downloads
|
||||
hostPath:
|
||||
path: /srv/homelab/userbot/Downloads
|
||||
type: DirectoryOrCreate
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: anna-userbot-deployment
|
||||
spec:
|
||||
template:
|
||||
spec:
|
||||
containers:
|
||||
- name: anna-userbot
|
||||
volumeMounts:
|
||||
- name: downloads
|
||||
mountPath: /app/downloads
|
||||
volumes:
|
||||
- name: downloads
|
||||
hostPath:
|
||||
path: /srv/homelab/userbot/Downloads
|
||||
type: DirectoryOrCreate
|
||||
+177
@@ -0,0 +1,177 @@
|
||||
# Moon-Userbot - telegram userbot
|
||||
# Copyright (C) 2020-present Moon Userbot Organization
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
# /// script
|
||||
# requires-python = ">=3.11"
|
||||
# dependencies = [
|
||||
# "pip",
|
||||
# "pyrofork",
|
||||
# "tgcrypto",
|
||||
# "wheel",
|
||||
# "gunicorn",
|
||||
# "flask",
|
||||
# "humanize",
|
||||
# "pygments",
|
||||
# "pymongo",
|
||||
# "psutil",
|
||||
# "Pillow>=10.3.0",
|
||||
# "click",
|
||||
# "dnspython",
|
||||
# "requests",
|
||||
# "environs",
|
||||
# "GitPython",
|
||||
# "beautifulsoup4",
|
||||
# "aiohttp",
|
||||
# "aiofiles",
|
||||
# "pySmartDL",
|
||||
# ]
|
||||
# ///
|
||||
import contextlib
|
||||
import logging
|
||||
import os
|
||||
import platform
|
||||
import sqlite3
|
||||
import subprocess
|
||||
|
||||
import requests
|
||||
from pyrogram import Client, errors, idle
|
||||
from pyrogram.enums.parse_mode import ParseMode
|
||||
from pyrogram.raw.functions.account import DeleteAccount, GetAuthorizations
|
||||
from utils import config
|
||||
from utils.db import db
|
||||
from utils.misc import userbot_version
|
||||
from utils.module import ModuleManager
|
||||
from utils.rentry import rentry_cleanup_job
|
||||
from utils.scripts import restart
|
||||
|
||||
SCRIPT_PATH = os.path.dirname(os.path.realpath(__file__))
|
||||
if os.getcwd() != SCRIPT_PATH:
|
||||
os.chdir(SCRIPT_PATH)
|
||||
|
||||
common_params = {
|
||||
'api_id': config.api_id,
|
||||
'api_hash': config.api_hash,
|
||||
'hide_password': True,
|
||||
'workdir': SCRIPT_PATH,
|
||||
'app_version': userbot_version,
|
||||
'device_model': 'mUserbot',
|
||||
'system_version': platform.version() + ' ' + platform.machine(),
|
||||
'sleep_threshold': 30,
|
||||
'test_mode': config.test_server,
|
||||
'parse_mode': ParseMode.HTML,
|
||||
}
|
||||
|
||||
if config.STRINGSESSION:
|
||||
common_params['session_string'] = config.STRINGSESSION
|
||||
|
||||
app = Client('my_account', **common_params)
|
||||
|
||||
|
||||
def load_missing_modules():
|
||||
all_modules = db.get('custom.modules', 'allModules', [])
|
||||
if not all_modules:
|
||||
return
|
||||
|
||||
custom_modules_path = f'{SCRIPT_PATH}/modules/custom_modules'
|
||||
os.makedirs(custom_modules_path, exist_ok=True)
|
||||
|
||||
try:
|
||||
resp = requests.get(
|
||||
'https://raw.githubusercontent.com/The-MoonTg-project/custom_modules/main/full.txt',
|
||||
timeout=10,
|
||||
)
|
||||
if not resp.ok:
|
||||
logging.error(
|
||||
'Failed to fetch custom modules list: HTTP %s',
|
||||
resp.status_code,
|
||||
)
|
||||
return
|
||||
f = resp.text
|
||||
except Exception as e:
|
||||
logging.error('Failed to fetch custom modules list: %s', e)
|
||||
return
|
||||
modules_dict = {line.split('/')[-1].split()[0]: line.strip() for line in f.splitlines()}
|
||||
|
||||
for module_name in all_modules:
|
||||
module_path = f'{custom_modules_path}/{module_name}.py'
|
||||
if not os.path.exists(module_path) and module_name in modules_dict:
|
||||
url = f'https://raw.githubusercontent.com/The-MoonTg-project/custom_modules/main/{modules_dict[module_name]}.py'
|
||||
resp = requests.get(url, timeout=10)
|
||||
if resp.ok:
|
||||
with open(module_path, 'wb') as f:
|
||||
f.write(resp.content)
|
||||
logging.info('Loaded missing module: %s', module_name)
|
||||
else:
|
||||
logging.warning('Failed to load module: %s', module_name)
|
||||
|
||||
|
||||
async def main():
|
||||
logging.basicConfig(
|
||||
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
|
||||
handlers=[logging.FileHandler('moonlogs.txt'), logging.StreamHandler()],
|
||||
level=logging.INFO,
|
||||
)
|
||||
DeleteAccount.__new__ = None
|
||||
|
||||
try:
|
||||
await app.start()
|
||||
except sqlite3.OperationalError as e:
|
||||
if str(e) == 'database is locked' and os.name == 'posix':
|
||||
logging.warning('Session file is locked. Trying to kill blocking process...')
|
||||
subprocess.run(['fuser', '-k', 'my_account.session'], check=True) # noqa: S607
|
||||
restart()
|
||||
raise
|
||||
except (errors.NotAcceptable, errors.Unauthorized) as e:
|
||||
logging.error(
|
||||
'%s: %s\nMoving session file to my_account.session-old...',
|
||||
e.__class__.__name__,
|
||||
e,
|
||||
)
|
||||
os.rename('./my_account.session', './my_account.session-old')
|
||||
restart()
|
||||
|
||||
load_missing_modules()
|
||||
module_manager = ModuleManager.get_instance()
|
||||
await module_manager.load_modules(app)
|
||||
|
||||
if info := db.get('core.updater', 'restart_info'):
|
||||
text = {
|
||||
'restart': '<b>Restart completed!</b>',
|
||||
'update': '<b>Update process completed!</b>',
|
||||
}[info['type']]
|
||||
with contextlib.suppress(errors.RPCError):
|
||||
await app.edit_message_text(info['chat_id'], info['message_id'], text)
|
||||
db.remove('core.updater', 'restart_info')
|
||||
|
||||
# required for sessionkiller module
|
||||
if db.get('core.sessionkiller', 'enabled', False):
|
||||
db.set(
|
||||
'core.sessionkiller',
|
||||
'auths_hashes',
|
||||
[auth.hash for auth in (await app.invoke(GetAuthorizations())).authorizations],
|
||||
)
|
||||
|
||||
logging.info('Moon-Userbot started!')
|
||||
|
||||
app.loop.create_task(rentry_cleanup_job())
|
||||
|
||||
await idle()
|
||||
|
||||
await app.stop()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
app.run(main())
|
||||
@@ -0,0 +1,32 @@
|
||||
from asyncio import sleep
|
||||
|
||||
from pyrogram import Client, filters
|
||||
from pyrogram.types import Message
|
||||
from utils.misc import modules_help, prefix
|
||||
|
||||
digits = {str(i): el for i, el in enumerate(['0️⃣', '1️⃣', '2️⃣', '3️⃣', '4️⃣', '5️⃣', '6️⃣', '7️⃣', '8️⃣', '9️⃣'])}
|
||||
|
||||
|
||||
def prettify(val: int) -> str:
|
||||
return ''.join(digits[i] for i in str(val))
|
||||
|
||||
|
||||
@Client.on_message(filters.command('ghoul', prefix) & filters.me)
|
||||
async def ghoul_counter(_, message: Message):
|
||||
await message.delete()
|
||||
|
||||
counter = int(message.command[1]) if len(message.command) > 1 and message.command[1].isdigit() else 1000
|
||||
|
||||
msg = await message.reply(prettify(counter), quote=False)
|
||||
|
||||
await sleep(1)
|
||||
|
||||
while counter // 7:
|
||||
counter -= 7
|
||||
await msg.edit(prettify(counter))
|
||||
await sleep(1)
|
||||
|
||||
await msg.edit('<b>🤡 GHOUL 🤡</b>')
|
||||
|
||||
|
||||
modules_help['1000-7'] = {'ghoul [count_from]': 'counting from 1000 (or given [count_from] to 0 as a ghoul'}
|
||||
@@ -0,0 +1,342 @@
|
||||
# Moon-Userbot - telegram userbot
|
||||
# Copyright (C) 2020-present Moon Userbot Organization
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
from contextlib import suppress
|
||||
|
||||
from pyrogram import Client, ContinuePropagation, filters
|
||||
from pyrogram.enums import ChatType
|
||||
from pyrogram.errors import (
|
||||
ChatAdminRequired,
|
||||
RPCError,
|
||||
UserAdminInvalid,
|
||||
)
|
||||
from pyrogram.raw import functions
|
||||
from pyrogram.types import ChatPermissions, Message
|
||||
from utils.db import db
|
||||
from utils.handlers import (
|
||||
AntiChannelsHandler,
|
||||
AntiRaidHandler,
|
||||
BanHandler,
|
||||
DeleteHistoryHandler,
|
||||
DemoteHandler,
|
||||
KickDeletedAccountsHandler,
|
||||
KickHandler,
|
||||
MuteHandler,
|
||||
PromoteHandler,
|
||||
TimeMuteHandler,
|
||||
TimeMuteUsersHandler,
|
||||
TimeUnmuteHandler,
|
||||
UnbanHandler,
|
||||
UnmuteHandler,
|
||||
)
|
||||
from utils.misc import modules_help, prefix
|
||||
from utils.scripts import format_exc, with_reply
|
||||
|
||||
db_cache: dict = db.get_collection('core.ats')
|
||||
|
||||
|
||||
def update_cache():
|
||||
db_cache.clear()
|
||||
db_cache.update(db.get_collection('core.ats'))
|
||||
|
||||
|
||||
@Client.on_message(filters.group & ~filters.me)
|
||||
async def admintool_handler(_, message: Message):
|
||||
if message.sender_chat and (
|
||||
message.sender_chat.type == 'supergroup'
|
||||
or message.sender_chat.id == db_cache.get(f'linked{message.chat.id}', 0)
|
||||
):
|
||||
raise ContinuePropagation
|
||||
|
||||
if message.sender_chat and db_cache.get(f'antich{message.chat.id}', False):
|
||||
with suppress(RPCError):
|
||||
await message.delete()
|
||||
await message.chat.ban_member(message.sender_chat.id)
|
||||
|
||||
tmuted_users = db_cache.get(f'c{message.chat.id}', [])
|
||||
if (
|
||||
message.from_user
|
||||
and message.from_user.id in tmuted_users
|
||||
or message.sender_chat
|
||||
and message.sender_chat.id in tmuted_users
|
||||
):
|
||||
with suppress(RPCError):
|
||||
await message.delete()
|
||||
|
||||
if db_cache.get(f'antiraid{message.chat.id}', False):
|
||||
with suppress(RPCError):
|
||||
await message.delete()
|
||||
if message.from_user:
|
||||
await message.chat.ban_member(message.from_user.id)
|
||||
elif message.sender_chat:
|
||||
await message.chat.ban_member(message.sender_chat.id)
|
||||
|
||||
if message.new_chat_members and db_cache.get(f'welcome_enabled{message.chat.id}', False):
|
||||
await message.reply(
|
||||
db_cache.get(f'welcome_text{message.chat.id}'),
|
||||
disable_web_page_preview=True,
|
||||
)
|
||||
|
||||
raise ContinuePropagation
|
||||
|
||||
|
||||
async def get_user_and_name(message):
|
||||
if message.reply_to_message.from_user:
|
||||
return (
|
||||
message.reply_to_message.from_user.id,
|
||||
message.reply_to_message.from_user.first_name,
|
||||
)
|
||||
if message.reply_to_message.sender_chat:
|
||||
return (
|
||||
message.reply_to_message.sender_chat.id,
|
||||
message.reply_to_message.sender_chat.title,
|
||||
)
|
||||
|
||||
|
||||
@Client.on_message(filters.command(['ban'], prefix) & filters.me)
|
||||
async def ban_command(client: Client, message: Message):
|
||||
handler = BanHandler(client, message)
|
||||
await handler.handle_ban()
|
||||
|
||||
|
||||
@Client.on_message(filters.command(['unban'], prefix) & filters.me)
|
||||
async def unban_command(client: Client, message: Message):
|
||||
handler = UnbanHandler(client, message)
|
||||
await handler.handle_unban()
|
||||
|
||||
|
||||
@Client.on_message(filters.command(['kick'], prefix) & filters.me)
|
||||
async def kick_command(client: Client, message: Message):
|
||||
handler = KickHandler(client, message)
|
||||
await handler.handle_kick()
|
||||
|
||||
|
||||
@Client.on_message(filters.command(['kickdel'], prefix) & filters.me)
|
||||
async def kickdel_cmd(client: Client, message: Message):
|
||||
handler = KickDeletedAccountsHandler(client, message)
|
||||
await handler.kick_deleted_accounts()
|
||||
|
||||
|
||||
@Client.on_message(filters.command(['tmute'], prefix) & filters.me)
|
||||
async def tmute_command(client: Client, message: Message):
|
||||
handler = TimeMuteHandler(client, message)
|
||||
await handler.handle_tmute()
|
||||
update_cache()
|
||||
|
||||
|
||||
@Client.on_message(filters.command(['tunmute'], prefix) & filters.me)
|
||||
async def tunmute_command(client: Client, message: Message):
|
||||
handler = TimeUnmuteHandler(client, message)
|
||||
await handler.handle_tunmute()
|
||||
update_cache()
|
||||
|
||||
|
||||
@Client.on_message(filters.command(['tmute_users'], prefix) & filters.me)
|
||||
async def tunmute_users_command(client: Client, message: Message):
|
||||
handler = TimeMuteUsersHandler(client, message)
|
||||
await handler.list_tmuted_users()
|
||||
|
||||
|
||||
@Client.on_message(filters.command(['unmute'], prefix) & filters.me)
|
||||
async def unmute_command(client: Client, message: Message):
|
||||
handler = UnmuteHandler(client, message)
|
||||
await handler.handle_unmute()
|
||||
|
||||
|
||||
@Client.on_message(filters.command(['mute'], prefix) & filters.me)
|
||||
async def mute_command(client: Client, message: Message):
|
||||
handler = MuteHandler(client, message)
|
||||
await handler.handle_mute()
|
||||
|
||||
|
||||
@Client.on_message(filters.command(['demote'], prefix) & filters.me)
|
||||
async def demote_command(client: Client, message: Message):
|
||||
handler = DemoteHandler(client, message)
|
||||
await handler.handle_demote()
|
||||
|
||||
|
||||
@Client.on_message(filters.command(['promote'], prefix) & filters.me)
|
||||
async def promote_command(client: Client, message: Message):
|
||||
handler = PromoteHandler(client, message)
|
||||
await handler.handle_promote()
|
||||
|
||||
|
||||
@Client.on_message(filters.command(['antich'], prefix))
|
||||
async def anti_channels(client: Client, message: Message):
|
||||
handler = AntiChannelsHandler(client, message)
|
||||
await handler.handle_anti_channels()
|
||||
update_cache()
|
||||
|
||||
|
||||
@Client.on_message(filters.command(['delete_history', 'dh'], prefix))
|
||||
async def delete_history(client: Client, message: Message):
|
||||
handler = DeleteHistoryHandler(client, message)
|
||||
await handler.handle_delete_history()
|
||||
|
||||
|
||||
@Client.on_message(filters.command(['report_spam', 'rs'], prefix))
|
||||
@with_reply
|
||||
async def report_spam(client: Client, message: Message):
|
||||
try:
|
||||
channel = await client.resolve_peer(message.chat.id)
|
||||
|
||||
user_id, name = await get_user_and_name(message)
|
||||
peer = await client.resolve_peer(user_id)
|
||||
await client.invoke(
|
||||
functions.channels.ReportSpam(
|
||||
channel=channel,
|
||||
participant=peer,
|
||||
id=[message.reply_to_message.id],
|
||||
)
|
||||
)
|
||||
except Exception as e:
|
||||
await message.edit(format_exc(e))
|
||||
else:
|
||||
await message.edit(f'<b>Message</a> from {name} was reported</b>')
|
||||
|
||||
|
||||
@Client.on_message(filters.command('pin', prefix) & filters.me)
|
||||
@with_reply
|
||||
async def pin(_, message: Message):
|
||||
try:
|
||||
await message.reply_to_message.pin()
|
||||
await message.edit('<b>Pinned!</b>')
|
||||
except Exception as e:
|
||||
await message.edit(format_exc(e))
|
||||
|
||||
|
||||
@Client.on_message(filters.command('unpin', prefix) & filters.me)
|
||||
@with_reply
|
||||
async def unpin(_, message: Message):
|
||||
try:
|
||||
await message.reply_to_message.unpin()
|
||||
await message.edit('<b>Unpinned!</b>')
|
||||
except Exception as e:
|
||||
await message.edit(format_exc(e))
|
||||
|
||||
|
||||
@Client.on_message(filters.command('ro', prefix) & filters.me)
|
||||
async def ro(client: Client, message: Message):
|
||||
if message.chat.type not in [ChatType.GROUP, ChatType.SUPERGROUP]:
|
||||
await message.edit('<b>Invalid chat type</b>')
|
||||
return
|
||||
|
||||
try:
|
||||
perms = message.chat.permissions
|
||||
perms_list = [
|
||||
perms.can_send_messages,
|
||||
perms.can_send_media_messages,
|
||||
perms.can_send_polls,
|
||||
perms.can_add_web_page_previews,
|
||||
perms.can_change_info,
|
||||
perms.can_invite_users,
|
||||
perms.can_pin_messages,
|
||||
]
|
||||
db.set('core.ats', f'ro{message.chat.id}', perms_list)
|
||||
|
||||
try:
|
||||
await client.set_chat_permissions(message.chat.id, ChatPermissions())
|
||||
except (UserAdminInvalid, ChatAdminRequired):
|
||||
await message.edit('<b>No rights</b>')
|
||||
else:
|
||||
await message.edit(f'<b>Read-only mode activated!\nTurn off with:</b><code>{prefix}unro</code>')
|
||||
except Exception as e:
|
||||
await message.edit(format_exc(e))
|
||||
|
||||
|
||||
@Client.on_message(filters.command('unro', prefix) & filters.me)
|
||||
async def unro(client: Client, message: Message):
|
||||
if message.chat.type not in [ChatType.GROUP, ChatType.SUPERGROUP]:
|
||||
await message.edit('<b>Invalid chat type</b>')
|
||||
return
|
||||
|
||||
try:
|
||||
perms_list = db.get(
|
||||
'core.ats',
|
||||
f'ro{message.chat.id}',
|
||||
[True, True, False, False, False, False, False],
|
||||
)
|
||||
|
||||
common_perms = {
|
||||
'can_send_messages': perms_list[0],
|
||||
'can_send_media_messages': perms_list[1],
|
||||
'can_send_polls': perms_list[2],
|
||||
'can_add_web_page_previews': perms_list[3],
|
||||
'can_change_info': perms_list[4],
|
||||
'can_invite_users': perms_list[5],
|
||||
'can_pin_messages': perms_list[6],
|
||||
}
|
||||
|
||||
perms = ChatPermissions(**common_perms)
|
||||
|
||||
try:
|
||||
await client.set_chat_permissions(message.chat.id, perms)
|
||||
except (UserAdminInvalid, ChatAdminRequired):
|
||||
await message.edit('<b>No rights</b>')
|
||||
else:
|
||||
await message.edit('<b>Read-only mode disabled!</b>')
|
||||
except Exception as e:
|
||||
await message.edit(format_exc(e))
|
||||
|
||||
|
||||
@Client.on_message(filters.command('antiraid', prefix) & filters.me)
|
||||
async def antiraid(client: Client, message: Message):
|
||||
handler = AntiRaidHandler(client, message)
|
||||
await handler.handle_antiraid()
|
||||
update_cache()
|
||||
|
||||
|
||||
@Client.on_message(filters.command(['welcome', 'wc'], prefix) & filters.me)
|
||||
async def welcome(_, message: Message):
|
||||
if message.chat.type not in [ChatType.GROUP, ChatType.SUPERGROUP]:
|
||||
return await message.edit('<b>Unsupported chat type</b>')
|
||||
|
||||
if len(message.command) > 1:
|
||||
text = message.text.split(maxsplit=1)[1]
|
||||
db.set('core.ats', f'welcome_enabled{message.chat.id}', True)
|
||||
db.set('core.ats', f'welcome_text{message.chat.id}', text)
|
||||
|
||||
await message.edit(f'<b>Welcome enabled in this chat\nText:</b> <code>{text}</code>')
|
||||
else:
|
||||
db.set('core.ats', f'welcome_enabled{message.chat.id}', False)
|
||||
await message.edit('<b>Welcome disabled in this chat</b>')
|
||||
|
||||
update_cache()
|
||||
|
||||
|
||||
modules_help['admintool'] = {
|
||||
'ban [reply]/[username/id]* [reason] [report_spam] [delete_history]': 'ban user in chat',
|
||||
'unban [reply]/[username/id]* [reason]': 'unban user in chat',
|
||||
'kick [reply]/[userid]* [reason] [report_spam] [delete_history]': 'kick user out of chat',
|
||||
'mute [reply]/[userid]* [reason] [1m]/[1h]/[1d]/[1w]': 'mute user in chat',
|
||||
'unmute [reply]/[userid]* [reason]': 'unmute user in chat',
|
||||
'promote [reply]/[userid]* [prefix]': 'promote user in chat',
|
||||
'demote [reply]/[userid]* [reason]': 'demote user in chat',
|
||||
'tmute [reply]/[username/id]* [reason]': 'delete all new messages from user in chat',
|
||||
'tunmute [reply]/[username/id]* [reason]': 'stop deleting all messages from user in chat',
|
||||
'tmute_users': 'list of tmuted (.tmute) users',
|
||||
'antich [enable/disable]': 'turn on/off blocking channels in this chat',
|
||||
'delete_history [reply]/[username/id]* [reason]': 'delete history from member in chat',
|
||||
'report_spam [reply]*': 'report spam message in chat',
|
||||
'pin [reply]*': 'Pin replied message',
|
||||
'unpin [reply]*': 'Unpin replied message',
|
||||
'ro': 'enable read-only mode',
|
||||
'unro': 'disable read-only mode',
|
||||
'antiraid [on|off]': 'when enabled, anyone who writes message will be blocked. Useful in raids. '
|
||||
'Running without arguments equals to toggling state',
|
||||
'welcome [text]*': 'enable auto-welcome to new users in groups. Running without text equals to disable',
|
||||
'kickdel': 'Kick all deleted accounts',
|
||||
}
|
||||
@@ -0,0 +1,360 @@
|
||||
# Moon-Userbot - telegram userbot
|
||||
# Copyright (C) 2020-present Moon Userbot Organization
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
from collections.abc import AsyncGenerator
|
||||
from time import perf_counter
|
||||
from typing import Optional
|
||||
|
||||
from pyrogram import Client, enums, filters, raw, types, utils
|
||||
from pyrogram.types.object import Object
|
||||
from utils.misc import modules_help, prefix
|
||||
from utils.scripts import format_exc
|
||||
|
||||
|
||||
class Chat(Object):
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
client: 'Client' = None,
|
||||
id: id, # noqa: A002
|
||||
type: type, # noqa: A002
|
||||
is_verified: bool = None,
|
||||
is_restricted: bool = None,
|
||||
is_creator: bool = None,
|
||||
is_scam: bool = None,
|
||||
is_fake: bool = None,
|
||||
is_support: bool = None,
|
||||
title: str = None,
|
||||
username: str = None,
|
||||
first_name: str = None,
|
||||
last_name: str = None,
|
||||
photo: 'types.ChatPhoto' = None,
|
||||
bio: str = None,
|
||||
description: str = None,
|
||||
dc_id: int = None,
|
||||
has_protected_content: bool = None,
|
||||
invite_link: str = None,
|
||||
pinned_message=None,
|
||||
sticker_set_name: str = None,
|
||||
can_set_sticker_set: bool = None,
|
||||
members_count: int = None,
|
||||
restrictions: list['types.Restriction'] = None,
|
||||
permissions: 'types.ChatPermissions' = None,
|
||||
distance: int = None,
|
||||
linked_chat: 'types.Chat' = None,
|
||||
send_as_chat: 'types.Chat' = None,
|
||||
available_reactions: Optional['types.ChatReactions'] = None,
|
||||
is_admin: bool = False,
|
||||
deactivated: bool = False,
|
||||
):
|
||||
super().__init__(client)
|
||||
|
||||
self.id = id
|
||||
self.type = type
|
||||
self.is_verified = is_verified
|
||||
self.is_restricted = is_restricted
|
||||
self.is_creator = is_creator
|
||||
self.is_scam = is_scam
|
||||
self.is_fake = is_fake
|
||||
self.is_support = is_support
|
||||
self.title = title
|
||||
self.username = username
|
||||
self.first_name = first_name
|
||||
self.last_name = last_name
|
||||
self.photo = photo
|
||||
self.bio = bio
|
||||
self.description = description
|
||||
self.dc_id = dc_id
|
||||
self.has_protected_content = has_protected_content
|
||||
self.invite_link = invite_link
|
||||
self.pinned_message = pinned_message
|
||||
self.sticker_set_name = sticker_set_name
|
||||
self.can_set_sticker_set = can_set_sticker_set
|
||||
self.members_count = members_count
|
||||
self.restrictions = restrictions
|
||||
self.permissions = permissions
|
||||
self.distance = distance
|
||||
self.linked_chat = linked_chat
|
||||
self.send_as_chat = send_as_chat
|
||||
self.available_reactions = available_reactions
|
||||
self.is_admin = is_admin
|
||||
self.deactivated = deactivated
|
||||
|
||||
@staticmethod
|
||||
def _parse_user_chat(client, user: raw.types.User) -> 'Chat':
|
||||
peer_id = user.id
|
||||
|
||||
return Chat(
|
||||
id=peer_id,
|
||||
type=enums.ChatType.BOT if user.bot else enums.ChatType.PRIVATE,
|
||||
is_verified=getattr(user, 'verified', None),
|
||||
is_restricted=getattr(user, 'restricted', None),
|
||||
is_scam=getattr(user, 'scam', None),
|
||||
is_fake=getattr(user, 'fake', None),
|
||||
is_support=getattr(user, 'support', None),
|
||||
username=user.username,
|
||||
first_name=user.first_name,
|
||||
last_name=user.last_name,
|
||||
photo=types.ChatPhoto._parse(client, user.photo, peer_id, user.access_hash),
|
||||
restrictions=types.List([types.Restriction._parse(r) for r in user.restriction_reason]) or None,
|
||||
dc_id=getattr(getattr(user, 'photo', None), 'dc_id', None),
|
||||
client=client,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def _parse_chat_chat(client, chat: raw.types.Chat) -> 'Chat':
|
||||
peer_id = -chat.id
|
||||
return Chat(
|
||||
id=peer_id,
|
||||
type=enums.ChatType.GROUP,
|
||||
title=chat.title,
|
||||
is_creator=getattr(chat, 'creator', None),
|
||||
photo=types.ChatPhoto._parse(client, getattr(chat, 'photo', None), peer_id, 0),
|
||||
permissions=types.ChatPermissions._parse(getattr(chat, 'default_banned_rights', None)),
|
||||
members_count=getattr(chat, 'participants_count', None),
|
||||
dc_id=getattr(getattr(chat, 'photo', None), 'dc_id', None),
|
||||
has_protected_content=getattr(chat, 'noforwards', None),
|
||||
client=client,
|
||||
is_admin=bool(getattr(chat, 'admin_rights', False)),
|
||||
deactivated=chat.deactivated,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def _parse_channel_chat(client, channel: raw.types.Channel) -> 'Chat':
|
||||
peer_id = utils.get_channel_id(channel.id)
|
||||
restriction_reason = getattr(channel, 'restriction_reason', [])
|
||||
|
||||
return Chat(
|
||||
id=peer_id,
|
||||
type=(enums.ChatType.SUPERGROUP if getattr(channel, 'megagroup', None) else enums.ChatType.CHANNEL),
|
||||
is_verified=getattr(channel, 'verified', None),
|
||||
is_restricted=getattr(channel, 'restricted', None),
|
||||
is_creator=getattr(channel, 'creator', None),
|
||||
is_scam=getattr(channel, 'scam', None),
|
||||
is_fake=getattr(channel, 'fake', None),
|
||||
title=channel.title,
|
||||
username=getattr(channel, 'username', None),
|
||||
photo=types.ChatPhoto._parse(
|
||||
client,
|
||||
getattr(channel, 'photo', None),
|
||||
peer_id,
|
||||
getattr(channel, 'access_hash', 0),
|
||||
),
|
||||
restrictions=types.List([types.Restriction._parse(r) for r in restriction_reason]) or None,
|
||||
permissions=types.ChatPermissions._parse(getattr(channel, 'default_banned_rights', None)),
|
||||
members_count=getattr(channel, 'participants_count', None),
|
||||
dc_id=getattr(getattr(channel, 'photo', None), 'dc_id', None),
|
||||
has_protected_content=getattr(channel, 'noforwards', None),
|
||||
is_admin=bool(getattr(channel, 'admin_rights', False)),
|
||||
client=client,
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def _parse(
|
||||
client,
|
||||
message: raw.types.Message | raw.types.MessageService,
|
||||
users: dict,
|
||||
chats: dict,
|
||||
is_chat: bool,
|
||||
) -> 'Chat':
|
||||
from_id = utils.get_raw_peer_id(message.from_id)
|
||||
peer_id = utils.get_raw_peer_id(message.peer_id)
|
||||
chat_id = (peer_id or from_id) if is_chat else (from_id or peer_id)
|
||||
|
||||
if isinstance(message.peer_id, raw.types.PeerUser):
|
||||
return Chat._parse_user_chat(client, users[chat_id])
|
||||
|
||||
if isinstance(message.peer_id, raw.types.PeerChat):
|
||||
return Chat._parse_chat_chat(client, chats[chat_id])
|
||||
|
||||
return Chat._parse_channel_chat(client, chats[chat_id])
|
||||
|
||||
@staticmethod
|
||||
def _parse_dialog(client, peer, users: dict, chats: dict):
|
||||
if isinstance(peer, raw.types.PeerUser):
|
||||
return Chat._parse_user_chat(client, users[peer.user_id])
|
||||
if isinstance(peer, raw.types.PeerChat):
|
||||
return Chat._parse_chat_chat(client, chats[peer.chat_id])
|
||||
return Chat._parse_channel_chat(client, chats[peer.channel_id])
|
||||
|
||||
|
||||
class Dialog(Object):
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
client: 'Client' = None,
|
||||
chat: 'types.Chat',
|
||||
top_message: 'types.Message',
|
||||
unread_messages_count: int,
|
||||
unread_mentions_count: int,
|
||||
unread_mark: bool,
|
||||
is_pinned: bool,
|
||||
):
|
||||
super().__init__(client)
|
||||
|
||||
self.chat = chat
|
||||
self.top_message = top_message
|
||||
self.unread_messages_count = unread_messages_count
|
||||
self.unread_mentions_count = unread_mentions_count
|
||||
self.unread_mark = unread_mark
|
||||
self.is_pinned = is_pinned
|
||||
|
||||
@staticmethod
|
||||
def _parse(client, dialog: 'raw.types.Dialog', messages, users, chats) -> 'Dialog':
|
||||
return Dialog(
|
||||
chat=Chat._parse_dialog(client, dialog.peer, users, chats),
|
||||
top_message=messages.get(utils.get_peer_id(dialog.peer)),
|
||||
unread_messages_count=dialog.unread_count,
|
||||
unread_mentions_count=dialog.unread_mentions_count,
|
||||
unread_mark=dialog.unread_mark,
|
||||
is_pinned=dialog.pinned,
|
||||
client=client,
|
||||
)
|
||||
|
||||
|
||||
async def get_dialogs(self: 'Client', limit: int = 0) -> AsyncGenerator['types.Dialog', None] | None:
|
||||
current = 0
|
||||
total = limit or (1 << 31) - 1
|
||||
limit = min(100, total)
|
||||
offset_date = 0
|
||||
offset_id = 0
|
||||
offset_peer = raw.types.InputPeerEmpty()
|
||||
while True:
|
||||
r = await self.invoke(
|
||||
raw.functions.messages.GetDialogs(
|
||||
offset_date=offset_date,
|
||||
offset_id=offset_id,
|
||||
offset_peer=offset_peer,
|
||||
limit=limit,
|
||||
hash=0,
|
||||
),
|
||||
sleep_threshold=60,
|
||||
)
|
||||
users = {i.id: i for i in r.users}
|
||||
chats = {i.id: i for i in r.chats}
|
||||
messages = {}
|
||||
for message in r.messages:
|
||||
if isinstance(message, raw.types.MessageEmpty):
|
||||
continue
|
||||
chat_id = utils.get_peer_id(message.peer_id)
|
||||
messages[chat_id] = await types.Message._parse(self, message, users, chats)
|
||||
dialogs = []
|
||||
for dialog in r.dialogs:
|
||||
if not isinstance(dialog, raw.types.Dialog):
|
||||
continue
|
||||
dialogs.append(Dialog._parse(self, dialog, messages, users, chats))
|
||||
if not dialogs:
|
||||
return
|
||||
last = dialogs[-1]
|
||||
offset_id = last.top_message.id
|
||||
offset_date = utils.datetime_to_timestamp(last.top_message.date)
|
||||
offset_peer = await self.resolve_peer(last.chat.id)
|
||||
for dialog in dialogs:
|
||||
yield dialog
|
||||
current += 1
|
||||
if current >= total:
|
||||
return
|
||||
|
||||
|
||||
@Client.on_message(filters.command('admlist', prefix) & filters.me)
|
||||
async def admlist(client: Client, message: types.Message):
|
||||
await message.edit("<b>Retrieving information... (it'll take some time)</b>")
|
||||
|
||||
start = perf_counter()
|
||||
try:
|
||||
adminned_chats = []
|
||||
owned_chats = []
|
||||
owned_usernamed_chats = []
|
||||
async for dialog in get_dialogs(client):
|
||||
chat = dialog.chat
|
||||
if getattr(chat, 'deactivated', False):
|
||||
continue
|
||||
if getattr(chat, 'is_creator', False) and getattr(chat, 'username', None):
|
||||
owned_usernamed_chats.append(chat)
|
||||
elif getattr(chat, 'is_creator', False):
|
||||
owned_chats.append(chat)
|
||||
elif getattr(chat, 'is_admin', False):
|
||||
adminned_chats.append(chat)
|
||||
|
||||
text = '<b>Adminned chats:</b>\n'
|
||||
for index, chat in enumerate(adminned_chats):
|
||||
cid = str(chat.id).replace('-100', '')
|
||||
text += f'{index + 1}. <a href=https://t.me/c/{cid}/1>{chat.title}</a>\n'
|
||||
|
||||
text += '\n<b>Owned chats:</b>\n'
|
||||
for index, chat in enumerate(owned_chats):
|
||||
cid = str(chat.id).replace('-100', '')
|
||||
text += f'{index + 1}. <a href=https://t.me/c/{cid}/1>{chat.title}</a>\n'
|
||||
|
||||
text += '\n<b>Owned chats with username:</b>\n'
|
||||
for index, chat in enumerate(owned_usernamed_chats):
|
||||
cid = str(chat.id).replace('-100', '')
|
||||
text += f'{index + 1}. <a href=https://t.me/c/{cid}/1>{chat.title}</a>\n'
|
||||
|
||||
stop = perf_counter()
|
||||
total_count = len(adminned_chats) + len(owned_chats) + len(owned_usernamed_chats)
|
||||
await message.edit(
|
||||
text + '\n'
|
||||
f'<b><u>Total:</u></b> {total_count}'
|
||||
f'\n<b><u>Adminned chats:</u></b> {len(adminned_chats)}\n'
|
||||
f'<b><u>Owned chats:</u></b> {len(owned_chats)}\n'
|
||||
f'<b><u>Owned chats with username:</u></b> {len(owned_usernamed_chats)}\n\n'
|
||||
f'Done in {round(stop - start, 3)} seconds.',
|
||||
)
|
||||
except Exception as e:
|
||||
await message.edit(format_exc(e))
|
||||
return
|
||||
|
||||
|
||||
@Client.on_message(filters.command('admcount', prefix) & filters.me)
|
||||
async def admcount(client: Client, message: types.Message):
|
||||
await message.edit("<b>Retrieving information... (it'll take some time)</b>")
|
||||
|
||||
start = perf_counter()
|
||||
try:
|
||||
adminned_chats = 0
|
||||
owned_chats = 0
|
||||
owned_usernamed_chats = 0
|
||||
async for dialog in get_dialogs(client):
|
||||
chat = dialog.chat
|
||||
if getattr(chat, 'deactivated', False):
|
||||
continue
|
||||
if getattr(chat, 'is_creator', False) and getattr(chat, 'username', None):
|
||||
owned_usernamed_chats += 1
|
||||
elif getattr(chat, 'is_creator', False):
|
||||
owned_chats += 1
|
||||
elif getattr(chat, 'is_admin', False):
|
||||
adminned_chats += 1
|
||||
|
||||
stop = perf_counter()
|
||||
total_count = adminned_chats + owned_chats + owned_usernamed_chats
|
||||
await message.edit(
|
||||
f'<b><u>Total:</u></b> {total_count}'
|
||||
f'\n<b><u>Adminned chats:</u></b> {adminned_chats}\n'
|
||||
f'<b><u>Owned chats:</u></b> {owned_chats}\n'
|
||||
f'<b><u>Owned chats with username:</u></b> {owned_usernamed_chats}\n\n'
|
||||
f'Done in {round(stop - start, 3)} seconds.\n\n'
|
||||
f'<b>Get full list: </b><code>{prefix}admlist</code>',
|
||||
)
|
||||
except Exception as e:
|
||||
await message.edit(format_exc(e))
|
||||
return
|
||||
|
||||
|
||||
modules_help['admlist'] = {
|
||||
'admcount': 'Get count of adminned and owned chats',
|
||||
'admlist': 'Get list of adminned and owned chats',
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
# Dragon-Userbot - telegram userbot
|
||||
# Copyright (C) 2020-present Dragon Userbot Organization
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import datetime
|
||||
|
||||
from pyrogram import Client, filters, types
|
||||
from utils.db import db
|
||||
from utils.misc import modules_help, prefix
|
||||
|
||||
# avoid using global variables
|
||||
afk_info = db.get(
|
||||
'core.afk',
|
||||
'afk_info',
|
||||
{
|
||||
'start': 0,
|
||||
'is_afk': False,
|
||||
'reason': '',
|
||||
},
|
||||
)
|
||||
|
||||
is_afk = filters.create(lambda _, __, ___: afk_info['is_afk'])
|
||||
is_support = filters.create(lambda _, __, message: message.chat.is_support)
|
||||
|
||||
|
||||
@Client.on_message(
|
||||
is_afk & (filters.private | filters.mentioned) & ~filters.channel & ~filters.me & ~filters.bot & ~is_support
|
||||
)
|
||||
async def afk_handler(_, message: types.Message):
|
||||
start = datetime.datetime.fromtimestamp(afk_info['start'])
|
||||
end = datetime.datetime.now().replace(microsecond=0)
|
||||
afk_time = end - start
|
||||
await message.reply(f"<b>I'm AFK {afk_time}\nReason:</b> <i>{afk_info['reason']}</i>")
|
||||
|
||||
|
||||
@Client.on_message(filters.command('afk', prefix) & filters.me)
|
||||
async def afk(_, message):
|
||||
reason = message.text.split(' ', maxsplit=1)[1] if len(message.text.split()) >= 2 else 'None'
|
||||
|
||||
afk_info['start'] = int(datetime.datetime.now().timestamp())
|
||||
afk_info['is_afk'] = True
|
||||
afk_info['reason'] = reason
|
||||
|
||||
await message.edit(f"<b>I'm going AFK.\nReason:</b> <i>{reason}</i>")
|
||||
|
||||
db.set('core.afk', 'afk_info', afk_info)
|
||||
|
||||
|
||||
@Client.on_message(filters.command('unafk', prefix) & filters.me)
|
||||
async def unafk(_, message):
|
||||
if afk_info['is_afk']:
|
||||
start = datetime.datetime.fromtimestamp(afk_info['start'])
|
||||
end = datetime.datetime.now().replace(microsecond=0)
|
||||
afk_time = end - start
|
||||
await message.edit(f"<b>I'm not AFK anymore.\nI was afk {afk_time}</b>")
|
||||
afk_info['is_afk'] = False
|
||||
else:
|
||||
await message.edit("<b>You weren't afk</b>")
|
||||
|
||||
db.set('core.afk', 'afk_info', afk_info)
|
||||
|
||||
|
||||
modules_help['afk'] = {'afk [reason]': 'Go to afk', 'unafk': 'Get out of AFK'}
|
||||
@@ -0,0 +1,116 @@
|
||||
import os
|
||||
|
||||
from PIL import Image
|
||||
from pyrogram import Client, enums, filters
|
||||
from pyrogram.types import Message
|
||||
from utils.misc import modules_help, prefix
|
||||
from utils.scripts import format_exc, import_library
|
||||
|
||||
genai = import_library('google.generativeai', 'google-generativeai')
|
||||
|
||||
from utils.config import gemini_key # noqa: E402
|
||||
|
||||
genai.configure(api_key=gemini_key)
|
||||
|
||||
generation_config_cook = {
|
||||
'temperature': 0.35,
|
||||
'top_p': 0.95,
|
||||
'top_k': 40,
|
||||
'max_output_tokens': 1024,
|
||||
}
|
||||
|
||||
model = genai.GenerativeModel('gemini-1.5-flash-latest')
|
||||
model_cook = genai.GenerativeModel(model_name='gemini-1.5-flash-latest', generation_config=generation_config_cook)
|
||||
|
||||
|
||||
@Client.on_message(filters.command('getai', prefix) & filters.me)
|
||||
async def getai(_, message: Message):
|
||||
try:
|
||||
await message.edit_text('<code>Please Wait...</code>')
|
||||
try:
|
||||
base_img = await message.reply_to_message.download()
|
||||
except AttributeError:
|
||||
return await message.edit_text('<code>Please reply to an image...</code>')
|
||||
|
||||
img = Image.open(base_img)
|
||||
prompt = 'Get details of given image, be as accurate as possible.'
|
||||
|
||||
response = model.generate_content([prompt, img])
|
||||
|
||||
await message.edit_text(f'**Detail Of Image:** {response.text}', parse_mode=enums.ParseMode.MARKDOWN)
|
||||
os.remove(base_img)
|
||||
return
|
||||
except Exception as e:
|
||||
await message.edit_text(f'An error occurred: {format_exc(e)}')
|
||||
|
||||
|
||||
@Client.on_message(filters.command('aicook', prefix) & filters.me)
|
||||
async def aicook(_, message: Message):
|
||||
if message.reply_to_message:
|
||||
try:
|
||||
await message.edit_text('<code>Cooking...</code>')
|
||||
|
||||
try:
|
||||
base_img = await message.reply_to_message.download()
|
||||
except AttributeError:
|
||||
return await message.edit_text('<code>Please reply to an image...</code>')
|
||||
|
||||
img = Image.open(base_img)
|
||||
cook_img = [
|
||||
'Accurately identify the baked good in the image and provide an appropriate and recipe consistent with your analysis. ',
|
||||
img,
|
||||
]
|
||||
|
||||
response = model_cook.generate_content(cook_img)
|
||||
|
||||
await message.edit_text(f'{response.text}', parse_mode=enums.ParseMode.MARKDOWN)
|
||||
os.remove(base_img)
|
||||
return
|
||||
except Exception as e:
|
||||
await message.edit_text(str(e))
|
||||
return await message.edit_text('<code>Please reply to an image...</code>')
|
||||
|
||||
|
||||
@Client.on_message(filters.command('aiseller', prefix) & filters.me)
|
||||
async def aiseller(_, message: Message):
|
||||
if message.reply_to_message:
|
||||
try:
|
||||
await message.edit_text('<code>Generating...</code>')
|
||||
if len(message.command) > 1:
|
||||
taud = message.text.split(maxsplit=1)[1]
|
||||
else:
|
||||
return await message.edit_text(
|
||||
f'<b>Usage: </b><code>{prefix}aiseller [target audience] [reply to product image]</code>'
|
||||
)
|
||||
|
||||
try:
|
||||
base_img = await message.reply_to_message.download()
|
||||
except AttributeError:
|
||||
return await message.edit_text('<code>Please reply to an image...</code>')
|
||||
|
||||
img = Image.open(base_img)
|
||||
sell_img = [
|
||||
'Given an image of a product and its target audience, write an engaging marketing description',
|
||||
'Product Image: ',
|
||||
img,
|
||||
'Target Audience: ',
|
||||
taud,
|
||||
]
|
||||
|
||||
response = model.generate_content(sell_img)
|
||||
|
||||
await message.edit_text(f'{response.text}', parse_mode=enums.ParseMode.MARKDOWN)
|
||||
os.remove(base_img)
|
||||
return
|
||||
except Exception:
|
||||
await message.edit_text(
|
||||
f'<b>Usage: </b><code>{prefix}aiseller [target audience] [reply to product image]</code>'
|
||||
)
|
||||
return await message.edit_text('<code>Please reply to an image...</code>')
|
||||
|
||||
|
||||
modules_help['aimage'] = {
|
||||
'getai [reply to image]*': 'Get details of image with Ai',
|
||||
'aicook [reply to image]*': 'Generate Cooking instrunctions of the given food image',
|
||||
'aiseller [target audience] [reply to product image]*': 'Generate a promotional message for the given image product for the given target audience',
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
from io import BytesIO
|
||||
from random import randint
|
||||
from textwrap import wrap
|
||||
|
||||
from PIL import Image, ImageDraw, ImageFont
|
||||
from pyrogram import Client, enums, filters
|
||||
from pyrogram.types import Message
|
||||
from requests import get
|
||||
from utils.misc import modules_help, prefix
|
||||
|
||||
|
||||
@Client.on_message(filters.command('amogus', prefix) & filters.me)
|
||||
async def amogus(client: Client, message: Message):
|
||||
text = ' '.join(message.command[1:])
|
||||
|
||||
await message.edit(
|
||||
'<b>amgus, tun tun tun tun tun tun tun tudududn tun tun...</b>',
|
||||
parse_mode=enums.ParseMode.HTML,
|
||||
)
|
||||
|
||||
clr = randint(1, 12) # noqa: S311
|
||||
|
||||
url = 'https://raw.githubusercontent.com/The-MoonTg-project/AmongUs/master/'
|
||||
font = ImageFont.truetype(BytesIO(get(url + 'bold.ttf', timeout=10).content), 60)
|
||||
imposter = Image.open(BytesIO(get(f'{url}{clr}.png', timeout=10).content))
|
||||
|
||||
text_ = '\n'.join(['\n'.join(wrap(part, 30)) for part in text.split('\n')])
|
||||
bbox = ImageDraw.Draw(Image.new('RGB', (1, 1))).multiline_textbbox((0, 0), text_, font, stroke_width=2)
|
||||
# w, h = bbox[2] - bbox[0], bbox[3] - bbox[1]
|
||||
w, h = bbox[2], bbox[3]
|
||||
text = Image.new('RGBA', (w + 30, h + 30))
|
||||
ImageDraw.Draw(text).multiline_text((15, 15), text_, '#FFF', font, stroke_width=2, stroke_fill='#000')
|
||||
w = imposter.width + text.width + 10
|
||||
h = max(imposter.height, text.height)
|
||||
|
||||
image = Image.new('RGBA', (w, h))
|
||||
image.paste(imposter, (0, h - imposter.height), imposter)
|
||||
image.paste(text, (w - text.width, 0), text)
|
||||
image.thumbnail((512, 512))
|
||||
|
||||
output = BytesIO()
|
||||
output.name = 'imposter.webp'
|
||||
image.save(output)
|
||||
output.seek(0)
|
||||
|
||||
await message.delete()
|
||||
await client.send_sticker(message.chat.id, output)
|
||||
|
||||
|
||||
modules_help['amogus'] = {'amogus [text]': 'amgus, tun tun tun tun tun tun tun tudududn tun tun'}
|
||||
@@ -0,0 +1,195 @@
|
||||
# From CatUB
|
||||
import asyncio
|
||||
import re
|
||||
from io import BytesIO
|
||||
from random import choice, randint
|
||||
from textwrap import wrap
|
||||
|
||||
import requests
|
||||
from PIL import Image, ImageDraw, ImageFont
|
||||
from pyrogram import Client, filters
|
||||
from pyrogram.types import Message
|
||||
from utils.misc import modules_help, prefix
|
||||
from utils.scripts import edit_or_reply
|
||||
from utils.scripts import reply_check as ReplyCheck
|
||||
|
||||
|
||||
async def amongus_gen(text: str, clr: int) -> str:
|
||||
url = 'https://github.com/TgCatUB/CatUserbot-Resources/raw/master/Resources/Amongus/'
|
||||
font = ImageFont.truetype(
|
||||
BytesIO(
|
||||
requests.get('https://github.com/TgCatUB/CatUserbot-Resources/raw/master/Resources/fonts/bold.ttf', timeout=10).content
|
||||
),
|
||||
60,
|
||||
)
|
||||
imposter = Image.open(BytesIO(requests.get(f'{url}{clr}.png', timeout=10).content))
|
||||
text_ = '\n'.join('\n'.join(wrap(part, 30)) for part in text.split('\n'))
|
||||
bbox = ImageDraw.Draw(Image.new('RGB', (1, 1))).multiline_textbbox((0, 0), text_, font, stroke_width=2)
|
||||
w, h = bbox[2], bbox[3]
|
||||
text = Image.new('RGBA', (w + 30, h + 30))
|
||||
ImageDraw.Draw(text).multiline_text((15, 15), text_, '#FFF', font, stroke_width=2, stroke_fill='#000')
|
||||
w = imposter.width + text.width + 10
|
||||
h = max(imposter.height, text.height)
|
||||
image = Image.new('RGBA', (w, h))
|
||||
image.paste(imposter, (0, h - imposter.height), imposter)
|
||||
image.paste(text, (w - text.width, 0), text)
|
||||
image.thumbnail((512, 512))
|
||||
output = BytesIO()
|
||||
output.name = 'imposter.webp'
|
||||
image.save(output, 'WebP')
|
||||
output.seek(0)
|
||||
return output
|
||||
|
||||
|
||||
async def get_imposter_img(text: str) -> BytesIO:
|
||||
background = requests.get(
|
||||
f'https://github.com/TgCatUB/CatUserbot-Resources/raw/master/Resources/imposter/impostor{randint(1, 22)}.png', # noqa: S311
|
||||
timeout=10,
|
||||
).content
|
||||
font = requests.get(
|
||||
'https://github.com/TgCatUB/CatUserbot-Resources/raw/master/Resources/fonts/roboto_regular.ttf',
|
||||
timeout=10,
|
||||
).content
|
||||
font = BytesIO(font)
|
||||
font = ImageFont.truetype(font, 30)
|
||||
image = Image.new('RGBA', (1, 1), (0, 0, 0, 0))
|
||||
draw = ImageDraw.Draw(image)
|
||||
bbox = ImageDraw.Draw(Image.new('RGB', (1, 1))).multiline_textbbox((0, 0), text, font, stroke_width=2)
|
||||
w, h = bbox[2], bbox[3]
|
||||
image = Image.open(BytesIO(background))
|
||||
x, y = image.size
|
||||
draw = ImageDraw.Draw(image)
|
||||
draw.multiline_text(((x - w) // 2, (y - h) // 2), text=text, font=font, fill='white', align='center')
|
||||
output = BytesIO()
|
||||
output.name = 'impostor.png'
|
||||
image.save(output, 'PNG')
|
||||
output.seek(0)
|
||||
return output
|
||||
|
||||
|
||||
@Client.on_message(filters.command('amongus', prefix) & filters.me)
|
||||
async def amongus_cmd(client: Client, message: Message):
|
||||
text = ' '.join(message.command[1:]) if len(message.command) > 1 else ''
|
||||
reply = message.reply_to_message
|
||||
await message.edit('tun tun tun...')
|
||||
if not text and reply:
|
||||
text = reply.text or reply.caption or ''
|
||||
|
||||
clr = re.findall(r'-c\d+', text)
|
||||
try:
|
||||
clr = clr[0]
|
||||
clr = clr.replace('-c', '')
|
||||
text = text.replace(f'-c{clr}', '')
|
||||
clr = int(clr)
|
||||
if clr > 12 or clr < 1:
|
||||
clr = randint(1, 12) # noqa: S311
|
||||
except IndexError:
|
||||
clr = randint(1, 12) # noqa: S311
|
||||
|
||||
if not text:
|
||||
if not reply:
|
||||
text = f'{message.from_user.first_name} Was a traitor!'
|
||||
else:
|
||||
text = f'{reply.from_user.first_name} Was a traitor!'
|
||||
|
||||
imposter_file = await amongus_gen(text, clr)
|
||||
await message.delete()
|
||||
await client.send_sticker(
|
||||
message.chat.id,
|
||||
imposter_file,
|
||||
reply_to_message_id=ReplyCheck(message),
|
||||
)
|
||||
|
||||
|
||||
@Client.on_message(filters.command('imposter', prefix) & filters.me)
|
||||
async def imposter_cmd(client: Client, message: Message):
|
||||
remain = randint(1, 2) # noqa: S311
|
||||
imps = ["wasn't the impostor", 'was the impostor']
|
||||
|
||||
if message.reply_to_message:
|
||||
user = message.reply_to_message.from_user
|
||||
text = f'{user.first_name} {choice(imps)}.' # noqa: S311
|
||||
else:
|
||||
args = message.text.split()[1:]
|
||||
text = ' '.join(args) if args else f'{message.from_user.first_name} {choice(imps)}.' # noqa: S311
|
||||
|
||||
text += f'\n{remain} impostor(s) remain.'
|
||||
imposter_file = await get_imposter_img(text)
|
||||
await message.delete()
|
||||
await client.send_photo(
|
||||
message.chat.id,
|
||||
imposter_file,
|
||||
reply_to_message_id=ReplyCheck(message),
|
||||
)
|
||||
|
||||
|
||||
@Client.on_message(filters.command(['imp', 'impn'], prefix) & filters.me)
|
||||
async def imp_animation(client: Client, message: Message):
|
||||
name = ' '.join(message.command[1:]) if len(message.command) > 1 else ''
|
||||
if not name:
|
||||
reply = message.reply_to_message
|
||||
name = reply.from_user.first_name if reply else message.from_user.first_name
|
||||
cmd = message.command[0].lower()
|
||||
|
||||
text1 = await edit_or_reply(message, 'Uhmm... Something is wrong here!!')
|
||||
await asyncio.sleep(2)
|
||||
await text1.delete()
|
||||
|
||||
stcr1 = await client.send_sticker(message.chat.id, 'CAADAQADRwADnjOcH98isYD5RJTwAg')
|
||||
text2 = await message.reply(f'<b>{message.from_user.first_name}:</b> I have to call discussion')
|
||||
await asyncio.sleep(3)
|
||||
await stcr1.delete()
|
||||
await text2.delete()
|
||||
|
||||
stcr2 = await client.send_sticker(message.chat.id, 'CAADAQADRgADnjOcH9odHIXtfgmvAg')
|
||||
text3 = await message.reply(f'<b>{message.from_user.first_name}:</b> We have to eject the imposter or will lose')
|
||||
await asyncio.sleep(3)
|
||||
await stcr2.delete()
|
||||
await text3.delete()
|
||||
|
||||
stcr3 = await client.send_sticker(message.chat.id, 'CAADAQADOwADnjOcH77v3Ap51R7gAg')
|
||||
text4 = await message.reply('<b>Others:</b> Where???')
|
||||
await asyncio.sleep(2)
|
||||
await text4.edit('<b>Others:</b> Who??')
|
||||
await asyncio.sleep(2)
|
||||
await text4.edit(f'<b>{message.from_user.first_name}:</b> Its {name}, I saw {name} using vent')
|
||||
await asyncio.sleep(3)
|
||||
await text4.edit(f'<b>Others:</b> Okay.. Vote {name}')
|
||||
await asyncio.sleep(2)
|
||||
await stcr3.delete()
|
||||
await text4.delete()
|
||||
|
||||
stcr4 = await client.send_sticker(message.chat.id, 'CAADAQADLwADnjOcH-wxu-ehy6NRAg')
|
||||
event = await message.reply(f'{name} is ejected.......')
|
||||
|
||||
# Ejection animation
|
||||
for _ in range(9):
|
||||
await asyncio.sleep(0.5)
|
||||
curr_pos = _ + 1
|
||||
spaces_before = 'ㅤ' * curr_pos
|
||||
await event.edit(f'{spaces_before}ඞ{"ㅤ" * (9 - curr_pos)}')
|
||||
|
||||
await asyncio.sleep(0.5)
|
||||
await event.edit('ㅤㅤㅤㅤㅤㅤㅤㅤㅤ')
|
||||
await asyncio.sleep(0.2)
|
||||
await stcr4.delete()
|
||||
|
||||
if cmd == 'imp':
|
||||
text = f". 。 • ゚ 。 .\n . . 。 。 . \n\n . 。 ඞ 。 . • •\n\n ゚{name} was an Imposter. 。 . 。 . 。 . \n . 。 . \n ' 0 Impostor remains 。 . . 。 . 。 . 。 . . . , 。\n ゚ . . , 。 . . 。"
|
||||
sticker_id = 'CAADAQADLQADnjOcH39IqwyR6Q_0Ag'
|
||||
else:
|
||||
text = f". 。 • ゚ 。 .\n . . 。 。 . \n\n . 。 ඞ 。 . • •\n\n ゚{name} was not an Imposter. 。 . 。 . 。 . \n . 。 . \n ' 1 Impostor remains 。 . . 。 . 。 . 。 . . . , 。\n ゚ . . , 。 . . 。"
|
||||
sticker_id = 'CAADAQADQAADnjOcH-WOkB8DEctJAg'
|
||||
|
||||
await event.edit(text)
|
||||
await asyncio.sleep(4)
|
||||
await event.delete()
|
||||
await client.send_sticker(message.chat.id, sticker_id)
|
||||
|
||||
|
||||
modules_help['amongus'] = {
|
||||
'amongus': 'Create Among Us themed sticker [text/reply] [-c1 to -c12 for colors]',
|
||||
'imposter': 'Create Among Us imposter image [username/reply]',
|
||||
'imp': 'Create Among Us ejection animation (imposter)',
|
||||
'impn': 'Create Among Us ejection animation (not imposter)',
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,230 @@
|
||||
import os
|
||||
|
||||
import aiofiles
|
||||
import requests
|
||||
from pyrogram import Client, enums, filters
|
||||
from pyrogram.errors import MediaCaptionTooLong
|
||||
from pyrogram.types import InputMediaPhoto, Message
|
||||
from utils.misc import modules_help, prefix
|
||||
from utils.scripts import format_exc
|
||||
|
||||
url = 'https://api.safone.co'
|
||||
|
||||
headers = {
|
||||
'Accept-Language': 'en-US,en;q=0.9',
|
||||
'Connection': 'keep-alive',
|
||||
'DNT': '1',
|
||||
'Referer': 'https://api.safone.co/docs',
|
||||
'Sec-Fetch-Dest': 'empty',
|
||||
'Sec-Fetch-Mode': 'cors',
|
||||
'Sec-Fetch-Site': 'same-origin',
|
||||
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36',
|
||||
'accept': 'application/json',
|
||||
'sec-ch-ua': '"Chromium";v="124", "Google Chrome";v="124", "Not-A.Brand";v="99"',
|
||||
'sec-ch-ua-mobile': '?0',
|
||||
'sec-ch-ua-platform': '"Linux"',
|
||||
}
|
||||
|
||||
|
||||
@Client.on_message(filters.command('anime_search', prefix) & filters.me)
|
||||
async def anime_search(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}/anime/search?query={query}', headers=headers, timeout=5)
|
||||
if response.status_code != 200:
|
||||
await message.edit_text('Something went wrong')
|
||||
return
|
||||
|
||||
result = response.json()
|
||||
|
||||
averageScore = result['averageScore']
|
||||
try:
|
||||
coverImage_url = result['imageUrl']
|
||||
coverImage = requests.get(url=coverImage_url, timeout=10).content
|
||||
async with aiofiles.open('coverImage.jpg', mode='wb') as f:
|
||||
await f.write(coverImage)
|
||||
|
||||
except Exception:
|
||||
coverImage = None
|
||||
|
||||
title = result['title']['english']
|
||||
trailer = result['trailer']['id']
|
||||
description = result['description']
|
||||
episodes = result['episodes']
|
||||
genres = ', '.join(result['genres'])
|
||||
isAdult = result['isAdult']
|
||||
status = result['status']
|
||||
studios = ', '.join(result['studios'])
|
||||
|
||||
await message.delete()
|
||||
await client.send_media_group(
|
||||
chat_id,
|
||||
[
|
||||
InputMediaPhoto(
|
||||
'coverImage.jpg',
|
||||
caption=f"<b>Title:</b> <code>{title}</code>\n<b>Average Score:</b> <code>{averageScore}</code>\n<b>Status:</b> <code>{status}</code>\n<b>Genres:</b> <code>{genres}</code>\n<b>Episodes:</b> <code>{episodes}</code>\n<b>Is Adult:</b> <code>{isAdult}</code>\n<b>Studios:</b> <code>{studios}</code>\n<b>Description:</b> <code>{description}</code>\n<b>Trailer:</b> <a href='https://youtu.be/{trailer}'>Click Here</a>",
|
||||
)
|
||||
],
|
||||
)
|
||||
|
||||
except MediaCaptionTooLong:
|
||||
description = description[:850]
|
||||
await message.delete()
|
||||
await client.send_media_group(
|
||||
chat_id,
|
||||
[
|
||||
InputMediaPhoto(
|
||||
'coverImage.jpg',
|
||||
caption=f"<b>Title:</b> <code>{title}</code>\n<b>Average Score:</b> <code>{averageScore}</code>\n<b>Status:</b> <code>{status}</code>\n<b>Genres:</b> <code>{genres}</code>\n<b>Episodes:</b> <code>{episodes}</code>\n<b>Is Adult:</b> <code>{isAdult}</code>\n<b>Studios:</b> <code>{studios}</code>\n<b>Description:</b> <code>{description}</code>\n<b>Trailer:</b> <a href='https://youtu.be/{trailer}'>Click Here</a>",
|
||||
)
|
||||
],
|
||||
)
|
||||
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('manga_search', prefix) & filters.me)
|
||||
async def manga_search(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}/anime/manga?query={query}', headers=headers, timeout=5)
|
||||
if response.status_code != 200:
|
||||
await message.edit_text('Something went wrong')
|
||||
return
|
||||
|
||||
result = response.json()
|
||||
|
||||
averageScore = result['averageScore']
|
||||
try:
|
||||
coverImage_url = result['imageUrl']
|
||||
coverImage = requests.get(url=coverImage_url, timeout=10).content
|
||||
async with aiofiles.open('coverImage.jpg', mode='wb') as f:
|
||||
await f.write(coverImage)
|
||||
|
||||
except Exception:
|
||||
coverImage = None
|
||||
|
||||
title = result['title']['english']
|
||||
trailer = result['trailer']['id']
|
||||
description = result['description']
|
||||
chapters = result['chapters']
|
||||
genres = ', '.join(result['genres'])
|
||||
isAdult = result['isAdult']
|
||||
status = result['status']
|
||||
studios = ', '.join(result['studios'])
|
||||
|
||||
await message.delete()
|
||||
await client.send_media_group(
|
||||
chat_id,
|
||||
[
|
||||
InputMediaPhoto(
|
||||
'coverImage.jpg',
|
||||
caption=f"<b>Title:</b> <code>{title}</code>\n<b>Average Score:</b> <code>{averageScore}</code>\n<b>Status:</b> <code>{status}</code>\n<b>Genres:</b> <code>{genres}</code>\n<b>Chapters:</b> <code>{chapters}</code>\n<b>Is Adult:</b> <code>{isAdult}</code>\n<b>Studios:</b> <code>{studios}</code>\n<b>Description:</b> <code>{description}</code>\n<b>Trailer:</b> <a href='https://youtu.be/{trailer}'>Click Here</a>",
|
||||
)
|
||||
],
|
||||
)
|
||||
|
||||
except MediaCaptionTooLong:
|
||||
description = description[:850]
|
||||
await message.delete()
|
||||
await client.send_media_group(
|
||||
chat_id,
|
||||
[
|
||||
InputMediaPhoto(
|
||||
'coverImage.jpg',
|
||||
caption=f"<b>Title:</b> <code>{title}</code>\n<b>Average Score:</b> <code>{averageScore}</code>\n<b>Status:</b> <code>{status}</code>\n<b>Genres:</b> <code>{genres}</code>\n<b>Chapters:</b> <code>{chapters}</code>\n<b>Is Adult:</b> <code>{isAdult}</code>\n<b>Studios:</b> <code>{studios}</code>\n<b>Description:</b> <code>{description}</code>\n<b>Trailer:</b> <a href='https://youtu.be/{trailer}'>Click Here</a>",
|
||||
)
|
||||
],
|
||||
)
|
||||
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('character', prefix) & filters.me)
|
||||
async def character(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}/anime/character?query={query}', headers=headers, timeout=5)
|
||||
if response.status_code != 200:
|
||||
await message.edit_text('Something went wrong')
|
||||
return
|
||||
|
||||
result = response.json()
|
||||
|
||||
try:
|
||||
coverImage_url = result['image']['large']
|
||||
coverImage = requests.get(url=coverImage_url, timeout=10).content
|
||||
async with aiofiles.open('coverImage.jpg', mode='wb') as f:
|
||||
await f.write(coverImage)
|
||||
|
||||
except Exception:
|
||||
coverImage = None
|
||||
|
||||
age = result['age']
|
||||
description = result['description']
|
||||
height = result['height']
|
||||
name = result['name']['full']
|
||||
native_name = result['name']['native']
|
||||
read_more = result['siteUrl']
|
||||
|
||||
await message.delete()
|
||||
await client.send_media_group(
|
||||
chat_id,
|
||||
[
|
||||
InputMediaPhoto(
|
||||
'coverImage.jpg',
|
||||
caption=f'**Name:** `{name}`\n**Native Name:** `{native_name}`\n**Age:** `{age}`\n**Height:** {height}\n**Description:** `{description}`[read more...]({read_more})',
|
||||
parse_mode=enums.ParseMode.MARKDOWN,
|
||||
)
|
||||
],
|
||||
)
|
||||
|
||||
except MediaCaptionTooLong:
|
||||
description = description[:850]
|
||||
await message.delete()
|
||||
await client.send_media_group(
|
||||
chat_id,
|
||||
[
|
||||
InputMediaPhoto(
|
||||
'coverImage.jpg',
|
||||
caption=f'**Name:** `{name}`\n**Native Name:** `{native_name}`\n**Age:** `{age}`\n**Height:** {height}\n**Description:** `{description}`[read more...]({read_more})',
|
||||
parse_mode=enums.ParseMode.MARKDOWN,
|
||||
)
|
||||
],
|
||||
)
|
||||
except Exception as e:
|
||||
await message.edit_text(format_exc(e))
|
||||
finally:
|
||||
if os.path.exists('coverImage.jpg'):
|
||||
os.remove('coverImage.jpg')
|
||||
|
||||
|
||||
modules_help['anilist'] = {
|
||||
'anime_search': 'Search for anime on Anilist',
|
||||
'manga_search': 'Search for manga on Anilist',
|
||||
'character': 'Search for character on Anilist',
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
from io import BytesIO
|
||||
|
||||
from aiohttp import ClientSession
|
||||
from pyrogram import Client, enums, filters
|
||||
from pyrogram.types import Message
|
||||
|
||||
# noinspection PyUnresolvedReferences
|
||||
from utils.misc import modules_help, prefix
|
||||
from utils.scripts import format_exc
|
||||
|
||||
session = ClientSession()
|
||||
|
||||
|
||||
class Post:
|
||||
def __init__(self, source: dict, session: ClientSession):
|
||||
self._json = source
|
||||
self.session = session
|
||||
|
||||
@property
|
||||
async def image(self):
|
||||
return (
|
||||
self.file_url
|
||||
if self.file_url
|
||||
else (
|
||||
self.large_file_url
|
||||
if self.large_file_url
|
||||
else (
|
||||
self.source
|
||||
if self.source and 'pximg' not in self.source
|
||||
else await self.pximg
|
||||
if self.source
|
||||
else None
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
@property
|
||||
async def pximg(self):
|
||||
async with self.session.get(self.source) as response:
|
||||
return BytesIO(await response.read())
|
||||
|
||||
def __getattr__(self, item):
|
||||
return self._json.get(item)
|
||||
|
||||
|
||||
async def random():
|
||||
async with session.get(url='https://danbooru.donmai.us/posts/random.json') as response:
|
||||
return Post(await response.json(encoding='utf-8'), session)
|
||||
|
||||
|
||||
@Client.on_message(filters.command(['arnd', 'arandom'], prefix) & filters.me)
|
||||
async def anime_handler(client: Client, message: Message):
|
||||
try:
|
||||
await message.edit('<b>Searching art</b>', parse_mode=enums.ParseMode.HTML)
|
||||
ra = await random()
|
||||
img = await ra.image
|
||||
await message.reply_photo(
|
||||
photo=img,
|
||||
caption=f'<b>{ra.tag_string_general if ra.tag_string_general else "Untitled"}</b>',
|
||||
parse_mode=enums.ParseMode.HTML,
|
||||
)
|
||||
return await message.delete()
|
||||
except Exception as e:
|
||||
await message.edit(format_exc(e), parse_mode=enums.ParseMode.HTML)
|
||||
|
||||
|
||||
modules_help['anime'] = {
|
||||
'arnd': 'Random anime art (May get caught 18+)',
|
||||
'arandom': 'Random anime art (May get caught 18+)',
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
# Moon-Userbot - telegram userbot
|
||||
# Copyright (C) 2020-present Moon Userbot Organization
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import asyncio
|
||||
|
||||
import requests
|
||||
from pyrogram import Client, filters
|
||||
from pyrogram.types import Message
|
||||
from utils.misc import modules_help, prefix
|
||||
from utils.scripts import format_exc
|
||||
|
||||
|
||||
def get_neko_media(query):
|
||||
return requests.get(f'https://nekos.life/api/v2/img/{query}', timeout=10).json()['url']
|
||||
|
||||
|
||||
@Client.on_message(filters.command('neko', prefix) & filters.me)
|
||||
async def neko(_, message: Message):
|
||||
if len(message.command) == 1:
|
||||
await message.edit(
|
||||
f"<b>Neko type isn't provided\nYou can get available neko types with <code>{prefix}neko_types</code></b>"
|
||||
)
|
||||
|
||||
query = message.command[1]
|
||||
await message.edit('<b>Loading...</b>')
|
||||
try:
|
||||
await message.edit(f'{get_neko_media(query)}', disable_web_page_preview=False)
|
||||
except Exception as e:
|
||||
await message.edit(format_exc(e))
|
||||
|
||||
|
||||
@Client.on_message(filters.command(['nekotypes', 'neko_types'], prefix) & filters.me)
|
||||
async def neko_types_func(_, message: Message):
|
||||
neko_types = """hug kiss tickle lewd neko pat lizard 8ball cat chat fact smug woof gasm goose cuddle avatar slap gecg feed fox_girl meow wallpaper spank waifu ngif name owoify spoiler why"""
|
||||
await message.edit(' '.join(f'<code>{n}</code>' for n in neko_types.split()))
|
||||
|
||||
|
||||
@Client.on_message(filters.command(['nekospam', 'neko_spam'], prefix) & filters.me)
|
||||
async def neko_spam(client: Client, message: Message):
|
||||
query = message.command[1]
|
||||
amount = int(message.command[2])
|
||||
|
||||
await message.delete()
|
||||
|
||||
for _ in range(amount):
|
||||
if message.reply_to_message:
|
||||
await message.reply_to_message.reply(get_neko_media(query))
|
||||
else:
|
||||
await client.send_message(message.chat.id, get_neko_media(query))
|
||||
await asyncio.sleep(0.1)
|
||||
|
||||
|
||||
modules_help['neko'] = {
|
||||
'neko [type]*': 'Get neko media',
|
||||
'neko_types': 'Available neko types',
|
||||
'neko_spam [type]* [amount]*': 'Start spam with neko media',
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
from random import randint
|
||||
|
||||
from pyrogram import Client, enums, filters
|
||||
from pyrogram.types import Message
|
||||
from utils.misc import modules_help, prefix
|
||||
from utils.scripts import format_exc
|
||||
|
||||
|
||||
@Client.on_message(filters.command(['aniq', 'aq'], prefix) & filters.me)
|
||||
async def aniquotes_handler(client: Client, message: Message):
|
||||
if message.reply_to_message and message.reply_to_message.text:
|
||||
query = message.reply_to_message.text[:512]
|
||||
elif message.reply_to_message and message.reply_to_message.caption:
|
||||
query = message.reply_to_message.caption[:512]
|
||||
elif len(message.command) > 1:
|
||||
query = message.text.split(maxsplit=1)[1][:512]
|
||||
else:
|
||||
return await message.edit(
|
||||
'<b>[💮 Aniquotes] <i>Please enter text to create sticker.</i></b>',
|
||||
parse_mode=enums.ParseMode.HTML,
|
||||
)
|
||||
|
||||
try:
|
||||
await message.delete()
|
||||
result = await client.get_inline_bot_results('@quotafbot', query)
|
||||
return await message.reply_inline_bot_result(
|
||||
query_id=result.query_id,
|
||||
result_id=result.results[randint(1, 2)].id, # noqa: S311
|
||||
reply_to_message_id=(message.reply_to_message.id if message.reply_to_message else None),
|
||||
)
|
||||
except Exception as e:
|
||||
return await message.reply(
|
||||
f'<b>[💮 Aniquotes]</b>\n<code>{format_exc(e)}</code>',
|
||||
parse_mode=enums.ParseMode.HTML,
|
||||
)
|
||||
|
||||
|
||||
modules_help['aniquotes'] = {
|
||||
'aq [text]': 'Create animated sticker with text',
|
||||
}
|
||||
@@ -0,0 +1,222 @@
|
||||
# Moon-Userbot - telegram userbot
|
||||
# Copyright (C) 2020-present Moon Userbot Organization
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import os
|
||||
|
||||
from pyrogram import Client, filters
|
||||
from pyrogram.raw import functions
|
||||
from pyrogram.types import Message
|
||||
from utils.config import pm_limit
|
||||
from utils.db import db
|
||||
from utils.misc import modules_help, prefix
|
||||
|
||||
anti_pm_enabled = filters.create(lambda _, __, ___: db.get('core.antipm', 'status', False))
|
||||
|
||||
in_contact_list = filters.create(lambda _, __, message: message.from_user.is_contact)
|
||||
|
||||
is_support = filters.create(lambda _, __, message: message.chat.is_support)
|
||||
|
||||
USER_WARNINGS = {}
|
||||
|
||||
|
||||
@Client.on_message(filters.private & ~filters.me & ~filters.bot & ~in_contact_list & ~is_support & anti_pm_enabled)
|
||||
async def anti_pm_handler(client: Client, message: Message):
|
||||
user_id = message.from_user.id
|
||||
ids = message.chat.id
|
||||
b_f = await client.get_me()
|
||||
u_n = b_f.first_name
|
||||
user = await client.get_users(ids)
|
||||
u_f = user.first_name
|
||||
default_text = db.get('core.antipm', 'antipm_msg', None)
|
||||
if default_text is None:
|
||||
default_text = f"""<b>Hello, {u_f}!
|
||||
This is the Assistant Of {u_n}.</b>
|
||||
<i>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!</i>
|
||||
|
||||
<b>This is an automated message by the assistant.</b>
|
||||
<b><u>Currently You Have <code>{USER_WARNINGS.get(user_id, 0)}</code> Warnings.</u></b>
|
||||
"""
|
||||
else:
|
||||
default_text = default_text.format(user=u_f, my_name=u_n, warns=USER_WARNINGS.get(user_id, 0))
|
||||
|
||||
if db.get('core.antipm', 'spamrep', False):
|
||||
user_info = await client.resolve_peer(ids)
|
||||
await client.invoke(functions.messages.ReportSpam(peer=user_info))
|
||||
|
||||
if db.get('core.antipm', 'block', False):
|
||||
await client.block_user(user_id)
|
||||
|
||||
if db.get('core.antipm', f'disallowusers{ids}') == user_id != db.get('core.antipm', f'allowusers{ids}') or db.get(
|
||||
'core.antipm', f'disallowusers{ids}'
|
||||
) != user_id != db.get('core.antipm', f'allowusers{ids}'):
|
||||
default_pic = db.get('core.antipm', 'antipm_pic', None)
|
||||
if default_pic and os.path.exists(default_pic):
|
||||
await client.send_photo(message.chat.id, default_pic, caption=default_text)
|
||||
else:
|
||||
await client.send_message(message.chat.id, default_text)
|
||||
|
||||
if user_id in USER_WARNINGS:
|
||||
USER_WARNINGS[user_id] += 1
|
||||
else:
|
||||
USER_WARNINGS[user_id] = 1
|
||||
|
||||
if USER_WARNINGS[user_id] > pm_limit:
|
||||
await client.send_message(
|
||||
message.chat.id,
|
||||
'<b>Ehm...! That was your Last warn, Bye Bye see you L0L</b>',
|
||||
)
|
||||
await client.block_user(user_id)
|
||||
del USER_WARNINGS[user_id]
|
||||
|
||||
|
||||
@Client.on_message(filters.command(['antipm', 'anti_pm'], prefix) & filters.me)
|
||||
async def anti_pm(_, message: Message):
|
||||
if len(message.command) == 1:
|
||||
if db.get('core.antipm', 'status', False):
|
||||
await message.edit(f'<b>Anti-PM status: enabled\nDisable with: </b><code>{prefix}antipm disable</code>')
|
||||
else:
|
||||
await message.edit(f'<b>Anti-PM status: disabled\nEnable with: </b><code>{prefix}antipm enable</code>')
|
||||
elif message.command[1] in ['enable', 'on', '1', 'yes', 'true']:
|
||||
db.set('core.antipm', 'status', True)
|
||||
await message.edit('<b>Anti-PM enabled!</b>')
|
||||
elif message.command[1] in ['disable', 'off', '0', 'no', 'false']:
|
||||
db.set('core.antipm', 'status', False)
|
||||
await message.edit('<b>Anti-PM disabled!</b>')
|
||||
else:
|
||||
await message.edit(f'<b>Usage: {prefix}antipm [enable|disable]</b>')
|
||||
|
||||
|
||||
@Client.on_message(filters.command(['antipm_report'], prefix) & filters.me)
|
||||
async def antipm_report(_, message: Message):
|
||||
if len(message.command) == 1:
|
||||
if db.get('core.antipm', 'spamrep', False):
|
||||
await message.edit(
|
||||
f'<b>Spam-reporting enabled.\nDisable with: </b><code>{prefix}antipm_report disable</code>'
|
||||
)
|
||||
else:
|
||||
await message.edit(
|
||||
f'<b>Spam-reporting disabled.\nEnable with: </b><code>{prefix}antipm_report enable</code>'
|
||||
)
|
||||
elif message.command[1] in ['enable', 'on', '1', 'yes', 'true']:
|
||||
db.set('core.antipm', 'spamrep', True)
|
||||
await message.edit('<b>Spam-reporting enabled!</b>')
|
||||
elif message.command[1] in ['disable', 'off', '0', 'no', 'false']:
|
||||
db.set('core.antipm', 'spamrep', False)
|
||||
await message.edit('<b>Spam-reporting disabled!</b>')
|
||||
else:
|
||||
await message.edit(f'<b>Usage: {prefix}antipm_report [enable|disable]</b>')
|
||||
|
||||
|
||||
@Client.on_message(filters.command(['antipm_block'], prefix) & filters.me)
|
||||
async def antipm_block(_, message: Message):
|
||||
if len(message.command) == 1:
|
||||
if db.get('core.antipm', 'block', False):
|
||||
await message.edit(
|
||||
f'<b>Blocking users enabled.\nDisable with: </b><code>{prefix}antipm_block disable</code>'
|
||||
)
|
||||
else:
|
||||
await message.edit(
|
||||
f'<b>Blocking users disabled.\nEnable with: </b><code>{prefix}antipm_block enable</code>'
|
||||
)
|
||||
elif message.command[1] in ['enable', 'on', '1', 'yes', 'true']:
|
||||
db.set('core.antipm', 'block', True)
|
||||
await message.edit('<b>Blocking users enabled!</b>')
|
||||
elif message.command[1] in ['disable', 'off', '0', 'no', 'false']:
|
||||
db.set('core.antipm', 'block', False)
|
||||
await message.edit('<b>Blocking users disabled!</b>')
|
||||
else:
|
||||
await message.edit(f'<b>Usage: {prefix}antipm_block [enable|disable]</b>')
|
||||
|
||||
|
||||
@Client.on_message(filters.command(['a'], prefix) & filters.me)
|
||||
async def add_contact(_, message: Message):
|
||||
ids = message.chat.id
|
||||
|
||||
db.set('core.antipm', f'allowusers{ids}', ids)
|
||||
if ids in USER_WARNINGS:
|
||||
del USER_WARNINGS[ids]
|
||||
await message.edit('User Approved!')
|
||||
|
||||
|
||||
@Client.on_message(filters.command(['d'], prefix) & filters.me)
|
||||
async def del_contact(_, message: Message):
|
||||
ids = message.chat.id
|
||||
|
||||
db.set('core.antipm', f'disallowusers{ids}', ids)
|
||||
db.remove('core.antipm', f'allowusers{ids}')
|
||||
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:
|
||||
db.set('core.antipm', 'antipm_msg', None)
|
||||
await message.edit('antipm message set to default.')
|
||||
return
|
||||
|
||||
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 <code>{user}</code> to mention the user.')
|
||||
if '{my_name}' not in afk_msg:
|
||||
return await message.edit('antipm message must contain <code>{my_name}</code> to mention your name.')
|
||||
if '{warns}' not in afk_msg:
|
||||
return await message.edit('antipm message must contain <code>{warns}</code> 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}')
|
||||
|
||||
|
||||
@Client.on_message(filters.command(['setantipmpic', 'sap'], prefix) & filters.me)
|
||||
async def set_antipm_pic(_, message: Message):
|
||||
if not message.reply_to_message or not message.reply_to_message.photo:
|
||||
db.set('core.antipm', 'antipm_pic', None)
|
||||
await message.edit('antipm picture set to default.')
|
||||
return
|
||||
|
||||
await message.edit('Setting antipm picture...')
|
||||
|
||||
photo = await message.reply_to_message.download('antipm_pic.jpg')
|
||||
|
||||
old_antipm_pic = db.get('core.antipm', 'antipm_pic', None)
|
||||
if old_antipm_pic:
|
||||
db.remove('core.antipm', 'antipm_pic')
|
||||
db.set('core.antipm', 'antipm_pic', photo)
|
||||
await message.edit('antipm picture set successfully.')
|
||||
|
||||
|
||||
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.',
|
||||
'setantipmpic [reply to photo]*': 'Set antipm picture.',
|
||||
'sap [reply to photo]*': 'Set antipm picture.',
|
||||
'a': 'Approve User',
|
||||
'd': 'DisApprove User',
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
import re
|
||||
import uuid
|
||||
|
||||
from aiohttp import ClientSession, FormData
|
||||
from pyrogram import Client, filters
|
||||
from utils.misc import modules_help, prefix
|
||||
|
||||
|
||||
def id_generator() -> str:
|
||||
return str(uuid.uuid4())
|
||||
|
||||
|
||||
@Client.on_message(filters.command(['bbox', 'blackbox'], prefix) & filters.me)
|
||||
async def blackbox(client, message):
|
||||
m = message
|
||||
msg = await m.edit_text('🔍')
|
||||
|
||||
if len(m.text.split()) == 1:
|
||||
return await msg.edit_text(
|
||||
f'Type some query buddy 🐼\n{prefix}blackbox text with reply to the photo or just text'
|
||||
)
|
||||
else:
|
||||
try:
|
||||
session = ClientSession()
|
||||
prompt = m.text.split(maxsplit=1)[1]
|
||||
user_id = id_generator()
|
||||
image = None
|
||||
|
||||
if m.reply_to_message and (
|
||||
m.reply_to_message.photo or (m.reply_to_message.sticker and not m.reply_to_message.sticker.is_video)
|
||||
):
|
||||
file_name = f'blackbox_{m.chat.id}.jpeg'
|
||||
file_path = await m.reply_to_message.download(file_name=file_name)
|
||||
with open(file_path, 'rb') as file:
|
||||
image = file.read()
|
||||
|
||||
if image:
|
||||
data = FormData()
|
||||
data.add_field('fileName', file_name)
|
||||
data.add_field('userId', user_id)
|
||||
data.add_field('image', image, filename=file_name, content_type='image/jpeg')
|
||||
api_url = 'https://www.blackbox.ai/api/upload'
|
||||
try:
|
||||
async with session.post(api_url, data=data) as response:
|
||||
response_json = await response.json()
|
||||
except Exception as e:
|
||||
return await msg.edit(f'❌ Error: {str(e)}')
|
||||
|
||||
messages = [
|
||||
{
|
||||
'role': 'user',
|
||||
'content': response_json['response'] + '\n#\n' + prompt,
|
||||
}
|
||||
]
|
||||
data = {
|
||||
'messages': messages,
|
||||
'user_id': user_id,
|
||||
'codeModelMode': True,
|
||||
'agentMode': {},
|
||||
'trendingAgentMode': {},
|
||||
}
|
||||
headers = {'Content-Type': 'application/json'}
|
||||
url = 'https://www.blackbox.ai/api/chat'
|
||||
try:
|
||||
async with session.post(url, headers=headers, json=data) as response:
|
||||
response_text = await response.text()
|
||||
except Exception as e:
|
||||
return await msg.edit(f'❌ Error: {str(e)}')
|
||||
|
||||
cleaned_response_text = re.sub(
|
||||
r'^\$?@?\$?v=undefined-rv\d+@?\$?|\$?@?\$?v=v\d+\.\d+-rv\d+@?\$?',
|
||||
'',
|
||||
response_text,
|
||||
)
|
||||
text = cleaned_response_text.strip()[2:]
|
||||
if '$~~~$' in text:
|
||||
text = re.sub(r'\$~~~\$.*?\$~~~\$', '', text, flags=re.DOTALL)
|
||||
rdata = {'reply': text}
|
||||
|
||||
return await msg.edit_text(text=rdata['reply'])
|
||||
else:
|
||||
reply = m.reply_to_message
|
||||
if reply and reply.text:
|
||||
prompt = f'Old conversation:\n{reply.text}\n\nQuestion:\n{prompt}'
|
||||
messages = [{'role': 'user', 'content': prompt}]
|
||||
data = {
|
||||
'messages': messages,
|
||||
'user_id': user_id,
|
||||
'codeModelMode': True,
|
||||
'agentMode': {},
|
||||
'trendingAgentMode': {},
|
||||
}
|
||||
headers = {'Content-Type': 'application/json'}
|
||||
url = 'https://www.blackbox.ai/api/chat'
|
||||
try:
|
||||
async with session.post(url, headers=headers, json=data) as response:
|
||||
response_text = await response.text()
|
||||
except Exception as e:
|
||||
return await msg.edit(f'❌ Error: {str(e)}')
|
||||
|
||||
cleaned_response_text = re.sub(
|
||||
r'^\$?@?\$?v=undefined-rv\d+@?\$?|\$?@?\$?v=v\d+\.\d+-rv\d+@?\$?',
|
||||
'',
|
||||
response_text,
|
||||
)
|
||||
text = cleaned_response_text.strip()[2:]
|
||||
if '$~~~$' in text:
|
||||
text = re.sub(r'\$~~~\$.*?\$~~~\$', '', text, flags=re.DOTALL)
|
||||
rdata = {'reply': text}
|
||||
|
||||
return await msg.edit_text(text=rdata['reply'])
|
||||
except Exception as e:
|
||||
return await msg.edit(f'�� Error: {str(e)}')
|
||||
finally:
|
||||
await session.close()
|
||||
|
||||
|
||||
modules_help['blackbox'] = {
|
||||
'blackbox [query]*': 'Ask anything to Blackbox',
|
||||
'bbox [query]*': 'Ask anything to Blackbox',
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
import asyncio
|
||||
|
||||
from pyrogram import Client, filters
|
||||
from pyrogram.types import Message
|
||||
from utils.misc import modules_help, prefix
|
||||
|
||||
|
||||
@Client.on_message(filters.command('calc', prefix) & filters.me)
|
||||
async def calc(_, message: Message):
|
||||
if len(message.command) <= 1:
|
||||
return
|
||||
args = ' '.join(message.command[1:])
|
||||
try:
|
||||
result = str(eval(args)) # noqa: S307
|
||||
|
||||
if len(result) > 4096:
|
||||
for i, x in enumerate(range(0, len(result), 4096)):
|
||||
if i == 0:
|
||||
await message.edit(
|
||||
f'<i>{args}</i><b>=</b><code>{result[x : x + 4000]}</code>',
|
||||
parse_mode='HTML',
|
||||
)
|
||||
else:
|
||||
await message.reply(f'<code>{result[x : x + 4096]}</code>', parse_mode='HTML')
|
||||
await asyncio.sleep(0.18)
|
||||
else:
|
||||
await message.edit(f'<i>{args}</i><b>=</b><code>{result}</code>', parse_mode='HTML')
|
||||
except Exception as e:
|
||||
await message.edit(f'<i>{args}=</i><b>=</b><code>{e}</code>', parse_mode='HTML')
|
||||
|
||||
|
||||
modules_help['calculator'] = {
|
||||
'calc [expression]*': 'solve a math problem\n'
|
||||
'+ – addition\n'
|
||||
'– – subtraction\n'
|
||||
'* – multiplication\n'
|
||||
'/ – division\n'
|
||||
'** – degree'
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
import os
|
||||
|
||||
from pyrogram import Client, filters
|
||||
from pyrogram.types import Message
|
||||
from utils.misc import modules_help, prefix
|
||||
from utils.scripts import format_exc, import_library
|
||||
|
||||
clarifai = import_library('clarifai')
|
||||
|
||||
from clarifai.client.model import Model # noqa: E402
|
||||
|
||||
|
||||
@Client.on_message(filters.command('cdxl', prefix) & filters.me)
|
||||
async def cdxl(c: Client, message: Message):
|
||||
try:
|
||||
chat_id = message.chat.id
|
||||
await message.edit_text('<code>Please Wait...</code>')
|
||||
|
||||
if len(message.command) > 1:
|
||||
prompt = message.text.split(maxsplit=1)[1]
|
||||
elif message.reply_to_message:
|
||||
prompt = message.reply_to_message.text
|
||||
else:
|
||||
await message.edit_text(f'<b>Usage: </b><code>{prefix}vdxl [prompt/reply to prompt]</code>')
|
||||
return
|
||||
|
||||
inference_params = {'width': 1024, 'height': 1024, 'steps': 50, 'cfg_scale': 9.0}
|
||||
|
||||
model_prediction = Model(
|
||||
'https://clarifai.com/stability-ai/stable-diffusion-2/models/stable-diffusion-xl'
|
||||
).predict_by_bytes(prompt.encode(), input_type='text', inference_params=inference_params)
|
||||
|
||||
output_base64 = model_prediction.outputs[0].data.image.base64
|
||||
|
||||
with open('sdxl_out.png', 'wb') as f:
|
||||
f.write(output_base64)
|
||||
|
||||
await message.delete()
|
||||
await c.send_photo(
|
||||
chat_id,
|
||||
photo='sdxl_out.png',
|
||||
caption=f'<b>Prompt:</b><code>{prompt}</code>',
|
||||
)
|
||||
os.remove('sdxl_out.png')
|
||||
|
||||
except Exception as e:
|
||||
await message.edit_text(f'An error occurred: {format_exc(e)}')
|
||||
|
||||
|
||||
modules_help['cdxl'] = {
|
||||
'cdxl [prompt/reply to prompt]*': 'Text to Image with SDXL model',
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
from pyrogram import Client, enums, filters
|
||||
from pyrogram.types import Message
|
||||
from utils.config import cohere_key
|
||||
from utils.db import db
|
||||
from utils.misc import modules_help, prefix
|
||||
from utils.scripts import format_exc, import_library, restart
|
||||
|
||||
cohere = import_library('cohere')
|
||||
|
||||
co = cohere.Client(cohere_key)
|
||||
|
||||
chatai_users = db.getaiusers()
|
||||
|
||||
|
||||
@Client.on_message(filters.command('addai', prefix) & filters.me)
|
||||
async def adduser(_, message: Message):
|
||||
if len(message.command) > 1:
|
||||
user_id = message.text.split(maxsplit=1)[1]
|
||||
if user_id.isdigit():
|
||||
user_id = int(user_id)
|
||||
db.addaiuser(user_id)
|
||||
await message.edit_text('<b>User ID Added</b>')
|
||||
restart()
|
||||
else:
|
||||
await message.edit_text('<b>User ID is invalid.</b>')
|
||||
return
|
||||
else:
|
||||
await message.edit_text(f'<b>Usage: </b><code>{prefix}addai [user_id]</code>')
|
||||
return
|
||||
|
||||
|
||||
@Client.on_message(filters.command('remai', prefix) & filters.me)
|
||||
async def remuser(_, message: Message):
|
||||
if len(message.command) > 1:
|
||||
user_id = message.text.split(maxsplit=1)[1]
|
||||
if user_id.isdigit():
|
||||
user_id = int(user_id)
|
||||
db.remaiuser(user_id)
|
||||
await message.edit_text('<b>User ID Removed</b>')
|
||||
restart()
|
||||
else:
|
||||
await message.edit_text('<b>User ID is invalid.</b>')
|
||||
return
|
||||
else:
|
||||
await message.edit_text(f'<b>Usage: </b><code>{prefix}remai [user_id]</code>')
|
||||
return
|
||||
|
||||
|
||||
@Client.on_message(filters.user(users=chatai_users) & filters.text)
|
||||
async def chatbot(_, message: Message):
|
||||
user_id = message.chat.id
|
||||
|
||||
if user_id in chatai_users:
|
||||
pass
|
||||
else:
|
||||
return
|
||||
try:
|
||||
await message.reply_chat_action(enums.ChatAction.TYPING)
|
||||
|
||||
chat_history = db.get_chat_history(user_id)
|
||||
|
||||
prompt = message.text
|
||||
|
||||
db.add_chat_history(user_id, {'role': 'USER', 'message': prompt})
|
||||
|
||||
response = co.chat(
|
||||
chat_history=chat_history,
|
||||
model='command-r-plus',
|
||||
message=prompt,
|
||||
temperature=0.3,
|
||||
connectors=[{'id': 'web-search', 'options': {'site': 'wikipedia.com'}}],
|
||||
prompt_truncation='AUTO',
|
||||
)
|
||||
|
||||
db.add_chat_history(user_id, {'role': 'CHATBOT', 'message': response.text})
|
||||
|
||||
await message.reply_text(f'{response.text}', parse_mode=enums.ParseMode.MARKDOWN)
|
||||
|
||||
except Exception as e:
|
||||
await message.reply_text(f'An error occurred: {format_exc(e)}')
|
||||
|
||||
|
||||
@Client.on_message(filters.command('chatoff', prefix) & filters.me)
|
||||
async def chatoff(_, message: Message):
|
||||
db.remove('core.chatbot', 'chatai_users')
|
||||
await message.reply_text('<b>ChatBot is off now</b>')
|
||||
restart()
|
||||
|
||||
|
||||
@Client.on_message(filters.command('listai', prefix) & filters.me)
|
||||
async def listai(_, message: Message):
|
||||
await message.edit_text(f"<b>User ID's Currently in AI ChatBot List:</b>\n <code>{chatai_users}</code>")
|
||||
|
||||
|
||||
modules_help['chatbot'] = {
|
||||
'addai [user_id]*': 'Add A user to AI ChatBot List',
|
||||
'remai [user_id]*': 'Remove A user from AI ChatBot List',
|
||||
'listai': 'List A user from AI ChatBot List',
|
||||
'chatoff': 'Turn off AI ChatBot',
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
import asyncio
|
||||
import os
|
||||
from io import BytesIO
|
||||
|
||||
from PIL import Image, ImageDraw, ImageFilter, ImageOps
|
||||
from pyrogram import Client, enums, filters
|
||||
from pyrogram.types import Message
|
||||
|
||||
# noinspection PyUnresolvedReferences
|
||||
from utils.misc import modules_help, prefix
|
||||
|
||||
# noinspection PyUnresolvedReferences
|
||||
from utils.scripts import format_exc, import_library
|
||||
|
||||
VideoFileClip = import_library('moviepy', 'moviepy==2.2.1').VideoFileClip
|
||||
|
||||
im = None
|
||||
|
||||
|
||||
def process_img(filename):
|
||||
global im
|
||||
im = Image.open(f'downloads/{filename}')
|
||||
w, h = im.size
|
||||
img = Image.new('RGBA', (w, h), (0, 0, 0, 0))
|
||||
img.paste(im, (0, 0))
|
||||
m = min(w, h)
|
||||
img = img.crop(((w - m) // 2, (h - m) // 2, (w + m) // 2, (h + m) // 2))
|
||||
w, h = img.size
|
||||
mask = Image.new('L', (w, h), 0)
|
||||
draw = ImageDraw.Draw(mask)
|
||||
draw.ellipse((10, 10, w - 10, h - 10), fill=255)
|
||||
mask = mask.filter(ImageFilter.GaussianBlur(2))
|
||||
img = ImageOps.fit(img, (w, h))
|
||||
img.putalpha(mask)
|
||||
im = BytesIO()
|
||||
im.name = 'img.webp'
|
||||
img.save(im)
|
||||
im.seek(0)
|
||||
|
||||
|
||||
video = None
|
||||
|
||||
|
||||
def process_vid(filename):
|
||||
global video
|
||||
video = VideoFileClip(f'downloads/{filename}')
|
||||
w, h = video.size
|
||||
m = min(w, h)
|
||||
box = {
|
||||
'x1': (w - m) // 2,
|
||||
'y1': (h - m) // 2,
|
||||
'x2': (w + m) // 2,
|
||||
'y2': (h + m) // 2,
|
||||
}
|
||||
video = video.cropped(**box)
|
||||
|
||||
|
||||
@Client.on_message(filters.command(['circle', 'round'], prefix) & filters.me)
|
||||
async def circle(_, message: Message):
|
||||
try:
|
||||
if not message.reply_to_message:
|
||||
return await message.reply(
|
||||
'<b>Reply is required for this command</b>',
|
||||
parse_mode=enums.ParseMode.HTML,
|
||||
)
|
||||
if message.reply_to_message.photo:
|
||||
filename = 'circle.jpg'
|
||||
typ = 'photo'
|
||||
elif message.reply_to_message.sticker:
|
||||
if message.reply_to_message.sticker.is_video:
|
||||
return await message.reply(
|
||||
'<b>Video stickers is not supported</b>',
|
||||
parse_mode=enums.ParseMode.HTML,
|
||||
)
|
||||
filename = 'circle.webp'
|
||||
typ = 'photo'
|
||||
elif message.reply_to_message.video:
|
||||
filename = 'circle.mp4'
|
||||
typ = 'video'
|
||||
elif message.reply_to_message.document:
|
||||
_filename = message.reply_to_message.document.file_name.casefold()
|
||||
if _filename.endswith('.png'):
|
||||
filename = 'circle.png'
|
||||
typ = 'photo'
|
||||
elif _filename.endswith('.jpg'):
|
||||
filename = 'circle.jpg'
|
||||
typ = 'photo'
|
||||
elif _filename.endswith('.jpeg'):
|
||||
filename = 'circle.jpeg'
|
||||
typ = 'photo'
|
||||
elif _filename.endswith('.webp'):
|
||||
filename = 'circle.webp'
|
||||
typ = 'photo'
|
||||
elif _filename.endswith('.mp4'):
|
||||
filename = 'circle.mp4'
|
||||
typ = 'video'
|
||||
else:
|
||||
return await message.reply('<b>Invalid file type</b>', parse_mode=enums.ParseMode.HTML)
|
||||
else:
|
||||
return await message.reply('<b>Invalid file type</b>', parse_mode=enums.ParseMode.HTML)
|
||||
|
||||
if typ == 'photo':
|
||||
await message.edit('<b>Processing image</b>📷', parse_mode=enums.ParseMode.HTML)
|
||||
await message.reply_to_message.download(f'downloads/{filename}')
|
||||
await asyncio.get_event_loop().run_in_executor(None, process_img, filename)
|
||||
await message.delete()
|
||||
return await message.reply_sticker(sticker=im, reply_to_message_id=message.reply_to_message.id)
|
||||
else:
|
||||
await message.edit('<b>Processing video</b>🎥', parse_mode=enums.ParseMode.HTML)
|
||||
await message.reply_to_message.download(f'downloads/{filename}')
|
||||
await asyncio.get_event_loop().run_in_executor(None, process_vid, filename)
|
||||
|
||||
await message.edit('<b>Saving video</b>📼', parse_mode=enums.ParseMode.HTML)
|
||||
await asyncio.get_event_loop().run_in_executor(None, video.write_videofile, 'downloads/result.mp4')
|
||||
|
||||
await message.delete()
|
||||
await message.reply_video_note(
|
||||
video_note='downloads/result.mp4',
|
||||
duration=int(video.duration),
|
||||
reply_to_message_id=message.reply_to_message.id,
|
||||
)
|
||||
if isinstance(video, VideoFileClip):
|
||||
video.close()
|
||||
os.remove(f'downloads/{filename}')
|
||||
os.remove('downloads/result.mp4')
|
||||
except Exception as e:
|
||||
await message.reply(format_exc(e), parse_mode=enums.ParseMode.HTML)
|
||||
|
||||
|
||||
modules_help['circle'] = {
|
||||
'round': 'Round a photo or video.',
|
||||
'circle': 'Circle a photo or video.',
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
# Moon-Userbot - telegram userbot
|
||||
# Copyright (C) 2020-present Moon Userbot Organization
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
from pyrogram import Client, filters
|
||||
from pyrogram.raw import functions
|
||||
from pyrogram.types import Message
|
||||
from utils.misc import modules_help, prefix
|
||||
|
||||
|
||||
@Client.on_message(filters.command(['clear_@'], prefix) & filters.me)
|
||||
async def solo_mention_clear(client: Client, message: Message):
|
||||
await message.delete()
|
||||
peer = await client.resolve_peer(message.chat.id)
|
||||
request = functions.messages.ReadMentions(peer=peer)
|
||||
await client.invoke(request)
|
||||
|
||||
|
||||
@Client.on_message(filters.command(['clear_all_@'], prefix) & filters.me)
|
||||
async def global_mention_clear(client: Client, message: Message):
|
||||
counter: int = 0
|
||||
await message.edit_text(f'<b>Clearing all mentions...</b>\n\n<b>Cleared:</b> <code>{counter}</code> chats')
|
||||
async for dialog in client.get_dialogs():
|
||||
peer = await client.resolve_peer(dialog.chat.id)
|
||||
request = functions.messages.ReadMentions(peer=peer)
|
||||
await client.invoke(request)
|
||||
counter += 1
|
||||
await message.edit_text(f'<b>Clearing all mentions...</b>\n\n<b>Cleared:</b> <code>{counter}</code> chats')
|
||||
await message.delete()
|
||||
|
||||
|
||||
@Client.on_message(filters.command(['clear_reacts'], prefix) & filters.me)
|
||||
async def solo_reaction_clear(client: Client, message: Message):
|
||||
await message.delete()
|
||||
peer = await client.resolve_peer(message.chat.id)
|
||||
request = functions.messages.ReadReactions(peer=peer)
|
||||
await client.invoke(request)
|
||||
|
||||
|
||||
@Client.on_message(filters.command(['clear_all_reacts'], prefix) & filters.me)
|
||||
async def global_reaction_clear(client: Client, message: Message):
|
||||
counter: int = 0
|
||||
await message.edit_text(f'<b>Clearing all reactions...</b>\n\n<b>Cleared:</b> <code>{counter}</code> chats')
|
||||
async for dialog in client.get_dialogs():
|
||||
peer = await client.resolve_peer(dialog.chat.id)
|
||||
request = functions.messages.ReadReactions(peer=peer)
|
||||
await client.invoke(request)
|
||||
counter += 1
|
||||
await message.edit_text(f'<b>Clearing all reactions...</b>\n\n<b>Cleared:</b> <code>{counter}</code> chats')
|
||||
await message.delete()
|
||||
|
||||
|
||||
modules_help['clear_notifs'] = {
|
||||
'clear_@': 'clear all mentions in this chat',
|
||||
'clear_all_@': 'clear all mentions in all chats',
|
||||
'clear_reacts': 'clear all reactions in this chat',
|
||||
'clear_all_reacts': 'clear all reactions in all chats (except private chats)',
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
import asyncio
|
||||
|
||||
from utils.config import cohere_key
|
||||
from utils.scripts import import_library
|
||||
|
||||
cohere = import_library('cohere')
|
||||
|
||||
import cohere # noqa: F811
|
||||
|
||||
co = cohere.Client(cohere_key)
|
||||
|
||||
from pyrogram import Client, enums, filters # noqa: E402
|
||||
from pyrogram.errors import MessageTooLong # noqa: E402
|
||||
from pyrogram.types import Message # noqa: E402
|
||||
from utils.db import db # noqa: E402
|
||||
from utils.misc import modules_help, prefix # noqa: E402
|
||||
from utils.rentry import paste as rentry_paste # noqa: E402
|
||||
from utils.scripts import format_exc # noqa: E402
|
||||
|
||||
|
||||
@Client.on_message(filters.command('cohere', prefix) & filters.me)
|
||||
async def cohere(c: Client, message: Message):
|
||||
try:
|
||||
user_id = message.from_user.id
|
||||
chat_history = db.get_chat_history(user_id)
|
||||
|
||||
if len(message.command) > 1:
|
||||
prompt = message.text.split(maxsplit=1)[1]
|
||||
elif message.reply_to_message:
|
||||
prompt = message.reply_to_message.text
|
||||
else:
|
||||
await message.edit_text(f'<b>Usage: </b><code>{prefix}cohere [prompt/reply to message]</code>')
|
||||
return
|
||||
|
||||
db.add_chat_history(user_id, {'role': 'USER', 'message': prompt})
|
||||
|
||||
await message.edit_text('<code>Umm, lemme think...</code>')
|
||||
|
||||
response = co.chat_stream(
|
||||
chat_history=chat_history,
|
||||
model='command-r-plus',
|
||||
message=prompt,
|
||||
temperature=0.8,
|
||||
tools=[{'name': 'internet_search'}],
|
||||
connectors=[],
|
||||
prompt_truncation='OFF',
|
||||
)
|
||||
output = ''
|
||||
tool_message = ''
|
||||
data = []
|
||||
for event in response:
|
||||
if event.event_type == 'tool-calls-chunk':
|
||||
if event.tool_call_delta and event.tool_call_delta.text is None:
|
||||
tool_message += ''
|
||||
else:
|
||||
tool_message += event.text
|
||||
if event.event_type == 'search-results':
|
||||
data.append(event.documents)
|
||||
if event.event_type == 'text-generation':
|
||||
output += event.text
|
||||
if output == '':
|
||||
output = "I can't seem to find an answer to that"
|
||||
|
||||
db.add_chat_history(user_id, {'role': 'CHATBOT', 'message': output})
|
||||
|
||||
await message.edit_text(f'<code>{tool_message}</code>')
|
||||
|
||||
await asyncio.sleep(5)
|
||||
|
||||
try:
|
||||
data = data[0]
|
||||
references = ''
|
||||
reference_dict = {}
|
||||
for item in data:
|
||||
title = item['title']
|
||||
url = item['url']
|
||||
if title not in reference_dict:
|
||||
reference_dict[title] = url
|
||||
|
||||
i = 1
|
||||
for title, url in reference_dict.items():
|
||||
references += f'**{i}.** [{title}]({url})\n'
|
||||
i += 1
|
||||
|
||||
await message.edit_text(
|
||||
f'**Question:**`{prompt}`\n**Answer:** {output}\n\n**References:**\n{references}',
|
||||
parse_mode=enums.ParseMode.MARKDOWN,
|
||||
disable_web_page_preview=True,
|
||||
)
|
||||
|
||||
except IndexError:
|
||||
references = ''
|
||||
await message.edit_text(
|
||||
f'**Question:**`{prompt}`\n**Answer:** {output}\n',
|
||||
parse_mode=enums.ParseMode.MARKDOWN,
|
||||
disable_web_page_preview=True,
|
||||
)
|
||||
except MessageTooLong:
|
||||
await message.edit_text('<code>Output is too long... Pasting to rentry...</code>')
|
||||
try:
|
||||
output = output + '\n\n' + references if references else output
|
||||
rentry_url, edit_code = await rentry_paste(text=output, return_edit=True)
|
||||
except RuntimeError:
|
||||
await message.edit_text('<b>Error:</b> <code>Failed to paste to rentry</code>')
|
||||
return
|
||||
await c.send_message(
|
||||
'me',
|
||||
f"Here's your edit code for Url: {rentry_url}\nEdit code: <code>{edit_code}</code>",
|
||||
disable_web_page_preview=True,
|
||||
)
|
||||
await message.edit_text(
|
||||
f'<b>Output:</b> {rentry_url}\n<b>Note:</b> <code>Edit Code has been sent to your saved messages</code>',
|
||||
disable_web_page_preview=True,
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
await message.edit_text(f'An error occurred: {format_exc(e)}')
|
||||
|
||||
|
||||
modules_help['cohere'] = {
|
||||
'cohere': 'Chat with cohere ai' + '\nSupports Chat History\n' + 'Supports real time internet search'
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
import random
|
||||
from io import BytesIO
|
||||
|
||||
from pyrogram import Client, enums, filters
|
||||
from pyrogram.types import Message
|
||||
from utils.misc import modules_help, prefix
|
||||
from utils.scripts import import_library
|
||||
|
||||
requests = import_library('requests')
|
||||
PIL = import_library('PIL', 'pillow')
|
||||
|
||||
from PIL import Image, ImageDraw, ImageFont # noqa: E402
|
||||
|
||||
|
||||
@Client.on_message(filters.command(['dem'], prefix) & filters.me)
|
||||
async def demotivator(client: Client, message: Message):
|
||||
await message.edit('<code>Process of demotivation...</code>', parse_mode=enums.ParseMode.HTML)
|
||||
font = requests.get('https://github.com/The-MoonTg-project/files/blob/main/Times%20New%20Roman.ttf?raw=true', timeout=10)
|
||||
f = font.content
|
||||
template_dem = requests.get('https://raw.githubusercontent.com/files/main/demotivator.png', timeout=10)
|
||||
if message.reply_to_message:
|
||||
words = ['random', 'text', 'typing', 'fuck']
|
||||
if message.reply_to_message.photo:
|
||||
donwloads = await client.download_media(message.reply_to_message.photo.file_id)
|
||||
photo = Image.open(f'{donwloads}')
|
||||
resize_photo = photo.resize((469, 312))
|
||||
text = message.text.split(' ', maxsplit=1)[1] if len(message.text.split()) > 1 else random.choice(words) # noqa: S311
|
||||
im = Image.open(BytesIO(template_dem.content))
|
||||
im.paste(resize_photo, (65, 48))
|
||||
text_font = ImageFont.truetype(BytesIO(f), 22)
|
||||
text_draw = ImageDraw.Draw(im)
|
||||
text_draw.multiline_text((299, 412), text, font=text_font, fill=(255, 255, 255), anchor='ms')
|
||||
im.save(f'downloads/{message.id}.png')
|
||||
await message.reply_to_message.reply_photo(f'downloads/{message.id}.png')
|
||||
await message.delete()
|
||||
elif message.reply_to_message.sticker:
|
||||
if not message.reply_to_message.sticker.is_animated:
|
||||
donwloads = await client.download_media(message.reply_to_message.sticker.file_id)
|
||||
photo = Image.open(f'{donwloads}')
|
||||
resize_photo = photo.resize((469, 312))
|
||||
text = message.text.split(' ', maxsplit=1)[1] if len(message.text.split()) > 1 else random.choice(words) # noqa: S311
|
||||
im = Image.open(BytesIO(template_dem.content))
|
||||
im.paste(resize_photo, (65, 48))
|
||||
text_font = ImageFont.truetype(BytesIO(f), 22)
|
||||
text_draw = ImageDraw.Draw(im)
|
||||
text_draw.multiline_text((299, 412), text, font=text_font, fill=(255, 255, 255), anchor='ms')
|
||||
im.save(f'downloads/{message.id}.png')
|
||||
await message.reply_to_message.reply_photo(f'downloads/{message.id}.png')
|
||||
await message.delete()
|
||||
else:
|
||||
await message.edit(
|
||||
'<b>Animated stickers are not supported</b>',
|
||||
parse_mode=enums.ParseMode.HTML,
|
||||
)
|
||||
else:
|
||||
await message.edit(
|
||||
'<b>Need to answer the photo/sticker</b>',
|
||||
parse_mode=enums.ParseMode.HTML,
|
||||
)
|
||||
else:
|
||||
await message.edit('<b>Need to answer the photo/sticker</b>', parse_mode=enums.ParseMode.HTML)
|
||||
|
||||
|
||||
modules_help['demotivator'] = {'dem [text]*': 'Reply to the picture to make a demotivator out of it'}
|
||||
@@ -0,0 +1,78 @@
|
||||
import os
|
||||
|
||||
from pyrogram import Client, enums, filters
|
||||
from pyrogram.types import Message
|
||||
from utils.misc import modules_help, prefix
|
||||
from utils.scripts import import_library
|
||||
|
||||
lottie = import_library('lottie')
|
||||
from lottie.exporters import exporters # noqa: E402
|
||||
from lottie.importers import importers # noqa: E402
|
||||
|
||||
|
||||
@Client.on_message(filters.command('destroy', prefix) & filters.me)
|
||||
async def destroy_sticker(client: Client, message: Message):
|
||||
"""Destroy animated stickers by modifying their animation properties"""
|
||||
try:
|
||||
reply = message.reply_to_message
|
||||
if not reply or not reply.sticker or not reply.sticker.is_animated:
|
||||
return await message.edit(
|
||||
'**Please reply to an animated sticker!**',
|
||||
parse_mode=enums.ParseMode.MARKDOWN,
|
||||
)
|
||||
|
||||
edit_msg = await message.edit('**🔄 Destroying sticker...**', parse_mode=enums.ParseMode.MARKDOWN)
|
||||
|
||||
# Download sticker
|
||||
tgs_path = await reply.download()
|
||||
if not tgs_path or not os.path.exists(tgs_path):
|
||||
return await edit_msg.edit('**❌ Download failed!**', parse_mode=enums.ParseMode.MARKDOWN)
|
||||
|
||||
# Conversion process
|
||||
json_path = 'temp.json'
|
||||
output_path = 'MoonUB.tgs'
|
||||
|
||||
importer = importers.get_from_filename(tgs_path)
|
||||
if not importer:
|
||||
return await edit_msg.edit('**❌ JSON conversion failed!**', parse_mode=enums.ParseMode.MARKDOWN)
|
||||
|
||||
animation = importer.process(tgs_path)
|
||||
exporter = exporters.get_from_filename(json_path)
|
||||
exporter.process(animation, json_path)
|
||||
|
||||
# Modify JSON data
|
||||
with open(json_path, 'r+') as f:
|
||||
content = f.read()
|
||||
modified = (
|
||||
content.replace('[1]', '[2]')
|
||||
.replace('[2]', '[3]')
|
||||
.replace('[3]', '[4]')
|
||||
.replace('[4]', '[5]')
|
||||
.replace('[5]', '[6]')
|
||||
)
|
||||
f.seek(0)
|
||||
f.write(modified)
|
||||
f.truncate()
|
||||
|
||||
importer = importers.get_from_filename(json_path)
|
||||
animation = importer.process(json_path)
|
||||
exporter = exporters.get_from_filename(output_path)
|
||||
exporter.process(animation, output_path)
|
||||
|
||||
# Send result
|
||||
await message.reply_document(output_path, reply_to_message_id=reply.id)
|
||||
await edit_msg.delete()
|
||||
|
||||
except Exception as e:
|
||||
await message.edit(f'**❌ Error:** `{e}`', parse_mode=enums.ParseMode.MARKDOWN)
|
||||
finally:
|
||||
# Cleanup temporary files
|
||||
for file_path in [tgs_path, json_path, output_path]:
|
||||
if file_path and os.path.exists(file_path):
|
||||
try:
|
||||
os.remove(file_path)
|
||||
except Exception as clean_error:
|
||||
print(f'Cleanup error: {clean_error}')
|
||||
|
||||
|
||||
modules_help['destroy'] = {'destroy [reply]': 'Modify and destroy animated stickers'}
|
||||
@@ -0,0 +1,26 @@
|
||||
import asyncio
|
||||
|
||||
from pyrogram import Client, enums, filters
|
||||
from pyrogram.types import Message
|
||||
from utils.misc import modules_help, prefix
|
||||
from utils.scripts import format_exc
|
||||
|
||||
|
||||
@Client.on_message(filters.command('dice', prefix) & filters.me)
|
||||
async def dice_text(client: Client, message: Message):
|
||||
try:
|
||||
value = int(message.command[1])
|
||||
if value not in range(1, 7):
|
||||
raise AssertionError
|
||||
except (ValueError, IndexError, AssertionError):
|
||||
return await message.edit('<b>Invalid value</b>', parse_mode=enums.ParseMode.HTML)
|
||||
|
||||
try:
|
||||
message.dice = type('bruh', (), {'value': 0})()
|
||||
while message.dice.value != value:
|
||||
message = (await asyncio.gather(message.delete(), client.send_dice(message.chat.id)))[1]
|
||||
except Exception as e:
|
||||
await message.edit(format_exc(e), parse_mode=enums.ParseMode.HTML)
|
||||
|
||||
|
||||
modules_help['dice'] = {'dice [1-6]*': 'Generate dice with specified value. Works only in groups'}
|
||||
@@ -0,0 +1,304 @@
|
||||
# Copyright (C) 2019 The Raphielscape Company LLC.
|
||||
#
|
||||
# Licensed under the Raphielscape Public License, Version 1.d (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
#
|
||||
"""Userbot module containing various sites direct links generators"""
|
||||
|
||||
import json
|
||||
import re
|
||||
import urllib.parse
|
||||
from random import choice
|
||||
from subprocess import PIPE, Popen
|
||||
|
||||
import requests
|
||||
from bs4 import BeautifulSoup
|
||||
from humanize import naturalsize
|
||||
from pyrogram import Client, enums, filters
|
||||
from pyrogram.types import Message
|
||||
from utils.misc import modules_help, prefix
|
||||
|
||||
|
||||
def subprocess_run(cmd):
|
||||
reply = ''
|
||||
cmd_args = cmd.split()
|
||||
subproc = Popen( # noqa: S603
|
||||
cmd_args,
|
||||
stdout=PIPE,
|
||||
stderr=PIPE,
|
||||
universal_newlines=True,
|
||||
executable='bash',
|
||||
)
|
||||
talk = subproc.communicate()
|
||||
exitCode = subproc.returncode
|
||||
if exitCode != 0:
|
||||
reply += (
|
||||
'```An error was detected while running the subprocess:\n'
|
||||
f'exit code: {exitCode}\n'
|
||||
f'stdout: {talk[0]}\n'
|
||||
f'stderr: {talk[1]}```'
|
||||
)
|
||||
return reply
|
||||
return talk
|
||||
|
||||
|
||||
@Client.on_message(filters.command('direct', prefix) & filters.me)
|
||||
async def direct_link_generator(_, m: Message):
|
||||
if len(m.command) > 1:
|
||||
message = m.text.split(maxsplit=1)[1]
|
||||
elif m.reply_to_message:
|
||||
message = m.reply_to_message.text
|
||||
else:
|
||||
await m.edit(f'<b>Usage: </b><code>{prefix}direct [url]</code>')
|
||||
return
|
||||
reply = ''
|
||||
links = re.findall(r'\bhttps?://.*\.\S+', message)
|
||||
if not links:
|
||||
reply = '`No links found!`'
|
||||
await m.edit(reply, parse_mode=enums.ParseMode.MARKDOWN)
|
||||
for link in links:
|
||||
if 'drive.google.com' in link:
|
||||
reply += gdrive(link)
|
||||
elif 'yadi.sk' in link:
|
||||
reply += yandex_disk(link)
|
||||
elif 'cloud.mail.ru' in link:
|
||||
reply += cm_ru(link)
|
||||
elif 'mediafire.com' in link:
|
||||
reply += mediafire(link)
|
||||
elif 'sourceforge.net' in link:
|
||||
reply += sourceforge(link)
|
||||
elif 'osdn.net' in link:
|
||||
reply += osdn(link)
|
||||
elif 'androidfilehost.com' in link:
|
||||
reply += androidfilehost(link)
|
||||
else:
|
||||
reply += re.findall(r'\bhttps?://(.*?[^/]+)', link)[0] + ' is not supported'
|
||||
await m.edit(reply, parse_mode=enums.ParseMode.MARKDOWN)
|
||||
|
||||
|
||||
def gdrive(url: str) -> str:
|
||||
"""GDrive direct links generator"""
|
||||
drive = 'https://drive.google.com'
|
||||
try:
|
||||
link = re.findall(r'\bhttps?://drive\.google\.com\S+', url)[0]
|
||||
except IndexError:
|
||||
reply = '`No Google drive links found`\n'
|
||||
return reply
|
||||
file_id = ''
|
||||
reply = ''
|
||||
if link.find('view') != -1:
|
||||
file_id = link.split('/')[-2]
|
||||
elif link.find('open?id=') != -1:
|
||||
file_id = link.split('open?id=')[1].strip()
|
||||
elif link.find('uc?id=') != -1:
|
||||
file_id = link.split('uc?id=')[1].strip()
|
||||
url = f'{drive}/uc?export=download&id={file_id}'
|
||||
download = requests.get(url, stream=True, allow_redirects=False, timeout=10)
|
||||
cookies = download.cookies
|
||||
try:
|
||||
# In case of small file size, Google downloads directly
|
||||
dl_url = download.headers['location']
|
||||
page = BeautifulSoup(download.content, 'html.parser')
|
||||
if 'accounts.google.com' in dl_url: # non-public file
|
||||
reply += '`Link is not public!`\n'
|
||||
return reply
|
||||
name = 'Direct Download Link'
|
||||
except KeyError:
|
||||
# In case of download warning page
|
||||
page = BeautifulSoup(download.content, 'html.parser')
|
||||
if download.headers is not None:
|
||||
dl_url = download.headers.get('location')
|
||||
page_element = page.find('a', {'id': 'uc-download-link'})
|
||||
if page_element is not None:
|
||||
export = drive + page_element.get('href')
|
||||
name = page.find('span', {'class': 'uc-name-size'}).text
|
||||
response = requests.get(export, stream=True, allow_redirects=False, cookies=cookies, timeout=10)
|
||||
dl_url = response.headers['location']
|
||||
if 'accounts.google.com' in dl_url:
|
||||
name = page.find('span', {'class': 'uc-name-size'}).text
|
||||
reply += 'Link is not public!'
|
||||
return reply
|
||||
if '=sharing' in dl_url:
|
||||
name = page.find('span', {'class': 'uc-name-size'}).text
|
||||
reply += '```Provide GDrive Link not directc sharing of GDrive!```'
|
||||
return reply
|
||||
|
||||
reply += f'[{name}]({dl_url})\n'
|
||||
return reply
|
||||
|
||||
|
||||
def yandex_disk(url: str) -> str:
|
||||
"""Yandex.Disk direct links generator
|
||||
Based on https://github.com/wldhx/yadisk-direct"""
|
||||
reply = ''
|
||||
try:
|
||||
link = re.findall(r'\bhttps?://.*yadi\.sk\S+', url)[0]
|
||||
except IndexError:
|
||||
reply = '`No Yandex.Disk links found`\n'
|
||||
return reply
|
||||
api = 'https://cloud-api.yandex.net/v1/disk/public/resources/download?public_key={}'
|
||||
try:
|
||||
dl_url = requests.get(api.format(link), timeout=10).json()['href']
|
||||
name = dl_url.split('filename=')[1].split('&disposition')[0]
|
||||
reply += f'[{name}]({dl_url})\n'
|
||||
except KeyError:
|
||||
reply += '`Error: File not found / Download limit reached`\n'
|
||||
return reply
|
||||
return reply
|
||||
|
||||
|
||||
def cm_ru(url: str) -> str:
|
||||
"""cloud.mail.ru direct links generator
|
||||
Using https://github.com/JrMasterModelBuilder/cmrudl.py"""
|
||||
reply = ''
|
||||
try:
|
||||
link = re.findall(r'\bhttps?://.*cloud\.mail\.ru\S+', url)[0]
|
||||
except IndexError:
|
||||
reply = '`No cloud.mail.ru links found`\n'
|
||||
return reply
|
||||
cmd = f'bin/cmrudl -s {link}'
|
||||
result = subprocess_run(cmd)
|
||||
try:
|
||||
result = result[0].splitlines()[-1]
|
||||
data = json.loads(result)
|
||||
except json.decoder.JSONDecodeError:
|
||||
reply += "`Error: Can't extract the link`\n"
|
||||
return reply
|
||||
except IndexError:
|
||||
return reply
|
||||
dl_url = data['download']
|
||||
name = data['file_name']
|
||||
size = naturalsize(int(data['file_size']))
|
||||
reply += f'[{name} ({size})]({dl_url})\n'
|
||||
return reply
|
||||
|
||||
|
||||
def mediafire(url: str) -> str:
|
||||
"""MediaFire direct links generator"""
|
||||
try:
|
||||
link = re.findall(r'\bhttps?://.*mediafire\.com\S+', url)[0]
|
||||
except IndexError:
|
||||
reply = '`No MediaFire links found`\n'
|
||||
return reply
|
||||
reply = ''
|
||||
page = BeautifulSoup(requests.get(link, timeout=10).content, 'lxml')
|
||||
info = page.find('a', {'aria-label': 'Download file'})
|
||||
dl_url = info.get('href')
|
||||
size = re.findall(r'\(.*\)', info.text)[0]
|
||||
name = page.find('div', {'class': 'filename'}).text
|
||||
reply += f'[{name} {size}]({dl_url})\n'
|
||||
return reply
|
||||
|
||||
|
||||
def sourceforge(url: str) -> str:
|
||||
"""SourceForge direct links generator"""
|
||||
try:
|
||||
link = re.findall(r'\bhttps?://.*sourceforge\.net\S+', url)[0]
|
||||
except IndexError:
|
||||
reply = '`No SourceForge links found`\n'
|
||||
return reply
|
||||
file_path = re.findall(r'files(.*)/download', link)[0]
|
||||
reply = f'Mirrors for __{file_path.split("/")[-1]}__\n'
|
||||
project = re.findall(r'projects?/(.*?)/files', link)[0]
|
||||
mirrors = f'https://sourceforge.net/settings/mirror_choices?projectname={project}&filename={file_path}'
|
||||
page = BeautifulSoup(requests.get(mirrors, timeout=10).content, 'html.parser')
|
||||
info = page.find('ul', {'id': 'mirrorList'}).findAll('li')
|
||||
for mirror in info[1:]:
|
||||
name = re.findall(r'\((.*)\)', mirror.text.strip())[0]
|
||||
dl_url = f'https://{mirror["id"]}.dl.sourceforge.net/project/{project}/{file_path}'
|
||||
reply += f'[{name}]({dl_url}) '
|
||||
return reply
|
||||
|
||||
|
||||
def osdn(url: str) -> str:
|
||||
"""OSDN direct links generator"""
|
||||
osdn_link = 'https://osdn.net'
|
||||
try:
|
||||
link = re.findall(r'\bhttps?://.*osdn\.net\S+', url)[0]
|
||||
except IndexError:
|
||||
reply = '`No OSDN links found`\n'
|
||||
return reply
|
||||
page = BeautifulSoup(requests.get(link, allow_redirects=True, timeout=10).content, 'lxml')
|
||||
info = page.find('a', {'class': 'mirror_link'})
|
||||
link = urllib.parse.unquote(osdn_link + info['href'])
|
||||
reply = f'Mirrors for __{link.split("/")[-1]}__\n'
|
||||
mirrors = page.find('form', {'id': 'mirror-select-form'}).findAll('tr')
|
||||
for data in mirrors[1:]:
|
||||
mirror = data.find('input')['value']
|
||||
name = re.findall(r'\((.*)\)', data.findAll('td')[-1].text.strip())[0]
|
||||
dl_url = re.sub(r'm=(.*)&f', f'm={mirror}&f', link)
|
||||
reply += f'[{name}]({dl_url}) '
|
||||
return reply
|
||||
|
||||
|
||||
def androidfilehost(url: str) -> str:
|
||||
"""AFH direct links generator"""
|
||||
try:
|
||||
link = re.findall(r'\bhttps?://.*androidfilehost.*fid.*\S+', url)[0]
|
||||
except IndexError:
|
||||
reply = '`No AFH links found`\n'
|
||||
return reply
|
||||
fid = re.findall(r'\?fid=(.*)', link)[0]
|
||||
session = requests.Session()
|
||||
user_agent = useragent()
|
||||
headers = {'user-agent': user_agent}
|
||||
res = session.get(link, headers=headers, allow_redirects=True)
|
||||
headers = {
|
||||
'origin': 'https://androidfilehost.com',
|
||||
'accept-encoding': 'gzip, deflate, br',
|
||||
'accept-language': 'en-US,en;q=0.9',
|
||||
'user-agent': user_agent,
|
||||
'content-type': 'application/x-www-form-urlencoded; charset=UTF-8',
|
||||
'x-mod-sbb-ctype': 'xhr',
|
||||
'accept': '*/*',
|
||||
'referer': f'https://androidfilehost.com/?fid={fid}',
|
||||
'authority': 'androidfilehost.com',
|
||||
'x-requested-with': 'XMLHttpRequest',
|
||||
}
|
||||
data = {'submit': 'submit', 'action': 'getdownloadmirrors', 'fid': f'{fid}'}
|
||||
mirrors = None
|
||||
reply = ''
|
||||
error = "`Error: Can't find Mirrors for the link`\n"
|
||||
try:
|
||||
req = session.post(
|
||||
'https://androidfilehost.com/libs/otf/mirrors.otf.php',
|
||||
headers=headers,
|
||||
data=data,
|
||||
cookies=res.cookies,
|
||||
)
|
||||
mirrors = req.json()['MIRRORS']
|
||||
except (json.decoder.JSONDecodeError, TypeError):
|
||||
reply += error
|
||||
if not mirrors:
|
||||
reply += error
|
||||
return reply
|
||||
for item in mirrors:
|
||||
name = item['name']
|
||||
dl_url = item['url']
|
||||
reply += f'[{name}]({dl_url}) '
|
||||
return reply
|
||||
|
||||
|
||||
def useragent():
|
||||
"""
|
||||
useragent random setter
|
||||
"""
|
||||
useragents = BeautifulSoup(
|
||||
requests.get(
|
||||
'https://developers.whatismybrowser.com/useragents/explore/operating_system_name/android/',
|
||||
timeout=10,
|
||||
).content,
|
||||
'lxml',
|
||||
).findAll('td', {'class': 'useragent'})
|
||||
if not useragents:
|
||||
return 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3'
|
||||
user_agent = choice(useragents) # noqa: S311
|
||||
return user_agent.text
|
||||
|
||||
|
||||
modules_help['direct'] = {
|
||||
'direct': 'Url/reply to Url\
|
||||
\n\n<b>Syntax : </b><code>.direct [url/reply] </code>\
|
||||
\n<b>Usage :</b> Generates direct download link from supported URL(s)\
|
||||
\n\n<b>Supported websites : </b><code>Google Drive - MEGA.nz - Cloud Mail - Yandex.Disk - AFH - MediaFire - SourceForge - OSDN</code>'
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
from pyrogram import Client, filters
|
||||
from pyrogram.types import Message
|
||||
from utils.misc import prefix
|
||||
|
||||
|
||||
@Client.on_message(filters.command('duck', prefix) & filters.me)
|
||||
async def duckgo(client: Client, message: Message):
|
||||
input_str = ' '.join(message.command[1:])
|
||||
sample_url = 'https://duckduckgo.com/?q={}'.format(input_str.replace(' ', '+'))
|
||||
if sample_url:
|
||||
link = sample_url.rstrip()
|
||||
await message.edit_text(f'Let me 🦆 DuckDuckGo that for you:\n🔎 [{input_str}]({link})')
|
||||
else:
|
||||
await message.edit_text('something is wrong. please try again later.')
|
||||
@@ -0,0 +1,16 @@
|
||||
from random import randint
|
||||
|
||||
from pyrogram import Client, enums, filters
|
||||
from pyrogram.types import Message
|
||||
from utils.misc import modules_help, prefix
|
||||
|
||||
|
||||
@Client.on_message(filters.command('durov', prefix) & filters.me)
|
||||
async def durov(_, message: Message):
|
||||
await message.edit(
|
||||
f'<b>Random post from channel: https://t.me/durov/{randint(21, 36500)}</b>', # noqa: S311
|
||||
parse_mode=enums.ParseMode.HTML,
|
||||
)
|
||||
|
||||
|
||||
modules_help['durov'] = {'durov': 'Send random post from durov channel'}
|
||||
@@ -0,0 +1,57 @@
|
||||
# Moon-Userbot - telegram userbot
|
||||
# Copyright (C) 2020-present Moon Userbot Organization
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
from pyrogram import Client, enums, filters
|
||||
from pyrogram.types import Message
|
||||
from utils.misc import modules_help, prefix
|
||||
|
||||
# if your module has packages from PyPi
|
||||
|
||||
# from utils.scripts import import_library
|
||||
# example_1 = import_library("example_1")
|
||||
# example_2 = import_library("example_2")
|
||||
|
||||
# import_library() will automatically install required library
|
||||
# if it isn't installed
|
||||
|
||||
|
||||
@Client.on_message(filters.command('example_edit', prefix) & filters.me)
|
||||
async def example_edit(client: Client, message: Message):
|
||||
try:
|
||||
await message.edit('<code>This is an example module</code>')
|
||||
except Exception as e:
|
||||
await message.edit(f'<code>[{e.error_code}: {enums.MessageType.TEXT}] - {e.error_details}</code>')
|
||||
|
||||
|
||||
@Client.on_message(filters.command('example_send', prefix) & filters.me)
|
||||
async def example_send(client: Client, message: Message):
|
||||
try:
|
||||
await client.send_message(message.chat.id, '<b>This is an example module</b>')
|
||||
except Exception as e:
|
||||
await message.edit(f'<code>[{e.error_code}: {enums.MessageType.TEXT}] - {e.error_details}</code>')
|
||||
|
||||
|
||||
# This adds instructions for your module
|
||||
modules_help['example'] = {
|
||||
'example_send': 'example send',
|
||||
'example_edit': 'example edit',
|
||||
}
|
||||
|
||||
# modules_help["example"] = { "example_send [text]": "example send" }
|
||||
# | | | |
|
||||
# | | | └─ command description
|
||||
# module_name command_name └─ optional command arguments
|
||||
# (only snake_case) (only snake_case too)
|
||||
@@ -0,0 +1,52 @@
|
||||
import os
|
||||
from random import randint
|
||||
|
||||
import aiohttp
|
||||
from pyrogram import Client, filters
|
||||
from pyrogram.types import Message
|
||||
from utils.misc import modules_help, prefix
|
||||
|
||||
|
||||
async def download_sticker(url, filename):
|
||||
headers = {
|
||||
'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7',
|
||||
'accept-language': 'en-US,en;q=0.9;q=0.8',
|
||||
'cache-control': 'no-cache',
|
||||
'dnt': '1',
|
||||
'pragma': 'no-cache',
|
||||
'priority': 'u=0, i',
|
||||
'sec-ch-ua': '"Not)A;Brand";v="8", "Chromium";v="138", "Microsoft Edge";v="138"',
|
||||
'sec-ch-ua-mobile': '?0',
|
||||
'sec-ch-ua-platform': '"Windows"',
|
||||
'sec-fetch-dest': 'document',
|
||||
'sec-fetch-mode': 'navigate',
|
||||
'sec-fetch-site': 'none',
|
||||
'sec-fetch-user': '?1',
|
||||
'upgrade-insecure-requests': '1',
|
||||
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36 Edg/138.0.0.0',
|
||||
}
|
||||
cookies = {'country': 'US', 'lang': 'en'}
|
||||
|
||||
async with aiohttp.ClientSession() as session, session.get(url, headers=headers, cookies=cookies) as response:
|
||||
if response.status == 200:
|
||||
with open(filename, 'wb') as f:
|
||||
f.write(await response.read())
|
||||
|
||||
|
||||
@Client.on_message(filters.command(['f'], prefix) & filters.me)
|
||||
async def random_stiker(client: Client, message: Message):
|
||||
await message.delete()
|
||||
random = randint(1, 63) # noqa: S311
|
||||
index = f'00{random}' if random < 10 else f'0{random}'
|
||||
sticker = f'https://www.chpic.su/_data/stickers/f/FforRespect/FforRespect_{index}.webp'
|
||||
await download_sticker(sticker, 'f.webp')
|
||||
if os.path.exists('f.webp'):
|
||||
await client.send_document(
|
||||
message.chat.id,
|
||||
'f.webp',
|
||||
reply_to_message_id=message.reply_to_message.id if message.reply_to_message else None,
|
||||
)
|
||||
os.remove('f.webp')
|
||||
|
||||
|
||||
modules_help['f'] = {'f': 'Send f to pay respect'}
|
||||
@@ -0,0 +1,80 @@
|
||||
from asyncio import sleep
|
||||
|
||||
from pyrogram import Client, enums, filters
|
||||
from pyrogram.raw import functions
|
||||
from pyrogram.types import InputReplyToMessage, Message
|
||||
from utils.misc import modules_help, prefix
|
||||
from utils.scripts import format_exc
|
||||
|
||||
commands = {
|
||||
'ftype': enums.ChatAction.TYPING,
|
||||
'faudio': enums.ChatAction.UPLOAD_AUDIO,
|
||||
'fvideo': enums.ChatAction.UPLOAD_VIDEO,
|
||||
'fphoto': enums.ChatAction.UPLOAD_PHOTO,
|
||||
'fdocument': enums.ChatAction.UPLOAD_DOCUMENT,
|
||||
'flocation': enums.ChatAction.FIND_LOCATION,
|
||||
'frvideo': enums.ChatAction.RECORD_VIDEO,
|
||||
'frvoice': enums.ChatAction.RECORD_AUDIO,
|
||||
'frvideor': enums.ChatAction.RECORD_VIDEO_NOTE,
|
||||
'fvideor': enums.ChatAction.UPLOAD_VIDEO_NOTE,
|
||||
'fgame': enums.ChatAction.PLAYING,
|
||||
'fcontact': enums.ChatAction.CHOOSE_CONTACT,
|
||||
'fstop': enums.ChatAction.CANCEL,
|
||||
'fscrn': 'screenshot',
|
||||
}
|
||||
|
||||
|
||||
# noinspection PyUnusedLocal
|
||||
@Client.on_message(filters.command(list(commands), prefix) & filters.me)
|
||||
async def fakeactions_handler(client: Client, message: Message):
|
||||
cmd = message.command[0]
|
||||
try:
|
||||
sec = int(message.command[1])
|
||||
if sec > 60:
|
||||
sec = 60
|
||||
except Exception:
|
||||
sec = None
|
||||
await message.delete()
|
||||
|
||||
action = commands[cmd]
|
||||
|
||||
try:
|
||||
if action != 'screenshot':
|
||||
if sec and action != enums.ChatAction.CANCEL:
|
||||
while sec > 0:
|
||||
await client.send_chat_action(chat_id=message.chat.id, action=action)
|
||||
await sleep(1)
|
||||
sec -= 1
|
||||
return await client.send_chat_action(chat_id=message.chat.id, action=action)
|
||||
else:
|
||||
for _ in range(sec if sec else 1):
|
||||
await client.invoke(
|
||||
functions.messages.SendScreenshotNotification(
|
||||
peer=await client.resolve_peer(message.chat.id),
|
||||
reply_to=InputReplyToMessage(reply_to_message_id=message.reply_to_message.id),
|
||||
random_id=client.rnd_id(),
|
||||
)
|
||||
)
|
||||
await sleep(0.1)
|
||||
except AttributeError:
|
||||
return await client.send_message('me', 'Error in <b>fakeactions</b>reply to message is required')
|
||||
except Exception as e:
|
||||
return await client.send_message('me', 'Error in <b>fakeactions</b> module:\n' + format_exc(e))
|
||||
|
||||
|
||||
modules_help['fakeactions'] = {
|
||||
'ftype [sec]': 'Typing... action',
|
||||
'faudio [sec]': 'Sending voice... action',
|
||||
'fvideo [sec]': 'Sending video... action',
|
||||
'fphoto [sec]': 'Sending photo... action',
|
||||
'fdocument [sec]': 'Sending document... action',
|
||||
'flocation [sec]': 'Find location... action',
|
||||
'fcontact [sec]': 'Sending contact... action',
|
||||
'frvideo [sec]': 'Recording video... action',
|
||||
'frvoice [sec]': 'Recording voice... action',
|
||||
'frvideor [sec]': 'Recording round video... action',
|
||||
'fvideor [sec]': 'Uploading round video... action',
|
||||
'fgame [sec]': 'Playing game... action',
|
||||
'fstop': 'Stop actions',
|
||||
'fscrn [amount] [reply_to_message]*': 'Make screenshot action',
|
||||
}
|
||||
@@ -0,0 +1,225 @@
|
||||
# Moon-Userbot - telegram userbot
|
||||
# Copyright (C) 2020-present Moon Userbot Organization
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
from pyrogram import Client, ContinuePropagation, errors, filters
|
||||
from pyrogram.types import (
|
||||
InputMediaAudio,
|
||||
InputMediaDocument,
|
||||
InputMediaPhoto,
|
||||
InputMediaVideo,
|
||||
Message,
|
||||
)
|
||||
from utils.db import db
|
||||
from utils.misc import modules_help, prefix
|
||||
from utils.scripts import format_exc
|
||||
|
||||
|
||||
def get_filters_chat(chat_id):
|
||||
return db.get('core.filters', f'{chat_id}', {})
|
||||
|
||||
|
||||
def set_filters_chat(chat_id, filters_):
|
||||
return db.set('core.filters', f'{chat_id}', filters_)
|
||||
|
||||
|
||||
async def contains_filter(_, __, m):
|
||||
return m.text and m.text.lower() in get_filters_chat(m.chat.id)
|
||||
|
||||
|
||||
contains = filters.create(contains_filter)
|
||||
|
||||
|
||||
# noinspection PyTypeChecker
|
||||
@Client.on_message(contains)
|
||||
async def filters_main_handler(client: Client, message: Message):
|
||||
value = get_filters_chat(message.chat.id)[message.text.lower()]
|
||||
try:
|
||||
await client.get_messages(int(value['CHAT_ID']), int(value['MESSAGE_ID']))
|
||||
except errors.RPCError as exc:
|
||||
raise ContinuePropagation from exc
|
||||
|
||||
if value.get('MEDIA_GROUP'):
|
||||
messages_grouped = await client.get_media_group(int(value['CHAT_ID']), int(value['MESSAGE_ID']))
|
||||
media_grouped_list = []
|
||||
for _ in messages_grouped:
|
||||
if _.photo:
|
||||
if _.caption:
|
||||
media_grouped_list.append(InputMediaPhoto(_.photo.file_id, _.caption.HTML))
|
||||
else:
|
||||
media_grouped_list.append(InputMediaPhoto(_.photo.file_id))
|
||||
elif _.video:
|
||||
if _.caption:
|
||||
if _.video.thumbs:
|
||||
media_grouped_list.append(
|
||||
InputMediaVideo(
|
||||
_.video.file_id,
|
||||
_.video.thumbs[0].file_id,
|
||||
_.caption.HTML,
|
||||
)
|
||||
)
|
||||
else:
|
||||
media_grouped_list.append(InputMediaVideo(_.video.file_id, _.caption.HTML))
|
||||
elif _.video.thumbs:
|
||||
media_grouped_list.append(InputMediaVideo(_.video.file_id, _.video.thumbs[0].file_id))
|
||||
else:
|
||||
media_grouped_list.append(InputMediaVideo(_.video.file_id))
|
||||
elif _.audio:
|
||||
if _.caption:
|
||||
media_grouped_list.append(InputMediaAudio(_.audio.file_id, _.caption.HTML))
|
||||
else:
|
||||
media_grouped_list.append(InputMediaAudio(_.audio.file_id))
|
||||
elif _.document:
|
||||
if _.caption:
|
||||
if _.document.thumbs:
|
||||
media_grouped_list.append(
|
||||
InputMediaDocument(
|
||||
_.document.file_id,
|
||||
_.document.thumbs[0].file_id,
|
||||
_.caption.HTML,
|
||||
)
|
||||
)
|
||||
else:
|
||||
media_grouped_list.append(InputMediaDocument(_.document.file_id, _.caption.HTML))
|
||||
elif _.document.thumbs:
|
||||
media_grouped_list.append(InputMediaDocument(_.document.file_id, _.document.thumbs[0].file_id))
|
||||
else:
|
||||
media_grouped_list.append(InputMediaDocument(_.document.file_id))
|
||||
await client.send_media_group(message.chat.id, media_grouped_list, reply_to_message_id=message.id)
|
||||
else:
|
||||
await client.copy_message(
|
||||
message.chat.id,
|
||||
int(value['CHAT_ID']),
|
||||
int(value['MESSAGE_ID']),
|
||||
reply_to_message_id=message.id,
|
||||
)
|
||||
raise ContinuePropagation
|
||||
|
||||
|
||||
@Client.on_message(filters.command(['filter'], prefix) & filters.me)
|
||||
async def filter_handler(client: Client, message: Message):
|
||||
try:
|
||||
if len(message.text.split()) < 2:
|
||||
return await message.edit(f'<b>Usage</b>: <code>{prefix}filter [name] (Reply required)</code>')
|
||||
name = message.text.split(maxsplit=1)[1].lower()
|
||||
chat_filters = get_filters_chat(message.chat.id)
|
||||
if name in chat_filters:
|
||||
return await message.edit(f'<b>Filter</b> <code>{name}</code> already exists.')
|
||||
if not message.reply_to_message:
|
||||
return await message.edit('<b>Reply to message</b> please.')
|
||||
|
||||
try:
|
||||
chat = await client.get_chat(db.get('core.notes', 'chat_id', 0))
|
||||
except (errors.RPCError, ValueError, KeyError):
|
||||
# group is not accessible or isn't created
|
||||
chat = await client.create_supergroup('Userbot_Notes_Filters', "Don't touch this group, please")
|
||||
db.set('core.notes', 'chat_id', chat.id)
|
||||
|
||||
chat_id = chat.id
|
||||
|
||||
if message.reply_to_message.media_group_id:
|
||||
get_media_group = [_.id for _ in await client.get_media_group(message.chat.id, message.reply_to_message.id)]
|
||||
try:
|
||||
message_id = await client.forward_messages(chat_id, message.chat.id, get_media_group)
|
||||
except errors.ChatForwardsRestricted:
|
||||
await message.edit('<b>Forwarding messages is restricted by chat admins</b>')
|
||||
return
|
||||
filter_ = {
|
||||
'MESSAGE_ID': str(message_id[1].id),
|
||||
'MEDIA_GROUP': True,
|
||||
'CHAT_ID': str(chat_id),
|
||||
}
|
||||
else:
|
||||
try:
|
||||
message_id = await message.reply_to_message.forward(chat_id)
|
||||
except errors.ChatForwardsRestricted:
|
||||
message_id = await message.copy(chat_id)
|
||||
filter_ = {
|
||||
'MEDIA_GROUP': False,
|
||||
'MESSAGE_ID': str(message_id.id),
|
||||
'CHAT_ID': str(chat_id),
|
||||
}
|
||||
|
||||
chat_filters.update({name: filter_})
|
||||
|
||||
set_filters_chat(message.chat.id, chat_filters)
|
||||
return await message.edit(
|
||||
f'<b>Filter</b> <code>{name}</code> has been added.',
|
||||
)
|
||||
except Exception as e:
|
||||
return await message.edit(format_exc(e))
|
||||
|
||||
|
||||
@Client.on_message(filters.command(['filters'], prefix) & filters.me)
|
||||
async def filters_handler(_, message: Message):
|
||||
try:
|
||||
text = ''
|
||||
for index, a in enumerate(get_filters_chat(message.chat.id).items(), start=1):
|
||||
key, _ = a
|
||||
key = key.replace('<', '').replace('>', '')
|
||||
text += f'{index}. <code>{key}</code>\n'
|
||||
text = f'<b>Your filters in current chat</b>:\n\n{text}'
|
||||
text = text[:4096]
|
||||
return await message.edit(text)
|
||||
except Exception as e:
|
||||
return await message.edit(format_exc(e))
|
||||
|
||||
|
||||
@Client.on_message(filters.command(['delfilter', 'filterdel', 'fdel'], prefix) & filters.me)
|
||||
async def filter_del_handler(_, message: Message):
|
||||
try:
|
||||
if len(message.text.split()) < 2:
|
||||
return await message.edit(
|
||||
f'<b>Usage</b>: <code>{prefix}fdel [name]</code>',
|
||||
)
|
||||
name = message.text.split(maxsplit=1)[1].lower()
|
||||
chat_filters = get_filters_chat(message.chat.id)
|
||||
if name not in chat_filters:
|
||||
return await message.edit(
|
||||
f"<b>Filter</b> <code>{name}</code> doesn't exists.",
|
||||
)
|
||||
del chat_filters[name]
|
||||
set_filters_chat(message.chat.id, chat_filters)
|
||||
return await message.edit(
|
||||
f'<b>Filter</b> <code>{name}</code> has been deleted.',
|
||||
)
|
||||
except Exception as e:
|
||||
return await message.edit(format_exc(e))
|
||||
|
||||
|
||||
@Client.on_message(filters.command(['fsearch'], prefix) & filters.me)
|
||||
async def filter_search_handler(_, message: Message):
|
||||
try:
|
||||
if len(message.text.split()) < 2:
|
||||
return await message.edit(
|
||||
f'<b>Usage</b>: <code>{prefix}fsearch [name]</code>',
|
||||
)
|
||||
name = message.text.split(maxsplit=1)[1].lower()
|
||||
chat_filters = get_filters_chat(message.chat.id)
|
||||
if name not in chat_filters:
|
||||
return await message.edit(
|
||||
f"<b>Filter</b> <code>{name}</code> doesn't exists.",
|
||||
)
|
||||
return await message.edit(f'<b>Trigger</b>:\n<code>{name}</code>\n<b>Answer</b>:\n{chat_filters[name]}')
|
||||
except Exception as e:
|
||||
return await message.edit(format_exc(e))
|
||||
|
||||
|
||||
modules_help['filters'] = {
|
||||
'filter [name]': 'Create filter (Reply required)',
|
||||
'filters': 'List of all triggers',
|
||||
'fdel [name]': 'Delete filter by name',
|
||||
'fsearch [name]': 'Info filter by name',
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
from pyrogram import Client, filters
|
||||
from pyrogram.types import Message
|
||||
from utils.misc import modules_help, prefix
|
||||
|
||||
REPLACEMENT_MAP = {
|
||||
'a': 'ɐ',
|
||||
'b': 'q',
|
||||
'c': 'ɔ',
|
||||
'd': 'p',
|
||||
'e': 'ǝ',
|
||||
'f': 'ɟ',
|
||||
'g': 'ƃ',
|
||||
'h': 'ɥ',
|
||||
'i': 'ᴉ',
|
||||
'j': 'ɾ',
|
||||
'k': 'ʞ',
|
||||
'l': 'l',
|
||||
'm': 'ɯ',
|
||||
'n': 'u',
|
||||
'o': 'o',
|
||||
'p': 'd',
|
||||
'q': 'b',
|
||||
'r': 'ɹ',
|
||||
's': 's',
|
||||
't': 'ʇ',
|
||||
'u': 'n',
|
||||
'v': 'ʌ',
|
||||
'w': 'ʍ',
|
||||
'x': 'x',
|
||||
'y': 'ʎ',
|
||||
'z': 'z',
|
||||
'A': '∀',
|
||||
'B': 'B',
|
||||
'C': 'Ɔ',
|
||||
'D': 'D',
|
||||
'E': 'Ǝ',
|
||||
'F': 'Ⅎ',
|
||||
'G': 'פ',
|
||||
'H': 'H',
|
||||
'I': 'I',
|
||||
'J': 'ſ',
|
||||
'K': 'K',
|
||||
'L': '˥',
|
||||
'M': 'W',
|
||||
'N': 'N',
|
||||
'O': 'O',
|
||||
'P': 'Ԁ',
|
||||
'Q': 'Q',
|
||||
'R': 'R',
|
||||
'S': 'S',
|
||||
'T': '┴',
|
||||
'U': '∩',
|
||||
'V': 'Λ',
|
||||
'W': 'M',
|
||||
'X': 'X',
|
||||
'Y': '⅄',
|
||||
'Z': 'Z',
|
||||
'0': '0',
|
||||
'1': 'Ɩ',
|
||||
'2': 'ᄅ',
|
||||
'3': 'Ɛ',
|
||||
'4': 'ㄣ',
|
||||
'5': 'ϛ',
|
||||
'6': '9',
|
||||
'7': 'ㄥ',
|
||||
'8': '8',
|
||||
'9': '6',
|
||||
',': "'",
|
||||
'.': '˙',
|
||||
'?': '¿',
|
||||
'!': '¡',
|
||||
'"': ',,',
|
||||
"'": ',',
|
||||
'(': ')',
|
||||
')': '(',
|
||||
'[': ']',
|
||||
']': '[',
|
||||
'{': '}',
|
||||
'}': '{',
|
||||
'<': '>',
|
||||
'>': '<',
|
||||
'&': '⅋',
|
||||
'_': '‾',
|
||||
}
|
||||
|
||||
|
||||
@Client.on_message(filters.command('flip', prefix) & filters.me)
|
||||
async def flip(client: Client, message: Message):
|
||||
text = ' '.join(message.command[1:])
|
||||
final_str = ''
|
||||
for char in text:
|
||||
new_char = REPLACEMENT_MAP.get(char, char)
|
||||
final_str += new_char
|
||||
if text != final_str:
|
||||
await message.edit(final_str)
|
||||
else:
|
||||
await message.edit(text)
|
||||
|
||||
|
||||
modules_help['fliptext'] = {'flip [amount]*': 'flip text upside down'}
|
||||
@@ -0,0 +1,51 @@
|
||||
import os
|
||||
import time
|
||||
|
||||
import requests
|
||||
from pyrogram import Client, filters
|
||||
from pyrogram.types import Message
|
||||
from utils.misc import modules_help, prefix
|
||||
from utils.scripts import format_exc, progress
|
||||
|
||||
|
||||
def schellwithflux(args):
|
||||
API_URL = 'https://randydev-ryuzaki-api.hf.space/api/v1/akeno/fluxai'
|
||||
payload = {'user_id': 1191668125, 'args': args} # Please don't edit here
|
||||
response = requests.post(API_URL, json=payload, timeout=10)
|
||||
if response.status_code != 200:
|
||||
print(f'Error status {response.status_code}')
|
||||
return None
|
||||
return response.content
|
||||
|
||||
|
||||
@Client.on_message(filters.command('fluxai', prefix) & filters.me)
|
||||
async def imgfluxai_(client: Client, message: Message):
|
||||
question = message.text.split(' ', 1)[1] if len(message.command) > 1 else None
|
||||
if not question:
|
||||
return await message.reply_text('Please provide a question for Flux.')
|
||||
try:
|
||||
image_bytes = schellwithflux(question)
|
||||
if image_bytes is None:
|
||||
return await message.reply_text('Failed to generate an image.')
|
||||
pro = await message.reply_text('Generating image, please wait...')
|
||||
|
||||
# Write the image bytes directly to a file
|
||||
with open('flux_gen.jpg', 'wb') as f:
|
||||
f.write(image_bytes)
|
||||
|
||||
ok = await pro.edit_text('Uploading image...')
|
||||
await message.reply_photo(
|
||||
'flux_gen.jpg',
|
||||
progress=progress,
|
||||
progress_args=(ok, time.time(), 'Uploading image...'),
|
||||
)
|
||||
await ok.delete()
|
||||
if os.path.exists('flux_gen.jpg'):
|
||||
os.remove('flux_gen.jpg')
|
||||
except Exception as e:
|
||||
await message.edit_text(format_exc(e))
|
||||
|
||||
|
||||
modules_help['fluxai'] = {
|
||||
'fluxai [prompt]*': 'text to image fluxai',
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
# This scripts contains use cases for userbots
|
||||
# This is used on my Moon-Userbot: https://github.com/The-MoonTg-project/Moon-Userbot
|
||||
# YOu can check it out for uses example
|
||||
|
||||
from pyrogram import Client, enums, filters
|
||||
from pyrogram.errors import MessageTooLong
|
||||
from pyrogram.types import Message
|
||||
from utils.config import gemini_key
|
||||
from utils.misc import modules_help, prefix
|
||||
from utils.rentry import paste as rentry_paste
|
||||
from utils.scripts import format_exc, import_library
|
||||
|
||||
genai = import_library('google.generativeai', 'google-generativeai')
|
||||
|
||||
genai.configure(api_key=gemini_key)
|
||||
|
||||
model = genai.GenerativeModel('gemini-2.0-flash')
|
||||
|
||||
|
||||
@Client.on_message(filters.command('gemini', prefix) & filters.me)
|
||||
async def say(client: Client, message: Message):
|
||||
try:
|
||||
await message.edit_text('<code>Please Wait...</code>')
|
||||
|
||||
if len(message.command) > 1:
|
||||
prompt = message.text.split(maxsplit=1)[1]
|
||||
elif message.reply_to_message:
|
||||
prompt = message.reply_to_message.text
|
||||
else:
|
||||
await message.edit_text(f'<b>Usage: </b><code>{prefix}gemini [prompt/reply to message]</code>')
|
||||
return
|
||||
|
||||
chat = model.start_chat()
|
||||
response = chat.send_message(prompt)
|
||||
|
||||
await message.edit_text(
|
||||
f'**Question:**`{prompt}`\n**Answer:** {response.text}',
|
||||
parse_mode=enums.ParseMode.MARKDOWN,
|
||||
)
|
||||
except MessageTooLong:
|
||||
await message.edit_text('<code>Output is too long... Pasting to rentry...</code>')
|
||||
try:
|
||||
rentry_url, edit_code = await rentry_paste(text=response.text, return_edit=True)
|
||||
except RuntimeError:
|
||||
await message.edit_text('<b>Error:</b> <code>Failed to paste to rentry</code>')
|
||||
return
|
||||
await client.send_message(
|
||||
'me',
|
||||
f"Here's your edit code for Url: {rentry_url}\nEdit code: <code>{edit_code}</code>",
|
||||
disable_web_page_preview=True,
|
||||
)
|
||||
await message.edit_text(
|
||||
f'<b>Output:</b> {rentry_url}\n<b>Note:</b> <code>Edit Code has been sent to your saved messages</code>',
|
||||
disable_web_page_preview=True,
|
||||
)
|
||||
except Exception as e:
|
||||
await message.edit_text(f'An error occurred: {format_exc(e)}')
|
||||
|
||||
|
||||
modules_help['gemini'] = {
|
||||
'gemini [prompt]*': 'Ask questions with Gemini Ai',
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
# Dragon-Userbot - telegram userbot
|
||||
# Copyright (C) 2020-present Dragon Userbot Organization
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
from pyrogram import Client, filters
|
||||
from pyrogram.types import Message
|
||||
from utils.misc import modules_help, prefix
|
||||
|
||||
|
||||
@Client.on_message(filters.command(['google', 'g'], prefix) & filters.me)
|
||||
async def webshot(_, message: Message):
|
||||
user_request = ' '.join(message.command[1:])
|
||||
|
||||
if user_request == '':
|
||||
if message.reply_to_message:
|
||||
reply_user_request = message.reply_to_message.text
|
||||
request = reply_user_request.replace(' ', '+')
|
||||
full_request = f'https://lmgtfy.app/?s=g&iie=1&q={request}'
|
||||
await message.edit(
|
||||
f'<a href={full_request}>{reply_user_request}</a>',
|
||||
disable_web_page_preview=True,
|
||||
)
|
||||
|
||||
else:
|
||||
request = user_request.replace(' ', '+')
|
||||
full_request = f'https://lmgtfy.app/?s=g&iie=1&q={request}'
|
||||
await message.edit(f'<a href={full_request}>{user_request}</a>', disable_web_page_preview=True)
|
||||
|
||||
|
||||
modules_help['google'] = {'google [request]': "To teach the interlocutor to use Google. Request isn't required."}
|
||||
@@ -0,0 +1,91 @@
|
||||
import asyncio
|
||||
import random
|
||||
|
||||
from pyrogram import Client, filters
|
||||
from pyrogram.errors.exceptions.flood_420 import FloodWait
|
||||
from pyrogram.types import Message
|
||||
from utils.misc import modules_help, prefix
|
||||
|
||||
R = '❤️'
|
||||
W = '🤍'
|
||||
|
||||
heart_list = [
|
||||
W * 9,
|
||||
W * 2 + R * 2 + W + R * 2 + W * 2,
|
||||
W + R * 7 + W,
|
||||
W + R * 7 + W,
|
||||
W + R * 7 + W,
|
||||
W * 2 + R * 5 + W * 2,
|
||||
W * 3 + R * 3 + W * 3,
|
||||
W * 4 + R + W * 4,
|
||||
W * 9,
|
||||
]
|
||||
joined_heart = '\n'.join(heart_list)
|
||||
|
||||
heartlet_len = joined_heart.count(R)
|
||||
|
||||
SLEEP = 0.1
|
||||
|
||||
|
||||
async def _wrap_edit(message: Message, text: str):
|
||||
"""Floodwait-safe utility wrapper for edit"""
|
||||
try:
|
||||
await message.edit(text)
|
||||
except FloodWait as fl:
|
||||
await asyncio.sleep(fl.x)
|
||||
|
||||
|
||||
async def phase1(message: Message):
|
||||
"""Big scroll"""
|
||||
BIG_SCROLL = '🧡💛💚💙💜🖤🤎'
|
||||
await _wrap_edit(message, joined_heart)
|
||||
for heart in BIG_SCROLL:
|
||||
await _wrap_edit(message, joined_heart.replace(R, heart))
|
||||
await asyncio.sleep(SLEEP)
|
||||
|
||||
|
||||
async def phase2(message: Message):
|
||||
"""Per-heart randomiser"""
|
||||
ALL = ['❤️'] + list('🧡💛💚💙💜🤎🖤') # don't include white heart
|
||||
|
||||
format_heart = joined_heart.replace(R, '{}')
|
||||
for _ in range(5):
|
||||
heart = format_heart.format(*random.choices(ALL, k=heartlet_len)) # noqa: S311
|
||||
await _wrap_edit(message, heart)
|
||||
await asyncio.sleep(SLEEP)
|
||||
|
||||
|
||||
async def phase3(message: Message):
|
||||
"""Fill up heartlet matrix"""
|
||||
await _wrap_edit(message, joined_heart)
|
||||
await asyncio.sleep(SLEEP * 2)
|
||||
repl = joined_heart
|
||||
for _ in range(joined_heart.count(W)):
|
||||
repl = repl.replace(W, R, 1)
|
||||
await _wrap_edit(message, repl)
|
||||
await asyncio.sleep(SLEEP)
|
||||
|
||||
|
||||
async def phase4(message: Message):
|
||||
"""Matrix shrinking"""
|
||||
for i in range(7, 0, -1):
|
||||
heart_matrix = '\n'.join([R * i] * i)
|
||||
await _wrap_edit(message, heart_matrix)
|
||||
await asyncio.sleep(SLEEP)
|
||||
|
||||
|
||||
@Client.on_message(filters.command('hearts', prefix) & filters.me)
|
||||
async def hearts(client: Client, message: Message):
|
||||
await phase1(message)
|
||||
await phase2(message)
|
||||
await phase3(message)
|
||||
await phase4(message)
|
||||
await asyncio.sleep(SLEEP * 3)
|
||||
|
||||
final_caption = ' '.join(message.command[1:])
|
||||
if not final_caption:
|
||||
final_caption = '💕 by @moonuserbot'
|
||||
await message.edit(final_caption)
|
||||
|
||||
|
||||
modules_help['hearts'] = {'hearts': 'Heart animation. May cause floodwaits, use at your own risk!'}
|
||||
@@ -0,0 +1,81 @@
|
||||
# Moon-Userbot - telegram userbot
|
||||
# Copyright (C) 2020-present Moon Userbot Organization
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
from pyrogram import Client, filters
|
||||
from pyrogram.types import Message
|
||||
from utils.misc import modules_help, prefix
|
||||
from utils.module import ModuleManager
|
||||
from utils.scripts import format_module_help, with_reply
|
||||
|
||||
module_manager = ModuleManager.get_instance()
|
||||
|
||||
|
||||
@Client.on_message(filters.command(['help', 'h'], prefix) & filters.me)
|
||||
async def help_cmd(_, message: Message):
|
||||
if not module_manager.help_navigator:
|
||||
await message.edit('<b>Help system is not initialized yet. Please wait...</b>')
|
||||
return
|
||||
|
||||
if len(message.command) == 1:
|
||||
await module_manager.help_navigator.send_page(message)
|
||||
elif message.command[1].lower() in modules_help:
|
||||
await message.edit(format_module_help(message.command[1].lower(), prefix))
|
||||
else:
|
||||
command_name = message.command[1].lower()
|
||||
module_found = False
|
||||
for module_name, commands in modules_help.items():
|
||||
for command in commands:
|
||||
if command.split()[0] == command_name:
|
||||
cmd = command.split(maxsplit=1)
|
||||
cmd_desc = commands[command]
|
||||
module_found = True
|
||||
return await message.edit(
|
||||
f'<b>Help for command <code>{prefix}{command_name}</code></b>\n'
|
||||
f'Module: {module_name} (<code>{prefix}help {module_name}</code>)\n\n'
|
||||
f'<code>{prefix}{cmd[0]}</code>'
|
||||
f'{" <code>" + cmd[1] + "</code>" if len(cmd) > 1 else ""}'
|
||||
f' — <i>{cmd_desc}</i>',
|
||||
)
|
||||
if not module_found:
|
||||
await message.edit(f'<b>Module or command {command_name} not found</b>')
|
||||
|
||||
|
||||
@Client.on_message(filters.command(['pn', 'pp', 'pq'], prefix) & filters.me)
|
||||
@with_reply
|
||||
async def handle_navigation(_, message: Message):
|
||||
if not module_manager.help_navigator:
|
||||
await message.edit('<b>Help system is not initialized yet. Please wait...</b>')
|
||||
return
|
||||
|
||||
reply_message = message.reply_to_message
|
||||
if reply_message and 'Help Page No:' in message.reply_to_message.text:
|
||||
cmd = message.command[0].lower()
|
||||
if cmd == 'pn':
|
||||
if module_manager.help_navigator.next_page():
|
||||
await module_manager.help_navigator.send_page(reply_message)
|
||||
return await message.delete()
|
||||
await message.edit('No more pages available.')
|
||||
elif cmd == 'pp':
|
||||
if module_manager.help_navigator.prev_page():
|
||||
await module_manager.help_navigator.send_page(reply_message)
|
||||
return await message.delete()
|
||||
return await message.edit('This is the first page.')
|
||||
elif cmd == 'pq':
|
||||
await reply_message.delete()
|
||||
return await message.edit('Help closed.')
|
||||
|
||||
|
||||
modules_help['help'] = {
|
||||
'help [module/command name]': 'Get common/module/command help',
|
||||
'pn/pp/pq': 'Navigate through help pages' + ' (pn: next page, pp: previous page, pq: quit help)',
|
||||
}
|
||||
@@ -0,0 +1,190 @@
|
||||
import asyncio
|
||||
import io
|
||||
import logging
|
||||
import os
|
||||
import time
|
||||
from concurrent.futures import ThreadPoolExecutor
|
||||
|
||||
import aiohttp
|
||||
from PIL import Image
|
||||
from pyrogram import Client, enums, filters
|
||||
from pyrogram.types import Message
|
||||
from utils.db import db
|
||||
from utils.misc import modules_help, prefix
|
||||
from utils.scripts import format_exc
|
||||
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
async def query_huggingface(payload):
|
||||
api_key = db.get('custom.hf', 'api_key', None)
|
||||
model = db.get('custom.hf', 'current_model', None)
|
||||
|
||||
if not api_key:
|
||||
raise ValueError(f'API key not set. Use {prefix}set_hf api <api_key> to set it.')
|
||||
if not model:
|
||||
raise ValueError(f'Model not set. Use {prefix}set_hf model <model_name> to set it.')
|
||||
|
||||
api_url = f'https://api-inference.huggingface.co/models/{model}'
|
||||
headers = {'Authorization': f'Bearer {api_key}'}
|
||||
timeout = aiohttp.ClientTimeout(total=120)
|
||||
start_time = time.time()
|
||||
retries = 3
|
||||
|
||||
for attempt in range(1, retries + 1):
|
||||
try:
|
||||
async with (
|
||||
aiohttp.ClientSession(timeout=timeout) as session,
|
||||
session.post(api_url, headers=headers, json=payload) as response,
|
||||
):
|
||||
fetch_time = int((time.time() - start_time) * 1000)
|
||||
if response.status != 200:
|
||||
error_text = await response.text()
|
||||
logger.error(f'API Error {response.status}: {error_text}')
|
||||
return None, fetch_time
|
||||
return await response.read(), fetch_time
|
||||
except TimeoutError:
|
||||
logger.error(f'TimeoutError: Attempt {attempt}/{retries} timed out.')
|
||||
if attempt == retries:
|
||||
raise
|
||||
except asyncio.CancelledError:
|
||||
logger.error('Request was cancelled. Ensure the task is not being forcefully terminated.')
|
||||
raise
|
||||
except aiohttp.ClientError as e:
|
||||
logger.error(f'Network Error: {e}')
|
||||
if attempt == retries:
|
||||
raise
|
||||
finally:
|
||||
await asyncio.sleep(2)
|
||||
|
||||
|
||||
async def save_image(image_bytes, path):
|
||||
loop = asyncio.get_event_loop()
|
||||
with ThreadPoolExecutor() as pool:
|
||||
await loop.run_in_executor(pool, lambda: Image.open(io.BytesIO(image_bytes)).save(path))
|
||||
|
||||
|
||||
@Client.on_message(filters.command(['set_hf'], prefix) & filters.me)
|
||||
async def manage_huggingface(_, message: Message):
|
||||
"""Manage Hugging Face API key and models."""
|
||||
subcommand = message.command[1].lower() if len(message.command) > 1 else None
|
||||
arg = message.command[2] if len(message.command) > 2 else None
|
||||
|
||||
if subcommand == 'api':
|
||||
if arg:
|
||||
db.set('custom.hf', 'api_key', arg)
|
||||
return await message.edit_text(f'Hugging Face API key set successfully.\nAPI Key: {arg}')
|
||||
return await message.edit_text(f'Usage: {prefix}hf api <api_key>')
|
||||
|
||||
if subcommand == 'model':
|
||||
if arg:
|
||||
models = db.get('custom.hf', 'models', [])
|
||||
if arg not in models:
|
||||
models.append(arg)
|
||||
db.set('custom.hf', 'models', models)
|
||||
db.set('custom.hf', 'current_model', arg)
|
||||
return await message.edit_text(f"Model '{arg}' added and set as the current model.")
|
||||
return await message.edit_text(f'Usage: {prefix}hf model <model_name>')
|
||||
|
||||
if subcommand == 'select':
|
||||
models = db.get('custom.hf', 'models', [])
|
||||
if arg and arg.lower() == 'all':
|
||||
db.set('custom.hf', 'current_model', 'all')
|
||||
model_list = '\n'.join([f'*{i + 1}. {m}' for i, m in enumerate(models)])
|
||||
return await message.edit_text(
|
||||
f'All models selected:\n<code>{model_list}</code>\n\nImages will be generated from all models.'
|
||||
)
|
||||
if arg:
|
||||
try:
|
||||
index = int(arg) - 1
|
||||
if 0 <= index < len(models):
|
||||
db.set('custom.hf', 'current_model', models[index])
|
||||
return await message.edit_text(f"Model set to '{models[index]}'.")
|
||||
return await message.edit_text('Invalid model number.')
|
||||
except ValueError:
|
||||
return await message.edit_text('Invalid model number. Use a valid integer.')
|
||||
return await message.edit_text(f'Usage: {prefix}hf select <model_number|all>')
|
||||
|
||||
if subcommand == 'delete' and arg:
|
||||
try:
|
||||
index = int(arg) - 1
|
||||
models = db.get('custom.hf', 'models', [])
|
||||
if 0 <= index < len(models):
|
||||
removed_model = models.pop(index)
|
||||
db.set('custom.hf', 'models', models)
|
||||
if db.get('custom.hf', 'current_model') == removed_model:
|
||||
db.set('custom.hf', 'current_model', models[0] if models else 'None')
|
||||
return await message.edit_text(f"Model '{removed_model}' deleted.")
|
||||
return await message.edit_text('Invalid model number.')
|
||||
except ValueError:
|
||||
return await message.edit_text('Invalid model number. Use a valid integer.')
|
||||
|
||||
api_key = db.get('custom.hf', 'api_key', None)
|
||||
models = db.get('custom.hf', 'models', [])
|
||||
current_model = db.get('custom.hf', 'current_model', 'Not set')
|
||||
model_list = '\n'.join(
|
||||
[f'{"*" if m == current_model or current_model == "all" else ""}{i + 1}. {m}' for i, m in enumerate(models)]
|
||||
)
|
||||
settings = (
|
||||
f'<b>Hugging Face settings:</b>\n'
|
||||
f'<b>API Key:</b>\n<code>{api_key if api_key else "Not set"}</code>\n\n'
|
||||
f'<b>Available Models:</b>\n<code>{model_list}</code>'
|
||||
)
|
||||
usage_message = (
|
||||
f'{settings}\n\n<b>Usage:</b>\n'
|
||||
f'<code>{prefix}set_hf</code> <code>api</code>, <code>model</code>, <code>select</code>, <code>delete</code>, <code>select all</code>'
|
||||
)
|
||||
await message.edit_text(usage_message)
|
||||
|
||||
|
||||
@Client.on_message(filters.command(['hf', 'hface', 'huggingface'], prefix))
|
||||
async def imgflux_(_, message: Message):
|
||||
prompt = message.text.split(' ', 1)[1] if len(message.command) > 1 else None
|
||||
if not prompt:
|
||||
usage_message = f'<b>Usage:</b> <code>{prefix}{message.command[0]} [custom prompt]</code>'
|
||||
return await (message.edit_text if message.from_user.is_self else message.reply_text)(usage_message)
|
||||
|
||||
processing_message = await (message.edit_text if message.from_user.is_self else message.reply_text)('Processing...')
|
||||
|
||||
try:
|
||||
current_model = db.get('custom.hf', 'current_model', None)
|
||||
models = db.get('custom.hf', 'models', [])
|
||||
models_to_use = models if current_model == 'all' else [current_model]
|
||||
|
||||
generated_images = []
|
||||
|
||||
for model in models_to_use:
|
||||
db.set('custom.hf', 'current_model', model)
|
||||
payload = {'inputs': prompt}
|
||||
image_bytes, fetch_time = await query_huggingface(payload)
|
||||
if not image_bytes:
|
||||
logger.warning(f'Failed to fetch image for model: {model}')
|
||||
continue
|
||||
|
||||
image_path = f'hf_flux_gen_{model.replace("/", "_")}.jpg'
|
||||
await save_image(image_bytes, image_path)
|
||||
generated_images.append((image_path, model, fetch_time))
|
||||
|
||||
if not generated_images:
|
||||
return await processing_message.edit_text('Failed to generate an image for all models.')
|
||||
|
||||
for image_path, model_name, fetch_time in generated_images:
|
||||
caption = f'**Model:**\n> {model_name}\n**Prompt used:**\n> {prompt}\n\n**Fetching Time:** {fetch_time} ms'
|
||||
await message.reply_photo(image_path, caption=caption, parse_mode=enums.ParseMode.MARKDOWN)
|
||||
os.remove(image_path)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f'Unexpected Error: {e}')
|
||||
await processing_message.edit_text(format_exc(e))
|
||||
finally:
|
||||
await processing_message.delete()
|
||||
|
||||
|
||||
modules_help['huggingface'] = {
|
||||
'hf [prompt]*': 'Generate an AI image using Hugging Face model(s).',
|
||||
'set_hf <api>*': 'Set the Hugging Face API key.',
|
||||
'set_hf model <model_name>*': 'Add and set a Hugging Face model.',
|
||||
'set_hf select <model_number|all>*': 'Select a specific model or all models for use.',
|
||||
'set_hf delete <model_number>*': 'Delete a model from the list.',
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
# Moon-Userbot - telegram userbot
|
||||
# Copyright (C) 2020-present Moon Userbot Organization
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
from pyrogram import Client, enums, filters
|
||||
from pyrogram.types import Message, MessageOriginHiddenUser
|
||||
from utils.misc import modules_help, prefix
|
||||
|
||||
|
||||
@Client.on_message(filters.command('id', prefix) & filters.me)
|
||||
async def ids(_, message: Message):
|
||||
text = '\n'.join(
|
||||
[
|
||||
f'Chat ID: `{message.chat.id}`',
|
||||
f'Chat DC ID: `{message.chat.dc_id}`\n',
|
||||
f'Message ID: `{message.id}`',
|
||||
(
|
||||
f'Your ID: `{message.from_user.id}`'
|
||||
if message.from_user
|
||||
else f'Channel/Group ID: `{message.sender_chat.id}`'
|
||||
),
|
||||
(
|
||||
f'Your DC ID: `{message.from_user.dc_id}`'
|
||||
if message.from_user
|
||||
else f'Channel/Group ID: `{message.sender_chat.id}`'
|
||||
),
|
||||
]
|
||||
)
|
||||
|
||||
if rtm := message.reply_to_message:
|
||||
# print(rtm)
|
||||
text += f'\n\nReplied Message ID: `{rtm.id}`'
|
||||
|
||||
if user := rtm.from_user:
|
||||
text = '\n'.join(
|
||||
[
|
||||
text,
|
||||
f'Replied User ID: `{user.id}`',
|
||||
f'Replied User DC ID: `{user.dc_id}`',
|
||||
]
|
||||
)
|
||||
|
||||
else:
|
||||
text = '\n'.join(
|
||||
[
|
||||
text,
|
||||
f'Replied Chat ID: `{rtm.sender_chat.id}`',
|
||||
f'Replied Chat DC ID: `{rtm.sender_chat.dc_id}`',
|
||||
]
|
||||
)
|
||||
|
||||
if rtm.forward_origin and rtm.forward_origin.date:
|
||||
if isinstance(rtm.forward_origin, MessageOriginHiddenUser):
|
||||
text = '\n'.join(
|
||||
[
|
||||
text,
|
||||
'\nForwarded from a hidden user.',
|
||||
]
|
||||
)
|
||||
elif ffc := rtm.forward_origin.sender_user:
|
||||
text = '\n'.join(
|
||||
[
|
||||
text,
|
||||
f'\nForwarded Message ID: `{getattr(rtm.forward_origin, "message_id", None)}`',
|
||||
f'Forwarded from Chat ID: `{ffc.id}`',
|
||||
f'Forwarded from Chat DC ID: `{ffc.dc_id}`',
|
||||
]
|
||||
)
|
||||
|
||||
await message.edit('**__' + text + '__**', parse_mode=enums.ParseMode.MARKDOWN)
|
||||
|
||||
|
||||
modules_help['id'] = {
|
||||
'id': 'simply run or reply to message',
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
import os
|
||||
from datetime import datetime
|
||||
|
||||
from pyrogram import Client, filters
|
||||
from pyrogram.types import Message
|
||||
from utils.misc import modules_help, prefix
|
||||
|
||||
|
||||
@Client.on_message(filters.command('joindate', prefix) & filters.me)
|
||||
async def joindate(client: Client, message: Message):
|
||||
await message.edit('<b>One moment...</b>')
|
||||
members = []
|
||||
cgetmsg = await client.get_messages(message.chat.id, 1)
|
||||
async for m in client.iter_chat_members(message.chat.id):
|
||||
members.append(
|
||||
(
|
||||
m.user.first_name,
|
||||
m.joined_date or cgetmsg.date,
|
||||
)
|
||||
)
|
||||
|
||||
members.sort(key=lambda member: member[1])
|
||||
|
||||
with open('joined_date.txt', 'w', encoding='utf8') as f:
|
||||
f.write('Join Date First Name\n')
|
||||
for member in members:
|
||||
f.write(str(datetime.fromtimestamp(member[1]).strftime('%y-%m-%d %H:%M')) + f' {member[0]}\n')
|
||||
|
||||
await message.delete()
|
||||
await client.send_document(message.chat.id, 'joined_date.txt')
|
||||
os.remove('joined_date.txt')
|
||||
|
||||
|
||||
modules_help['joindate'] = {
|
||||
'joindate': 'Get a list of all chat members and sort them by the date they joined the group'
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
import asyncio
|
||||
import random
|
||||
|
||||
from pyrogram import Client, filters
|
||||
from pyrogram.types import Message
|
||||
from utils.misc import modules_help, prefix
|
||||
|
||||
|
||||
@Client.on_message(filters.command('kokodrilo', prefix) & filters.me)
|
||||
async def kokodrilo_explodando(_, message: Message):
|
||||
amount = 1
|
||||
if len(message.command) > 1:
|
||||
amount = int(message.command[1])
|
||||
for _ in range(amount):
|
||||
await message.edit('🐊')
|
||||
await asyncio.sleep(random.uniform(1, 2.5)) # noqa: S311
|
||||
await message.edit('💥')
|
||||
await asyncio.sleep(1.8)
|
||||
|
||||
|
||||
modules_help['kokodrilo_explodando'] = {
|
||||
'kokodrilo [number of explosions]': '<b>kOkOdRiLo ExPlOrAdO</b>',
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
# Dragon-Userbot - telegram userbot
|
||||
# Copyright (C) 2020-present Dragon Userbot Organization
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import asyncio
|
||||
|
||||
from pyrogram import Client, filters
|
||||
from pyrogram.types import Message
|
||||
from utils.misc import modules_help, prefix
|
||||
|
||||
|
||||
@Client.on_message(filters.command(['leave_chat', 'lc'], prefix) & filters.me)
|
||||
async def leave_chat(_, message: Message):
|
||||
if message.chat.type != 'private':
|
||||
await message.edit('<b>Goodbye...</b>')
|
||||
await asyncio.sleep(3)
|
||||
await message.chat.leave()
|
||||
else:
|
||||
await message.edit('<b>Not supported in private chats</b>')
|
||||
|
||||
|
||||
modules_help['leave_chat'] = {
|
||||
'leave_chat': 'Quit chat',
|
||||
}
|
||||
@@ -0,0 +1,318 @@
|
||||
# Moon-Userbot - telegram userbot
|
||||
# Copyright (C) 2020-present Moon Userbot Organization
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import hashlib
|
||||
import os
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
import requests
|
||||
from pyrogram import Client, filters
|
||||
from pyrogram.types import Message
|
||||
from utils.db import db
|
||||
from utils.misc import modules_help, prefix
|
||||
from utils.scripts import restart
|
||||
|
||||
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)
|
||||
async def get_mod_hash(_, message: Message):
|
||||
if len(message.command) == 1:
|
||||
return
|
||||
url = message.command[1].lower()
|
||||
resp = requests.get(url, timeout=10)
|
||||
if not resp.ok:
|
||||
await message.edit(f'<b>Troubleshooting with downloading module <code>{url}</code></b>')
|
||||
return
|
||||
|
||||
await message.edit(
|
||||
f'<b>Module hash: <code>{hashlib.sha256(resp.content).hexdigest()}</code>\n'
|
||||
f'Link: <code>{url}</code>\nFile: <code>{url.split("/")[-1]}</code></b>',
|
||||
)
|
||||
|
||||
|
||||
@Client.on_message(filters.command(['loadmod', 'lm'], prefix) & filters.me)
|
||||
async def loadmod(_, message: Message):
|
||||
if (
|
||||
not (
|
||||
message.reply_to_message
|
||||
and message.reply_to_message.document
|
||||
and message.reply_to_message.document.file_name.endswith('.py')
|
||||
)
|
||||
and len(message.command) == 1
|
||||
):
|
||||
await message.edit('<b>Specify module to download</b>')
|
||||
return
|
||||
|
||||
if len(message.command) > 1:
|
||||
await message.edit('<b>Fetching module...</b>')
|
||||
url = message.command[1].lower()
|
||||
|
||||
if url.startswith('https://raw.githubusercontent.com/The-MoonTg-project/custom_modules/main/'):
|
||||
module_name = url.split('/')[-1].split('.')[0]
|
||||
elif '.' not in url:
|
||||
module_name = url.lower()
|
||||
try:
|
||||
f = requests.get(
|
||||
'https://raw.githubusercontent.com/The-MoonTg-project/custom_modules/main/full.txt'
|
||||
, timeout=10).text
|
||||
except Exception:
|
||||
return await message.edit('Failed to fetch custom modules list')
|
||||
modules_dict = {line.split('/')[-1].split()[0]: line.strip() for line in f.splitlines()}
|
||||
if module_name in modules_dict:
|
||||
url = f'https://raw.githubusercontent.com/The-MoonTg-project/custom_modules/main/{modules_dict[module_name]}.py'
|
||||
else:
|
||||
await message.edit(f'<b>Module <code>{module_name}</code> is not found</b>')
|
||||
return
|
||||
else:
|
||||
modules_hashes = requests.get(
|
||||
'https://raw.githubusercontent.com/The-MoonTg-project/custom_modules/main/modules_hashes.txt'
|
||||
, timeout=10).text
|
||||
resp = requests.get(url, timeout=10)
|
||||
|
||||
if not resp.ok:
|
||||
await message.edit(
|
||||
f'<b>Troubleshooting with downloading module <code>{url}</code></b>',
|
||||
)
|
||||
return
|
||||
|
||||
if hashlib.sha256(resp.content).hexdigest() not in modules_hashes:
|
||||
return await message.edit(
|
||||
'<b>Only <a href=https://github.com/The-MoonTg-project/custom_modules/tree/main/modules_hashes.txt>'
|
||||
'verified</a> modules or from the official '
|
||||
'<a href=https://github.com/The-MoonTg-project/custom_modules>'
|
||||
'custom_modules</a> repository are supported!</b>',
|
||||
disable_web_page_preview=True,
|
||||
)
|
||||
|
||||
module_name = url.split('/')[-1].split('.')[0]
|
||||
|
||||
resp = requests.get(url, timeout=10)
|
||||
if not resp.ok:
|
||||
await message.edit(f'<b>Module <code>{module_name}</code> is not found</b>')
|
||||
return
|
||||
|
||||
if not os.path.exists(f'{BASE_PATH}/modules/custom_modules'):
|
||||
os.mkdir(f'{BASE_PATH}/modules/custom_modules')
|
||||
|
||||
with open(f'./modules/custom_modules/{module_name}.py', 'wb') as f:
|
||||
f.write(resp.content)
|
||||
else:
|
||||
file_name = await message.reply_to_message.download()
|
||||
module_name = message.reply_to_message.document.file_name[:-3]
|
||||
|
||||
with open(file_name, 'rb') as f:
|
||||
content = f.read()
|
||||
|
||||
modules_hashes = requests.get(
|
||||
'https://raw.githubusercontent.com/The-MoonTg-project/custom_modules/main/modules_hashes.txt'
|
||||
, timeout=10).text
|
||||
|
||||
if hashlib.sha256(content).hexdigest() not in modules_hashes:
|
||||
os.remove(file_name)
|
||||
return await message.edit(
|
||||
'<b>Only <a href=https://github.com/The-MoonTg-project/custom_modules/tree/main/modules_hashes.txt>'
|
||||
'verified</a> modules or from the official '
|
||||
'<a href=https://github.com/The-MoonTg-project/custom_modules>'
|
||||
'custom_modules</a> repository are supported!</b>',
|
||||
disable_web_page_preview=True,
|
||||
)
|
||||
os.rename(file_name, f'./modules/custom_modules/{module_name}.py')
|
||||
|
||||
all_modules = db.get('custom.modules', 'allModules', [])
|
||||
if module_name not in all_modules:
|
||||
all_modules.append(module_name)
|
||||
db.set('custom.modules', 'allModules', all_modules)
|
||||
await message.edit(f'<b>The module <code>{module_name}</code> is loaded!\nRestarting...</b>')
|
||||
db.set(
|
||||
'core.updater',
|
||||
'restart_info',
|
||||
{
|
||||
'type': 'restart',
|
||||
'chat_id': message.chat.id,
|
||||
'message_id': message.id,
|
||||
},
|
||||
)
|
||||
restart()
|
||||
|
||||
|
||||
@Client.on_message(filters.command(['unloadmod', 'ulm'], prefix) & filters.me)
|
||||
async def unload_mods(_, message: Message):
|
||||
if len(message.command) <= 1:
|
||||
return
|
||||
|
||||
module_name = message.command[1].lower()
|
||||
|
||||
if module_name.startswith('https://raw.githubusercontent.com/The-MoonTg-project/custom_modules/main/'):
|
||||
module_name = module_name.split('/')[-1].split('.')[0]
|
||||
|
||||
if os.path.exists(f'{BASE_PATH}/modules/custom_modules/{module_name}.py'):
|
||||
os.remove(f'{BASE_PATH}/modules/custom_modules/{module_name}.py')
|
||||
if module_name == 'musicbot':
|
||||
subprocess.run(
|
||||
[sys.executable, '-m', 'pip', 'uninstall', '-y', 'requirements.txt'],
|
||||
cwd=f'{BASE_PATH}/musicbot',
|
||||
)
|
||||
shutil.rmtree(f'{BASE_PATH}/musicbot')
|
||||
all_modules = db.get('custom.modules', 'allModules', [])
|
||||
if module_name in all_modules:
|
||||
all_modules.remove(module_name)
|
||||
db.set('custom.modules', 'allModules', all_modules)
|
||||
await message.edit(f'<b>The module <code>{module_name}</code> removed!\nRestarting...</b>')
|
||||
db.set(
|
||||
'core.updater',
|
||||
'restart_info',
|
||||
{
|
||||
'type': 'restart',
|
||||
'chat_id': message.chat.id,
|
||||
'message_id': message.id,
|
||||
},
|
||||
)
|
||||
restart()
|
||||
elif os.path.exists(f'{BASE_PATH}/modules/{module_name}.py'):
|
||||
await message.edit('<b>It is forbidden to remove built-in modules, it will disrupt the updater</b>')
|
||||
else:
|
||||
await message.edit(f'<b>Module <code>{module_name}</code> is not found</b>')
|
||||
|
||||
|
||||
@Client.on_message(filters.command(['loadallmods', 'lmall'], prefix) & filters.me)
|
||||
async def load_all_mods(_, message: Message):
|
||||
await message.edit('<b>Fetching info...</b>')
|
||||
|
||||
if not os.path.exists(f'{BASE_PATH}/modules/custom_modules'):
|
||||
os.mkdir(f'{BASE_PATH}/modules/custom_modules')
|
||||
|
||||
try:
|
||||
f = requests.get('https://raw.githubusercontent.com/The-MoonTg-project/custom_modules/main/full.txt', timeout=10).text
|
||||
except Exception:
|
||||
return await message.edit('Failed to fetch custom modules list')
|
||||
modules_list = f.splitlines()
|
||||
|
||||
await message.edit('<b>Loading modules...</b>')
|
||||
for module_name in modules_list:
|
||||
url = f'https://raw.githubusercontent.com/The-MoonTg-project/custom_modules/main/{module_name}.py'
|
||||
resp = requests.get(url, timeout=10)
|
||||
if not resp.ok:
|
||||
continue
|
||||
with open(f'./modules/custom_modules/{module_name.split("/")[1]}.py', 'wb') as f:
|
||||
f.write(resp.content)
|
||||
|
||||
await message.edit(
|
||||
f'<b>Successfully loaded new modules: {len(modules_list)}\nRestarting...</b>',
|
||||
)
|
||||
db.set(
|
||||
'core.updater',
|
||||
'restart_info',
|
||||
{
|
||||
'type': 'restart',
|
||||
'chat_id': message.chat.id,
|
||||
'message_id': message.id,
|
||||
},
|
||||
)
|
||||
restart()
|
||||
|
||||
|
||||
@Client.on_message(filters.command(['unloadallmods', 'ulmall'], prefix) & filters.me)
|
||||
async def unload_all_mods(_, message: Message):
|
||||
await message.edit('<b>Fetching info...</b>')
|
||||
|
||||
if not os.path.exists(f'{BASE_PATH}/modules/custom_modules'):
|
||||
return await message.edit("<b>You don't have any modules installed</b>")
|
||||
shutil.rmtree(f'{BASE_PATH}/modules/custom_modules')
|
||||
db.set('custom.modules', 'allModules', [])
|
||||
await message.edit('<b>Successfully unloaded all modules!\nRestarting...</b>')
|
||||
|
||||
db.set(
|
||||
'core.updater',
|
||||
'restart_info',
|
||||
{
|
||||
'type': 'restart',
|
||||
'chat_id': message.chat.id,
|
||||
'message_id': message.id,
|
||||
},
|
||||
)
|
||||
restart()
|
||||
|
||||
|
||||
@Client.on_message(filters.command(['updateallmods'], prefix) & filters.me)
|
||||
async def updateallmods(_, message: Message):
|
||||
await message.edit('<b>Updating modules...</b>')
|
||||
|
||||
if not os.path.exists(f'{BASE_PATH}/modules/custom_modules'):
|
||||
os.mkdir(f'{BASE_PATH}/modules/custom_modules')
|
||||
|
||||
modules_installed = list(os.walk('modules/custom_modules'))[0][2]
|
||||
|
||||
if not modules_installed:
|
||||
return await message.edit("<b>You don't have any modules installed</b>")
|
||||
|
||||
for module_name in modules_installed:
|
||||
if not module_name.endswith('.py'):
|
||||
continue
|
||||
try:
|
||||
f = requests.get('https://raw.githubusercontent.com/The-MoonTg-project/custom_modules/main/full.txt', timeout=10).text
|
||||
except Exception:
|
||||
return await message.edit('Failed to fetch custom modules list')
|
||||
modules_dict = {line.split('/')[-1].split()[0]: line.strip() for line in f.splitlines()}
|
||||
if module_name in modules_dict:
|
||||
resp = requests.get(
|
||||
f'https://raw.githubusercontent.com/The-MoonTg-project/custom_modules/main/{modules_dict[module_name]}.py'
|
||||
, timeout=10)
|
||||
if not resp.ok:
|
||||
modules_installed.remove(module_name)
|
||||
continue
|
||||
|
||||
with open(f'./modules/custom_modules/{module_name}', 'wb') as f:
|
||||
f.write(resp.content)
|
||||
|
||||
await message.edit(f'<b>Successfully updated {len(modules_installed)} modules</b>')
|
||||
|
||||
|
||||
modules_help['loader'] = {
|
||||
'loadmod [module_name]*': 'Download module.\n'
|
||||
'Only modules from the official custom_modules repository and proven '
|
||||
'modules whose hashes are in modules_hashes.txt are supported',
|
||||
'unloadmod [module_name]*': 'Delete module',
|
||||
'modhash [link]*': 'Get module hash by link',
|
||||
'loadallmods': 'Load all custom modules (use it at your own risk)',
|
||||
'unloadallmods': 'Unload all custom modules',
|
||||
'updateallmods': 'Update all custom modules'
|
||||
'\n\n* - required argument'
|
||||
'\n <b>short cmds:</b>'
|
||||
'\n loadmod - lm'
|
||||
'\n unloadmod - ulm'
|
||||
'\n modhash - mh'
|
||||
'\n loadallmods - lmall'
|
||||
'\n unloadallmods - ulmall',
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
# Moon-Userbot - telegram userbot
|
||||
# Copyright (C) 2020-present Moon Userbot Organization
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import os
|
||||
|
||||
from pyrogram import Client, filters
|
||||
from pyrogram.types import Message
|
||||
from utils.misc import modules_help
|
||||
from utils.scripts import import_library, prefix, with_reply
|
||||
|
||||
import_library('markitdown')
|
||||
|
||||
from markitdown import MarkItDown # noqa: E402
|
||||
|
||||
|
||||
@Client.on_message(filters.command(['markitdown', 'mkdn'], prefix) & filters.me)
|
||||
@with_reply
|
||||
async def markitdown(client: Client, message: Message):
|
||||
if message.reply_to_message.document:
|
||||
await message.edit('Converting to Markdown...')
|
||||
file = await message.reply_to_message.download()
|
||||
file_name = (message.reply_to_message.document.file_name).split('.')[0] + '.md'
|
||||
markitdown = MarkItDown()
|
||||
result = markitdown.convert(file)
|
||||
with open(file_name, 'w') as f:
|
||||
f.write(result.text_content)
|
||||
await message.edit('Uploading...')
|
||||
await client.send_document(message.chat.id, file_name, reply_to_message_id=message.reply_to_message.id)
|
||||
os.remove(file)
|
||||
os.remove(file_name)
|
||||
await message.delete()
|
||||
else:
|
||||
await message.edit('Reply to a document to convert it to Markdown.')
|
||||
|
||||
|
||||
modules_help['markitdown'] = {'markitdown': 'Convert a document to Markdown.'}
|
||||
@@ -0,0 +1,65 @@
|
||||
# Moon-Userbot - telegram userbot
|
||||
# Copyright (C) 2020-present Moon Userbot Organization
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
from pyrogram import Client, filters
|
||||
from pyrogram.types import Message
|
||||
from pyrogram.types.user_and_chats.user import Link
|
||||
from utils.misc import modules_help, prefix
|
||||
|
||||
|
||||
def custom_mention(user, custom_text):
|
||||
return Link(
|
||||
f'tg://user?id={user.id}',
|
||||
custom_text,
|
||||
user._client.parse_mode,
|
||||
)
|
||||
|
||||
|
||||
@Client.on_message(filters.command('mention', prefix) & filters.me)
|
||||
async def example_edit(client: Client, message: Message):
|
||||
chat_id = message.chat.id
|
||||
if message.reply_to_message and not len(message.text.split()) > 1:
|
||||
user = message.reply_to_message.from_user
|
||||
custom_text = message.text.split(maxsplit=1)[1] if len(message.text.split()) > 1 else None
|
||||
if custom_text:
|
||||
await message.edit(custom_mention(user, custom_text))
|
||||
else:
|
||||
await message.delete()
|
||||
await client.send_message(chat_id, user.mention)
|
||||
else:
|
||||
if len(message.text.split()) > 1:
|
||||
user_id = message.text.split()[1]
|
||||
if user_id.isdigit():
|
||||
text = message.text.split(maxsplit=2)[2] if len(message.text.split()) > 2 else None
|
||||
if text:
|
||||
men = Link(f'tg://user?id={user_id}', text, client.parse_mode)
|
||||
else:
|
||||
men = (await client.get_users(user_id)).mention
|
||||
await message.edit(men)
|
||||
else:
|
||||
await message.edit('Invalid user_id')
|
||||
await message.delete()
|
||||
else:
|
||||
await message.edit('Reply to a message or provide a user_id')
|
||||
await message.delete()
|
||||
|
||||
|
||||
modules_help['mention'] = {
|
||||
'mention': 'Mention the user you replied to.',
|
||||
'mention [custom_text]': 'Mention the user you replied to with custom text.',
|
||||
'mention [user_id] [custom_text]': 'Mention a user by their user_id with custom text.',
|
||||
'mention [user_id]': 'Mention a user by their user_id.',
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
# original module https://raw.githubusercontent.com/KeyZenD/modules/master/MirrorFlipV2.py | t.me/the_kzd
|
||||
import os
|
||||
|
||||
from pyrogram import Client, enums, filters
|
||||
from pyrogram.types import Message
|
||||
from utils.misc import modules_help, prefix
|
||||
from utils.scripts import import_library
|
||||
|
||||
PIL = import_library('PIL', 'pillow')
|
||||
from PIL import Image, ImageOps # noqa: E402
|
||||
|
||||
|
||||
async def make(client, message, o):
|
||||
reply = message.reply_to_message
|
||||
if reply.photo or reply.sticker:
|
||||
if reply.photo:
|
||||
downloads = await client.download_media(reply.photo.file_id)
|
||||
else:
|
||||
downloads = await client.download_media(reply.sticker.file_id)
|
||||
path = f'{downloads}'
|
||||
img = Image.open(path)
|
||||
await message.delete()
|
||||
w, h = img.size
|
||||
if o in [1, 2]:
|
||||
if o == 2:
|
||||
img = ImageOps.mirror(img)
|
||||
part = img.crop([0, 0, w // 2, h])
|
||||
img = ImageOps.mirror(img)
|
||||
else:
|
||||
if o == 4:
|
||||
img = ImageOps.flip(img)
|
||||
part = img.crop([0, 0, w, h // 2])
|
||||
img = ImageOps.flip(img)
|
||||
img.paste(part, (0, 0))
|
||||
img.save(path)
|
||||
if reply.photo:
|
||||
return await reply.reply_photo(photo=path)
|
||||
elif reply.sticker:
|
||||
return await reply.reply_sticker(sticker=path)
|
||||
os.remove(path)
|
||||
|
||||
return await message.edit('<b>Need to answer the photo/sticker</b>', parse_mode=enums.ParseMode.HTML)
|
||||
|
||||
|
||||
@Client.on_message(filters.command(['ll', 'rr', 'dd', 'uu'], prefix) & filters.me)
|
||||
async def mirror_flip(client: Client, message: Message):
|
||||
await message.edit('<b>Processing...</b>', parse_mode=enums.ParseMode.HTML)
|
||||
param = {'ll': 1, 'rr': 2, 'dd': 3, 'uu': 4}[message.command[0]]
|
||||
await make(client, message, param)
|
||||
|
||||
|
||||
modules_help['mirror_flip'] = {
|
||||
'll [reply on photo or sticker]*': 'reflects the left side',
|
||||
'rr [reply on photo or sticker]*': 'reflects the right side',
|
||||
'uu [reply on photo or sticker]*': 'reflects the top',
|
||||
'dd [reply on photo or sticker]*': 'reflects the bottom',
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
from os import listdir
|
||||
|
||||
from pyrogram import Client, enums, filters
|
||||
from pyrogram.types import Message
|
||||
|
||||
# noinspection PyUnresolvedReferences
|
||||
from utils.misc import modules_help, prefix
|
||||
|
||||
# noinspection PyUnresolvedReferences
|
||||
from utils.scripts import format_exc
|
||||
|
||||
|
||||
@Client.on_message(filters.command(['lback'], prefix) & filters.me)
|
||||
async def backup_database_cmd(_: Client, message: Message):
|
||||
"""
|
||||
Backup the database.
|
||||
"""
|
||||
if len(message.command) == 1:
|
||||
await message.edit("[😇] I think you didn't specify the name of the bot.")
|
||||
return
|
||||
await message.edit_text("<b>I'm copying the database...</b>", parse_mode=enums.ParseMode.HTML)
|
||||
try:
|
||||
name = message.command[1].lower()
|
||||
folders = listdir('/root/')
|
||||
if name not in folders:
|
||||
await message.edit('[😇] There is no such bot in the root folder.')
|
||||
return
|
||||
folder = listdir('/root/' + name)
|
||||
for file in folder:
|
||||
if file.endswith(('.db', '.sqlite', '.sqlite3')):
|
||||
await message.reply_document(
|
||||
document='/root/' + name + '/' + file,
|
||||
caption='<code>Bot Database <b>' + name + '</b></code>',
|
||||
parse_mode=enums.ParseMode.HTML,
|
||||
)
|
||||
return await message.delete()
|
||||
folder = listdir('/root/' + name + '/assets')
|
||||
for file in folder:
|
||||
if file.endswith(('.db', '.sqlite', '.sqlite3')):
|
||||
await message.reply_document(
|
||||
document='/root/' + name + '/assets/' + file,
|
||||
caption='<code>Bot Database <b>' + name + '</b></code>',
|
||||
parse_mode=enums.ParseMode.HTML,
|
||||
)
|
||||
return await message.delete()
|
||||
await message.edit('[😇] Database not found.')
|
||||
except Exception as ex:
|
||||
await message.edit_text(
|
||||
f'Failed to back up the database!\n\n{format_exc(ex)}',
|
||||
parse_mode=enums.ParseMode.HTML,
|
||||
)
|
||||
|
||||
|
||||
modules_help['autobackup'] = {
|
||||
'lback [name]*': '<b>Backup database from folder</b>',
|
||||
'lbackall': '<b>Backup all databases</b>',
|
||||
}
|
||||
@@ -0,0 +1,165 @@
|
||||
# Moon-Userbot - telegram userbot
|
||||
# Copyright (C) 2020-present Moon Userbot Organization
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
from pyrogram import Client, filters
|
||||
from pyrogram.errors import MessageTooLong
|
||||
from pyrogram.types import Message
|
||||
from utils.db import db
|
||||
from utils.misc import modules_help, prefix
|
||||
|
||||
|
||||
def addtrg(channel_id):
|
||||
channel_ids = db.get('custom.autofwd', 'chatto', default=[])
|
||||
if channel_id not in channel_ids:
|
||||
channel_ids.append(channel_id)
|
||||
db.set('custom.autofwd', 'chatto', channel_ids)
|
||||
|
||||
|
||||
def rmtrg(channel_id):
|
||||
channel_ids = db.get('custom.autofwd', 'chatto', default=[])
|
||||
if channel_id in channel_ids:
|
||||
channel_ids.remove(channel_id)
|
||||
db.set('custom.autofwd', 'chatto', channel_ids)
|
||||
|
||||
|
||||
def addsrc(channel_id):
|
||||
channel_ids = db.get('custom.autofwd', 'chatsrc', default=[])
|
||||
if channel_id not in channel_ids:
|
||||
channel_ids.append(channel_id)
|
||||
db.set('custom.autofwd', 'chatsrc', channel_ids)
|
||||
|
||||
|
||||
def rmsrc(channel_id):
|
||||
channel_ids = db.get('custom.autofwd', 'chatsrc', default=[])
|
||||
if channel_id in channel_ids:
|
||||
channel_ids.remove(channel_id)
|
||||
db.set('custom.autofwd', 'chatsrc', channel_ids)
|
||||
|
||||
|
||||
def getfwd_data():
|
||||
source_chats = db.get('custom.autofwd', 'chatsrc')
|
||||
target_chats = db.get('custom.autofwd', 'chatto')
|
||||
return source_chats, target_chats
|
||||
|
||||
|
||||
@Client.on_message(filters.command(['addfwd_src', 'addfwd_to'], prefix) & filters.me)
|
||||
async def addfwd(_, message: Message):
|
||||
if message.command[0] == 'addfwd_src':
|
||||
if len(message.command) > 1:
|
||||
channel_id = message.text.split(maxsplit=1)[1]
|
||||
if not channel_id.startswith('-100'):
|
||||
channel_id = '-100' + channel_id
|
||||
# chat id should be integer
|
||||
if not channel_id.isdigit():
|
||||
try:
|
||||
channel_id = int(channel_id)
|
||||
except Exception:
|
||||
return await message.edit_text('Chat id should be in integer')
|
||||
addsrc(channel_id=channel_id)
|
||||
await message.edit_text(f'Auto Forwarding Enabled for Chat with id: <code>{channel_id}</code>')
|
||||
else:
|
||||
await message.edit_text('Chat id not provided!')
|
||||
return
|
||||
elif message.command[0] == 'addfwd_to':
|
||||
if len(message.command) > 1:
|
||||
channel_id = message.text.split(maxsplit=1)[1]
|
||||
if not channel_id.startswith('-100'):
|
||||
channel_id = '-100' + channel_id
|
||||
# chat id should be integer
|
||||
if not channel_id.isdigit():
|
||||
try:
|
||||
channel_id = int(channel_id)
|
||||
except Exception:
|
||||
return await message.edit_text('Chat id should be in integer')
|
||||
addtrg(channel_id=channel_id)
|
||||
await message.edit_text(f'Auto Forwarding Enabled to Chat with id: <code>{channel_id}</code>')
|
||||
else:
|
||||
await message.edit_text('Chat id not provided!')
|
||||
return
|
||||
|
||||
|
||||
@Client.on_message(filters.command(['delfwd_src', 'delfwd_to'], prefix) & filters.me)
|
||||
async def delfwd(_, message: Message):
|
||||
if message.command[0] == 'delfwd_src':
|
||||
if len(message.command) > 1:
|
||||
channel_id = message.text.split(maxsplit=1)[1]
|
||||
if not channel_id.startswith('-100'):
|
||||
channel_id = '-100' + channel_id
|
||||
# chat id should be integer
|
||||
if not channel_id.isdigit():
|
||||
try:
|
||||
channel_id = int(channel_id)
|
||||
except Exception:
|
||||
return await message.edit_text('Chat id should be in integer')
|
||||
rmsrc(channel_id=channel_id)
|
||||
await message.edit_text(f'Auto Forwarding Disabled for Chat with id: <code>{channel_id}</code>')
|
||||
else:
|
||||
await message.edit_text('Chat id not provided!')
|
||||
return
|
||||
elif message.command[0] == 'delfwd_to':
|
||||
if len(message.command) > 1:
|
||||
channel_id = message.text.split(maxsplit=1)[1]
|
||||
if not channel_id.startswith('-100'):
|
||||
channel_id = '-100' + channel_id
|
||||
# chat id should be integer
|
||||
if not channel_id.isdigit():
|
||||
try:
|
||||
channel_id = int(channel_id)
|
||||
except Exception:
|
||||
return await message.edit_text('Chat id should be in integer')
|
||||
rmtrg(channel_id=channel_id)
|
||||
await message.edit_text(f'Auto Forwarding Disabled to Chat with id: <code>{channel_id}</code>')
|
||||
else:
|
||||
await message.edit_text('Chat id not provided!')
|
||||
return
|
||||
|
||||
|
||||
@Client.on_message(filters.command('autofwd', prefix) & filters.me)
|
||||
async def autofwd(_, message: Message):
|
||||
source_chats, target_chats = getfwd_data()
|
||||
return await message.edit_text(f'Source Chats: {source_chats}\nTarget Chats: {target_chats}')
|
||||
|
||||
|
||||
@Client.on_message(filters.channel | filters.group)
|
||||
async def autofwd_main(client: Client, message: Message):
|
||||
chat_id = message.chat.id
|
||||
source_chats = db.get('custom.autofwd', 'chatsrc')
|
||||
target_chats = db.get('custom.autofwd', 'chatto')
|
||||
|
||||
if source_chats is not None and chat_id in source_chats and target_chats is not None:
|
||||
for chat in target_chats:
|
||||
try:
|
||||
await message.copy(chat)
|
||||
except Exception as e:
|
||||
try:
|
||||
await client.send_message(
|
||||
'me',
|
||||
f'Auto Forwarding Failed for Chat with id: <code>{chat_id}</code> to <code>{chat}</code>\n\n{e}',
|
||||
)
|
||||
except MessageTooLong:
|
||||
await client.send_message(
|
||||
'me',
|
||||
f'Auto Forwarding Failed for Chat with id: <code>{chat_id}</code> to <code>{chat}</code>, Please check logs!',
|
||||
)
|
||||
|
||||
|
||||
modules_help['autofwd'] = {
|
||||
'autofwd': 'Retrieve Data of auto fwd',
|
||||
'addfwd_src [channel_id]*': 'Enable auto forwarding for a channel',
|
||||
'addfwd_to [channel_id]*': 'Enable auto forwarding to a channel',
|
||||
'delfwd_src [channel_id]*': 'Disable auto forwarding for a channel',
|
||||
'delfwd_to [channel_id]*': 'Disable auto forwarding to a channel',
|
||||
}
|
||||
@@ -0,0 +1,230 @@
|
||||
import os
|
||||
import shutil
|
||||
|
||||
from pyrogram import Client, enums, filters
|
||||
from pyrogram.types import Message
|
||||
from utils import config
|
||||
from utils.db import db
|
||||
|
||||
# noinspection PyUnresolvedReferences
|
||||
from utils.misc import modules_help, prefix
|
||||
from utils.scripts import format_exc, restart
|
||||
|
||||
if config.db_type in ['mongodb', 'mongo']:
|
||||
import bson
|
||||
|
||||
|
||||
def dump_mongo(collections, path, db_):
|
||||
for coll in collections:
|
||||
with open(os.path.join(path, f'{coll}.bson'), 'wb+') as f:
|
||||
for doc in db_[coll].find():
|
||||
f.write(bson.BSON.encode(doc))
|
||||
|
||||
|
||||
def restore_mongo(path, db_):
|
||||
for coll in os.listdir(path):
|
||||
if coll.endswith('.bson'):
|
||||
with open(os.path.join(path, coll), 'rb+') as f:
|
||||
db_[coll.split('.')[0]].insert_many(bson.decode_all(f.read()))
|
||||
|
||||
|
||||
@Client.on_message(filters.command(['backup', 'back'], prefix) & filters.me)
|
||||
async def backup(client: Client, message: Message):
|
||||
"""
|
||||
Backup the database
|
||||
"""
|
||||
try:
|
||||
if not os.path.exists('backups/'):
|
||||
os.mkdir('backups/')
|
||||
|
||||
await message.edit('<b>Backing up database...</b>', parse_mode=enums.ParseMode.HTML)
|
||||
|
||||
if config.db_type in ['mongo', 'mongodb']:
|
||||
dump_mongo(db._database.list_collection_names(), 'backups/', db._database)
|
||||
return await message.edit(
|
||||
'<b>Database backed up to:</b> <code>backups/</code> folder',
|
||||
parse_mode=enums.ParseMode.HTML,
|
||||
)
|
||||
else:
|
||||
shutil.copy(config.db_name, f'backups/{config.db_name}')
|
||||
await client.send_document(
|
||||
'me',
|
||||
caption='<b>Database backup complete!\nType: </b>'
|
||||
'<code>.restore</code> in response to this message to restore the database.',
|
||||
document=f'backups/{config.db_name}',
|
||||
parse_mode=enums.ParseMode.HTML,
|
||||
)
|
||||
return await message.edit(
|
||||
'<b>Database backed up successfully! <code>(Check your favorites)</code></b>',
|
||||
parse_mode=enums.ParseMode.HTML,
|
||||
)
|
||||
except Exception as e:
|
||||
await message.edit(format_exc(e), parse_mode=enums.ParseMode.HTML)
|
||||
|
||||
|
||||
@Client.on_message(filters.command(['restore', 'res'], prefix) & filters.me)
|
||||
async def restore(client: Client, message: Message):
|
||||
"""
|
||||
Restore the database
|
||||
"""
|
||||
try:
|
||||
await message.edit('<b>Restoring database...</b>', parse_mode=enums.ParseMode.HTML)
|
||||
if config.db_type in ['mongo', 'mongodb']:
|
||||
restore_mongo('backups/', db._database)
|
||||
return await message.edit(
|
||||
'<b>Database restored from:</b> <code>backups/</code> folder',
|
||||
parse_mode=enums.ParseMode.HTML,
|
||||
)
|
||||
else:
|
||||
if not message.reply_to_message or not message.reply_to_message.document:
|
||||
return await message.edit(
|
||||
'<b>Reply to a document to restore the database.</b>',
|
||||
parse_mode=enums.ParseMode.HTML,
|
||||
)
|
||||
elif not message.reply_to_message.document.file_name.casefold().endswith(('.db', '.sqlite', '.sqlite3')):
|
||||
return await message.edit(
|
||||
'<b>Reply to a database file to restore the database.</b>',
|
||||
parse_mode=enums.ParseMode.HTML,
|
||||
)
|
||||
await message.reply_to_message.download(f'backups/{message.reply_to_message.document.file_name}')
|
||||
shutil.copy(f'backups/{message.reply_to_message.document.file_name}', config.db_name)
|
||||
await message.edit(
|
||||
'<b>Database restored successfully!</b>',
|
||||
parse_mode=enums.ParseMode.HTML,
|
||||
)
|
||||
restart()
|
||||
except Exception as e:
|
||||
await message.edit(format_exc(e), parse_mode=enums.ParseMode.HTML)
|
||||
|
||||
|
||||
@Client.on_message(filters.command(['backupmods', 'bms'], prefix) & filters.me)
|
||||
async def backupmods(client: Client, message: Message):
|
||||
"""
|
||||
Backup the modules
|
||||
"""
|
||||
try:
|
||||
if not os.path.exists('backups/'):
|
||||
os.mkdir('backups/')
|
||||
|
||||
await message.edit('<b>Backing up modules...</b>', parse_mode=enums.ParseMode.HTML)
|
||||
|
||||
from utils.misc import modules_help
|
||||
|
||||
for mod in modules_help:
|
||||
if os.path.isfile(f'modules/custom_modules/{mod}.py'):
|
||||
f = open(f'backups/{mod}.py', 'wb')
|
||||
f.write(open(f'modules/custom_modules/{mod}.py', 'rb').read())
|
||||
await message.edit(
|
||||
text='<b>All modules backed up to:</b> <code>backups/</code> folder',
|
||||
parse_mode=enums.ParseMode.HTML,
|
||||
)
|
||||
except Exception as e:
|
||||
await message.edit(format_exc(e), parse_mode=enums.ParseMode.HTML)
|
||||
|
||||
|
||||
@Client.on_message(filters.command(['backupmod', 'bm'], prefix) & filters.me)
|
||||
async def backupmod(client: Client, message: Message):
|
||||
"""
|
||||
Backup the module
|
||||
"""
|
||||
try:
|
||||
if not os.path.exists('backups/'):
|
||||
os.mkdir('backups/')
|
||||
|
||||
try:
|
||||
mod = message.text.split(maxsplit=1)[1].split('.')[0]
|
||||
except Exception:
|
||||
return await message.edit(
|
||||
f'<b>Usage:</b> <code>{prefix}backupmod [module]</code>',
|
||||
parse_mode=enums.ParseMode.HTML,
|
||||
)
|
||||
|
||||
await message.edit('<b>Backing up module...</b>', parse_mode=enums.ParseMode.HTML)
|
||||
|
||||
if os.path.isfile(f'modules/custom_modules/{mod}.py'):
|
||||
f = open(f'backups/{mod}.py', 'wb')
|
||||
f.write(open(f'modules/custom_modules/{mod}.py', 'rb').read())
|
||||
else:
|
||||
return await message.edit(
|
||||
f'<b>Module <code>{mod}</code> not found.</b>',
|
||||
parse_mode=enums.ParseMode.HTML,
|
||||
)
|
||||
await message.reply_document(
|
||||
document=f'backups/{mod}.py',
|
||||
caption=f'<b>Module <code>{mod}</code> backed up to:</b> <code>backups/</code> folder',
|
||||
parse_mode=enums.ParseMode.HTML,
|
||||
)
|
||||
except Exception as e:
|
||||
await message.edit(format_exc(e), parse_mode=enums.ParseMode.HTML)
|
||||
|
||||
|
||||
@Client.on_message(filters.command(['restoremod', 'resmod'], prefix) & filters.me)
|
||||
async def restoremod(client: Client, message: Message):
|
||||
"""
|
||||
Restore the module
|
||||
"""
|
||||
try:
|
||||
if not os.path.exists('backups/'):
|
||||
os.mkdir('backups/')
|
||||
|
||||
try:
|
||||
mod = message.text.split(maxsplit=1)[1].split('.')[0]
|
||||
except Exception:
|
||||
return await message.edit(
|
||||
f'<b>Usage:</b> <code>{prefix}restoremod [module]</code>',
|
||||
parse_mode=enums.ParseMode.HTML,
|
||||
)
|
||||
|
||||
await message.edit('<b>Restoring module...</b>', parse_mode=enums.ParseMode.HTML)
|
||||
|
||||
if os.path.isfile(f'backups/{mod}.py'):
|
||||
f = open(f'modules/custom_modules/{mod}.py', 'wb')
|
||||
f.write(open(f'backups/{mod}.py', 'rb').read())
|
||||
else:
|
||||
return await message.edit(
|
||||
f'<b>Module <code>{mod}</code> not found.</b>',
|
||||
parse_mode=enums.ParseMode.HTML,
|
||||
)
|
||||
await message.edit(
|
||||
f'<b>Module <code>{mod}</code> restored successfully!</b>',
|
||||
parse_mode=enums.ParseMode.HTML,
|
||||
)
|
||||
restart()
|
||||
except Exception as e:
|
||||
await message.edit(format_exc(e), parse_mode=enums.ParseMode.HTML)
|
||||
|
||||
|
||||
@Client.on_message(filters.command(['restoremods', 'resmods'], prefix) & filters.me)
|
||||
async def restoremods(client: Client, message: Message):
|
||||
"""
|
||||
Restore the modules
|
||||
"""
|
||||
try:
|
||||
if not os.path.exists('backups/'):
|
||||
os.mkdir('backups/')
|
||||
|
||||
await message.edit('<b>Restoring modules...</b>', parse_mode=enums.ParseMode.HTML)
|
||||
|
||||
for mod in os.listdir('backups/'):
|
||||
if mod.endswith('.py'):
|
||||
if os.path.isfile(f'modules/{mod}'):
|
||||
continue
|
||||
f = open(f'modules/custom_modules/{mod}', 'wb')
|
||||
f.write(open(f'backups/{mod}', 'rb').read())
|
||||
await message.edit(
|
||||
text='<b>All modules restored from:</b> <code>backups/</code> folder',
|
||||
parse_mode=enums.ParseMode.HTML,
|
||||
)
|
||||
restart()
|
||||
except Exception as e:
|
||||
await message.edit(format_exc(e), parse_mode=enums.ParseMode.HTML)
|
||||
|
||||
|
||||
modules_help['backup'] = {
|
||||
'backup': '<b>Backup database</b>',
|
||||
'restore [reply]': '<b>Restore database</b>',
|
||||
'backupmod [name]': '<b>Backup mod</b>',
|
||||
'backupmods': '<b>Backup all mods</b>',
|
||||
'resmod [name]': '<b>Restore mod</b>',
|
||||
'resmods': '<b>Restore all mods</b>',
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
import requests
|
||||
from pyrogram import Client, filters
|
||||
from utils.misc import modules_help, prefix
|
||||
from utils.scripts import format_exc, import_library
|
||||
|
||||
pcp = import_library('pubchempy')
|
||||
|
||||
INATURALIST_API_URL = 'https://api.inaturalist.org/v1/observations'
|
||||
|
||||
|
||||
def get_marine_life_details(species_name):
|
||||
params = {
|
||||
'taxon_name': species_name,
|
||||
'quality_grade': 'research',
|
||||
'iconic_taxa': 'Mollusca,Fish,Crustacea',
|
||||
'per_page': 1,
|
||||
}
|
||||
|
||||
response = requests.get(INATURALIST_API_URL, params=params, timeout=10)
|
||||
|
||||
if response.status_code == 200:
|
||||
data = response.json()
|
||||
if data['total_results'] > 0:
|
||||
observation = data['results'][0]
|
||||
species = observation['taxon']['name']
|
||||
common_name = observation['taxon']['preferred_common_name']
|
||||
photo_url = observation['photos'][0]['url'] if observation['photos'] else 'No photo available'
|
||||
description = observation.get('description', 'No description available.')
|
||||
return {
|
||||
'species': species,
|
||||
'common_name': common_name,
|
||||
'photo_url': photo_url,
|
||||
'description': description,
|
||||
}
|
||||
else:
|
||||
return {'error': 'No marine life found for this species.'}
|
||||
else:
|
||||
return {'error': f'Error {response.status_code}: Unable to connect to iNaturalist API.'}
|
||||
|
||||
|
||||
@Client.on_message(filters.command('camistry', prefix) & filters.me)
|
||||
async def fetch_chemical_data_with_visual(_, message):
|
||||
query = ' '.join(message.text.split()[1:]) # Combine query words properly
|
||||
|
||||
try:
|
||||
# Fetch chemical data by name
|
||||
results = pcp.get_compounds(query, 'name', record_type='3d')
|
||||
|
||||
if results:
|
||||
compound = results[0]
|
||||
|
||||
# Send chemical information without SMILES structure
|
||||
info = (
|
||||
f'<b>Chemical Data for {compound.iupac_name}</b>\n\n'
|
||||
f'<b>Molecular Formula:</b> <code>{compound.molecular_formula}</code>\n'
|
||||
f'<b>Molecular Weight:</b> <code>{compound.molecular_weight}</code>\n'
|
||||
f'<b>CID:</b> <code>{compound.cid}</code>\n'
|
||||
f'<b>Synonyms:</b> <code>{", ".join(compound.synonyms[:5])}</code>\n'
|
||||
)
|
||||
await message.edit_text(info)
|
||||
else:
|
||||
await message.edit_text(f"No chemical data found for the query: '{query}'")
|
||||
|
||||
except pcp.PubChemHTTPError as http_err:
|
||||
await message.edit_text(f'HTTP error occurred: {format_exc(http_err)}')
|
||||
|
||||
except Exception as e:
|
||||
await message.edit_text(f'An error occurred: {format_exc(e)}')
|
||||
|
||||
|
||||
@Client.on_message(filters.command('marinelife', prefix) & filters.me)
|
||||
async def marine_life_command(_, message):
|
||||
if len(message.command) < 2:
|
||||
await message.edit_text(f'Please specify a species name. Example: {prefix}marinelife dolphin')
|
||||
return
|
||||
|
||||
species_name = ' '.join(message.command[1:])
|
||||
marine_life = get_marine_life_details(species_name)
|
||||
|
||||
if 'error' in marine_life:
|
||||
await message.edit_text(marine_life['error'])
|
||||
else:
|
||||
reply_text = (
|
||||
f'<b>Species</b>: <code>{marine_life["species"]}</code>\n'
|
||||
f'<b>Common Name</b>: <code>{marine_life["common_name"]}</code>\n'
|
||||
f'<b>Description</b>: <code>{marine_life["description"]}</code>\n'
|
||||
f"<a href='{marine_life['photo_url']}'>Photo</a>"
|
||||
)
|
||||
await message.edit_text(reply_text)
|
||||
|
||||
|
||||
modules_help['cama'] = {
|
||||
'camistry [text]': ' getting camicale info',
|
||||
'marinelife [text]': ' getting marinelife info',
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
import asyncio
|
||||
import os
|
||||
from collections import defaultdict
|
||||
|
||||
from pyrogram import Client, filters
|
||||
from pyrogram.errors import (
|
||||
FileReferenceExpired,
|
||||
FileReferenceInvalid,
|
||||
TopicClosed,
|
||||
TopicDeleted,
|
||||
)
|
||||
from pyrogram.types import Message
|
||||
from utils.db import db
|
||||
from utils.misc import modules_help, prefix
|
||||
|
||||
mlog_enabled = filters.create(lambda _, __, ___: db.get('custom.mlog', 'status', False))
|
||||
|
||||
# Media cache and processing tasks
|
||||
user_media_cache = defaultdict(list)
|
||||
media_processing_tasks = {}
|
||||
|
||||
|
||||
# Helper to get group-specific data
|
||||
def get_group_data(group_id):
|
||||
return db.get('custom.mlog', str(group_id), {})
|
||||
|
||||
|
||||
# Helper to update group-specific data
|
||||
def update_group_data(group_id, data):
|
||||
db.set('custom.mlog', str(group_id), data)
|
||||
|
||||
|
||||
@Client.on_message(filters.command(['mlog'], prefix) & filters.me)
|
||||
async def mlog(_, message: Message):
|
||||
if len(message.command) < 2 or message.command[1].lower() not in ['on', 'off']:
|
||||
return await message.edit(f'<b>Usage:</b> <code>{prefix}mlog [on/off]</code>')
|
||||
|
||||
status = message.command[1].lower() == 'on'
|
||||
db.set('custom.mlog', 'status', status)
|
||||
await message.edit(f'<b>Media logging is now {"enabled" if status else "disabled"}</b>')
|
||||
|
||||
|
||||
@Client.on_message(filters.command(['msetchat'], prefix) & filters.me)
|
||||
async def set_chat(_, message: Message):
|
||||
if len(message.command) < 2:
|
||||
return await message.edit(f'<b>Usage:</b> <code>{prefix}msetchat [chat_id]</code>')
|
||||
|
||||
try:
|
||||
chat_id = message.command[1]
|
||||
chat_id = int('-100' + chat_id if not chat_id.startswith('-100') else chat_id)
|
||||
db.set('custom.mlog', 'chat', chat_id)
|
||||
await message.edit(f'<b>Chat ID set to {chat_id}</b>')
|
||||
except ValueError:
|
||||
await message.edit('<b>Invalid chat ID</b>')
|
||||
|
||||
|
||||
@Client.on_message(mlog_enabled & filters.incoming & filters.private & filters.media & ~filters.me & ~filters.bot)
|
||||
async def media_log(client: Client, message: Message):
|
||||
user_id = message.from_user.id
|
||||
user_media_cache[user_id].append(message)
|
||||
|
||||
if user_id not in media_processing_tasks:
|
||||
media_processing_tasks[user_id] = asyncio.create_task(process_media(client, message.from_user))
|
||||
|
||||
|
||||
async def process_media(client: Client, user):
|
||||
await asyncio.sleep(5) # Wait to group incoming media
|
||||
user_id = user.id
|
||||
|
||||
me = await client.get_me()
|
||||
if user_id == me.id:
|
||||
return
|
||||
|
||||
chat_id = db.get('custom.mlog', 'chat')
|
||||
if not chat_id:
|
||||
return await client.send_message(
|
||||
'me',
|
||||
f'Media Logger is on, but no Chat ID is set. Use {prefix}msetchat to set it.',
|
||||
)
|
||||
|
||||
group_data = get_group_data(chat_id)
|
||||
user_topics = group_data.get('user_topics', {})
|
||||
topic_id = user_topics.get(str(user_id)) # Fetch user's topic ID if it exists
|
||||
|
||||
if not topic_id:
|
||||
topic = await client.create_forum_topic(chat_id, user.first_name)
|
||||
topic_id = topic.id
|
||||
user_topics[str(user_id)] = topic_id # Store topic ID for this user
|
||||
update_group_data(chat_id, {'user_topics': user_topics})
|
||||
m = await client.send_message(
|
||||
chat_id=chat_id,
|
||||
message_thread_id=topic_id,
|
||||
text=f'<b>Chat Name:</b> {user.full_name}\n<b>User ID:</b> {user_id}\n<b>Username:</b> @{user.username or "N/A"}\n<b>Phone No:</b> +{user.phone_number or "N/A"}',
|
||||
)
|
||||
await m.pin()
|
||||
|
||||
messages_to_process = user_media_cache.pop(user_id, [])
|
||||
for media_message in messages_to_process:
|
||||
try:
|
||||
await media_message.copy(chat_id=chat_id, message_thread_id=topic_id)
|
||||
await asyncio.sleep(1) # Delay between sending media
|
||||
except (FileReferenceExpired, FileReferenceInvalid):
|
||||
# Handle self-destruct photos and video notes
|
||||
await handle_self_destruct_media(client, media_message, chat_id, topic_id)
|
||||
except TopicDeleted:
|
||||
topic = await client.create_forum_topic(chat_id, user.first_name)
|
||||
topic_id = topic.id
|
||||
user_topics[str(user_id)] = topic_id # Update the new topic ID
|
||||
update_group_data(chat_id, {'user_topics': user_topics})
|
||||
await client.send_message(
|
||||
chat_id=chat_id,
|
||||
message_thread_id=topic_id,
|
||||
text=f'<b>Chat Name:</b> {user.full_name}\n<b>User ID:</b> {user_id}\n<b>Username:</b> @{user.username or "N/A"}\n<b>Phone No:</b> +{user.phone_number or "N/A"}',
|
||||
)
|
||||
await handle_self_destruct_media(client, media_message, chat_id, topic_id)
|
||||
except TopicClosed:
|
||||
await client.reopen_forum_topic(chat_id=chat_id, topic_id=topic_id)
|
||||
await media_message.copy(chat_id=chat_id, message_thread_id=topic_id)
|
||||
|
||||
media_processing_tasks.pop(user_id, None)
|
||||
|
||||
|
||||
async def handle_self_destruct_media(client: Client, message: Message, chat_id: int, topic_id: int):
|
||||
try:
|
||||
# Download the self-destructing media
|
||||
file_path = await message.download()
|
||||
if message.photo:
|
||||
await client.send_photo(chat_id, file_path, message_thread_id=topic_id)
|
||||
elif message.video_note:
|
||||
await client.send_video(chat_id, file_path, message_thread_id=topic_id)
|
||||
os.remove(file_path) # Clean up after sending
|
||||
except Exception as e:
|
||||
print(f'Error handling self-destructing media: {e}')
|
||||
|
||||
|
||||
modules_help['mlog'] = {
|
||||
'mlog [on/off]': 'Enable or disable media logging',
|
||||
'msetchat [chat_id]': 'Set the chat ID for media logging',
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
from datetime import datetime
|
||||
|
||||
import aiohttp
|
||||
from pyrogram import Client, filters
|
||||
from pyrogram.types import Message
|
||||
from utils.misc import modules_help, prefix
|
||||
|
||||
# Aladhan API credentials
|
||||
ALADHAN_API_URL = 'https://api.aladhan.com/v1/timingsByCity'
|
||||
DEFAULT_METHOD = 2 # Islamic Society of North America
|
||||
DEFAULT_CITY = 'Lahore'
|
||||
DEFAULT_COUNTRY = 'PK'
|
||||
|
||||
|
||||
async def fetch_namaz_times(city_name: str, country_name: str) -> dict:
|
||||
params = {'city': city_name, 'country': country_name, 'method': DEFAULT_METHOD}
|
||||
async with aiohttp.ClientSession() as session:
|
||||
try:
|
||||
async with session.get(ALADHAN_API_URL, params=params) as response:
|
||||
response.raise_for_status()
|
||||
return await response.json()
|
||||
except Exception as e:
|
||||
return {'error': str(e)}
|
||||
|
||||
|
||||
def format_time_12hr(time_str: str) -> str:
|
||||
try:
|
||||
# Split time into hours and minutes
|
||||
hours, minutes = map(int, time_str.split(':'))
|
||||
# Convert to 12-hour format
|
||||
period = 'AM' if hours < 12 else 'PM'
|
||||
if hours == 0:
|
||||
hours = 12
|
||||
elif hours > 12:
|
||||
hours -= 12
|
||||
elif hours == 12:
|
||||
period = 'PM'
|
||||
return f'{hours}:{minutes:02d} {period}'
|
||||
except Exception as e:
|
||||
return f'Error formatting time: {str(e)}'
|
||||
|
||||
|
||||
@Client.on_message(filters.command('prayer', prefix) & filters.me)
|
||||
async def namaz_times(client: Client, message: Message):
|
||||
if message.reply_to_message:
|
||||
city_name = message.reply_to_message.text
|
||||
country_name = DEFAULT_COUNTRY # Default to Pakistan if no country is provided
|
||||
else:
|
||||
args = message.text.split(maxsplit=2)
|
||||
if len(args) < 2:
|
||||
city_name = DEFAULT_CITY
|
||||
country_name = DEFAULT_COUNTRY
|
||||
elif len(args) == 2:
|
||||
city_name = args[1]
|
||||
country_name = DEFAULT_COUNTRY
|
||||
else:
|
||||
city_name = args[1]
|
||||
country_name = args[2]
|
||||
|
||||
data = await fetch_namaz_times(city_name, country_name)
|
||||
|
||||
if 'error' in data:
|
||||
result = f'<b>Error:</b> <i>{data["error"]}</i>'
|
||||
elif 'data' in data:
|
||||
timings = data['data']['timings']
|
||||
today = datetime.now().strftime('%Y-%m-%d')
|
||||
formatted_timings = {
|
||||
'Fajr': format_time_12hr(timings['Fajr']),
|
||||
'Dhuhr': format_time_12hr(timings['Dhuhr']),
|
||||
'Asr': format_time_12hr(timings['Asr']),
|
||||
'Maghrib': format_time_12hr(timings['Maghrib']),
|
||||
'Isha': format_time_12hr(timings['Isha']),
|
||||
}
|
||||
result = (
|
||||
f'<b>Prayer Times for {city_name}, {country_name} on {today}:</b>\n\n'
|
||||
f'<b>Fajr:</b> {formatted_timings["Fajr"]}\n'
|
||||
f'<b>Dhuhr:</b> {formatted_timings["Dhuhr"]}\n'
|
||||
f'<b>Asr:</b> {formatted_timings["Asr"]}\n'
|
||||
f'<b>Maghrib:</b> {formatted_timings["Maghrib"]}\n'
|
||||
f'<b>Isha:</b> {formatted_timings["Isha"]}\n'
|
||||
)
|
||||
else:
|
||||
result = '<b>Error:</b> <i>Unable to get prayer times for the specified location.</i>'
|
||||
|
||||
await message.edit_text(result)
|
||||
|
||||
|
||||
modules_help['namaz'] = {
|
||||
'prayer [city_name] [country_name]': 'Shows the prayer times. Default to Pakistan if no country is provided'
|
||||
}
|
||||
@@ -0,0 +1,519 @@
|
||||
# Moon-Userbot - telegram userbot
|
||||
# Copyright (C) 2020-present Moon Userbot Organization
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import base64
|
||||
import os
|
||||
from io import BytesIO
|
||||
|
||||
import aiofiles
|
||||
import aiohttp
|
||||
import requests
|
||||
from PIL import Image, ImageEnhance
|
||||
from pyrogram import Client, enums, filters
|
||||
from pyrogram.errors import MediaCaptionTooLong, MessageTooLong
|
||||
from pyrogram.types import InputMediaPhoto, Message
|
||||
from utils.misc import modules_help, prefix
|
||||
from utils.scripts import format_exc
|
||||
|
||||
url = 'https://api.safone.co'
|
||||
|
||||
headers = {
|
||||
'Accept-Language': 'en-US,en;q=0.9',
|
||||
'Connection': 'keep-alive',
|
||||
'DNT': '1',
|
||||
'Referer': 'https://api.safone.dev/docs',
|
||||
'Sec-Fetch-Dest': 'empty',
|
||||
'Sec-Fetch-Mode': 'cors',
|
||||
'Sec-Fetch-Site': 'same-origin',
|
||||
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36',
|
||||
'accept': 'application/json',
|
||||
'sec-ch-ua': '"Chromium";v="124", "Google Chrome";v="124", "Not-A.Brand";v="99"',
|
||||
'sec-ch-ua-mobile': '?0',
|
||||
'sec-ch-ua-platform': '"Linux"',
|
||||
}
|
||||
|
||||
|
||||
async def make_carbon(code):
|
||||
url = 'https://carbonara.solopov.dev/api/cook'
|
||||
|
||||
async with aiohttp.ClientSession() as session, 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
|
||||
|
||||
|
||||
async def telegraph(title, user_name, content):
|
||||
formatted_content = '<br>'.join(content.split('\n'))
|
||||
formatted_content = '<p>' + formatted_content + '</p>'
|
||||
|
||||
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, timeout=10)
|
||||
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, timeout=10)
|
||||
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, timeout=10).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'<b>Title:</b> <code>{title}</code>\n<b>Rating:</b> <code>{rating}</code>\n<b>IsFree:</b> <code>{IsFree}</code>\n<b>Price:</b> <code>{price}</code>\n<b>Package Name:</b> <code>{package_name}</code>\n<b>Genres:</b> <code>{genre}</code>\n<b>Developer:</b> <code>{developer}\n<b>Description:</b> {description}\n<b>Link:</b> {link}',
|
||||
)
|
||||
],
|
||||
)
|
||||
|
||||
except MediaCaptionTooLong:
|
||||
description = description[:850]
|
||||
await message.delete()
|
||||
await client.send_media_group(
|
||||
chat_id,
|
||||
[
|
||||
InputMediaPhoto(
|
||||
'coverImage.jpg',
|
||||
caption=f'<b>Title:</b> <code>{title}</code>\n<b>Rating:</b> <code>{rating}</code>\n<b>IsFree:</b> <code>{IsFree}</code>\n<b>Price:</b> <code>{price}</code>\n<b>Package Name:</b> <code>{package_name}</code>\n<b>Genres:</b> <code>{genre}</code>\n<b>Developer:</b> <code>{developer}\n<b>Description:</b> {description}\n<b>Link:</b> {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, timeout=10)
|
||||
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'<b>Title:</b> <code>{titles}</code>\n<b>Category:</b> <code>{categorys}</code>\n<b>Language:</b> <code>{languages}</code>\n<b>Size:</b> <code>{sizes}</code>\n<b>Genres:</b> <code>{genres}</code>\n<b>Description:</b> {descriptions}\n<b>Magnet Link:</b> <code>{links}</code><br>'
|
||||
results.append(r)
|
||||
|
||||
all_results_content = '<br>'.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, timeout=10).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"<b>Title:</b> <code>{title}</code>\n<b>Category:</b> <code>{category}</code>\n<b>Language:</b> <code>{language}</code>\n<b>Size:</b> <code>{size}</code>\n<b>Genres:</b> <code>{genre}</code>\n<b>Description:</b> {description}\n<b>Magnet Link:</b> <a href='{link_result}'>Click Here</a>\n<b>More Results:</b> <a href='{link_results}'>Click Here</a>",
|
||||
)
|
||||
],
|
||||
)
|
||||
else:
|
||||
await message.edit_text(
|
||||
f"<b>Title:</b> <code>{title}</code>\n<b>Category:</b> <code>{category}</code>\n<b>Language:</b> <code>{language}</code>\n<b>Size:</b> <code>{size}</code>\n<b>Genres:</b> <code>{genre}</code>\n<b>Description:</b> {description}\n<b>Magnet Link:</b> <a href='{link_result}'>Click Here</a>\n<b>More Results:</b> <a href='{link_results}'>Click Here</a>",
|
||||
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"<b>Title:</b> <code>{title}</code>\n<b>Category:</b> <code>{category}</code>\n<b>Language:</b> <code>{language}</code>\n<b>Size:</b> <code>{size}</code>\n<b>Genres:</b> <code>{genre}</code>\n<b>Description:</b> {description}\n<b>Magnet Link:</b> <a href='{link_result}'>Click Here</a>",
|
||||
)
|
||||
],
|
||||
)
|
||||
|
||||
except MessageTooLong:
|
||||
description = description[:150]
|
||||
await message.edit_text(
|
||||
f"<b>Title:</b> <code>{title}</code>\n<b>Category:</b> <code>{category}</code>\n<b>Language:</b> <code>{language}</code>\n<b>Size:</b> <code>{size}</code>\n<b>Genres:</b> <code>{genre}</code>\n<b>Description:</b> {description}\n<b>Magnet Link:</b> <a href='{link_result}'>Click Here</a>",
|
||||
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('stts', prefix) & filters.me)
|
||||
async def tts(client: Client, message: Message):
|
||||
characters = await voice_characters()
|
||||
await message.edit_text('<code>Please Wait...</code>')
|
||||
try:
|
||||
if len(message.command) > 2:
|
||||
character, prompt = message.text.split(maxsplit=2)[1:]
|
||||
if character not in characters:
|
||||
await message.edit_text(
|
||||
f'<b>Usage: </b><code>{prefix}tts [character]* [text/reply to text]*</code>\n <b>Available Characters:</b> <blockquote>{characters}</blockquote>'
|
||||
)
|
||||
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'<b>Usage: </b><code>{prefix}tts [character]* [text/reply to text]*</code>\n <b>Available Characters:</b> <blockquote>{characters}</blockquote>'
|
||||
)
|
||||
return
|
||||
|
||||
else:
|
||||
await message.edit_text(
|
||||
f'<b>Usage: </b><code>{prefix}tts [character]* [text/reply to text]*</code>\n <b>Available Characters:</b> <blockquote>{characters}</blockquote>'
|
||||
)
|
||||
return
|
||||
|
||||
data = {'text': prompt, 'character': character}
|
||||
response = requests.post(url=f'{url}/speech', headers=headers, json=data, timeout=10)
|
||||
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'<b>Characters:</b> <code>{character}</code>\n<b>Prompt:</b> <code>{prompt}</code>',
|
||||
)
|
||||
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'<b>Usage: </b><code>{prefix}tts [character]* [text/reply to text]*</code>\n <b>Available Characters:</b> <blockquote>{characters}</blockquote>'
|
||||
)
|
||||
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'<b>Text:</b> <code>{text}</code>',
|
||||
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'<b>Text:</b> <code>{cap}</code>',
|
||||
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, timeout=10)
|
||||
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: <code>{bins}</code>\nTotal: <code>{len(cards)}</code>\nCards: \n<code>{cards_str}</code>'
|
||||
)
|
||||
|
||||
|
||||
@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'<b>Text:</b> <code>{text}</code>',
|
||||
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'<b>Text:</b> <code>{cap}</code>',
|
||||
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',
|
||||
}
|
||||
@@ -0,0 +1,504 @@
|
||||
# Moon-Userbot - telegram userbot
|
||||
# Copyright (C) 2020-present Moon Userbot Organization
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import asyncio
|
||||
import contextlib
|
||||
import os
|
||||
|
||||
import requests
|
||||
from modules.url import generate_screenshot
|
||||
from pyrogram import Client, enums, filters
|
||||
from pyrogram.types import Message
|
||||
from utils.misc import modules_help, prefix
|
||||
from utils.scripts import no_prefix
|
||||
|
||||
np = no_prefix(prefix)
|
||||
|
||||
# API URLs
|
||||
BASE_URL = 'https://deliriussapi-oficial.vercel.app'
|
||||
URL = f'{BASE_URL}/ia'
|
||||
GOOGLE_SEARCH_URL = f'{BASE_URL}/search/googlesearch?query='
|
||||
YOUTUBE_SEARCH_URL = f'{BASE_URL}/search/ytsearch?q='
|
||||
MOVIE_SEARCH_URL = f'{BASE_URL}/search/movie?query='
|
||||
APK_SEARCH_URL = 'https://bk9.fun/search/apkfab?q='
|
||||
APK_DOWNLOAD_URL = 'https://bk9.fun/download/apkfab?url='
|
||||
|
||||
|
||||
def clean_data(data):
|
||||
parts = data.split('$@$')
|
||||
|
||||
if len(parts) > 1:
|
||||
return parts[-1]
|
||||
else:
|
||||
return data
|
||||
|
||||
|
||||
# Store search results temporarily
|
||||
search_results = {}
|
||||
|
||||
|
||||
# Helper Functions
|
||||
def format_google_results(results):
|
||||
results = results[:15]
|
||||
return results, '\n\n'.join(
|
||||
[f'{i + 1}. **[{item["title"]}]({item["url"]})**\n{item["description"]}' for i, item in enumerate(results)]
|
||||
)
|
||||
|
||||
|
||||
def format_youtube_results(results):
|
||||
results = results[:15]
|
||||
return results, '\n\n'.join(
|
||||
[
|
||||
f'{i + 1}. **[{item["title"]}]({item["url"]})**\nPublished by: [{item["author"]["name"]}]({item["author"]["url"]}) - {item["views"]} views - {item["duration"]}'
|
||||
for i, item in enumerate(results)
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
def format_movie_results(results):
|
||||
results = results[:15]
|
||||
return results, '\n\n'.join(
|
||||
[
|
||||
f'{i + 1}. **{item["title"]}** ({item["release_date"]})\nRating: {item["vote_average"]}/10\nVotes: {item["vote_count"]}'
|
||||
for i, item in enumerate(results)
|
||||
]
|
||||
)
|
||||
|
||||
|
||||
def format_apk_results(results):
|
||||
results = results[:15]
|
||||
return results, '\n\n'.join([f'{i + 1}. [{item["title"]}]({item["link"]})' for i, item in enumerate(results)])
|
||||
|
||||
|
||||
async def send_screenshot(client, message, url):
|
||||
screenshot_data = generate_screenshot(url)
|
||||
if screenshot_data:
|
||||
await client.send_photo(
|
||||
message.chat.id,
|
||||
screenshot_data,
|
||||
caption=f'Screenshot of <code>{url}</code>',
|
||||
reply_to_message_id=message.id,
|
||||
)
|
||||
else:
|
||||
await message.reply('Failed to take screenshot.')
|
||||
|
||||
|
||||
async def delete_search_data(client, chat_id, message_id):
|
||||
await asyncio.sleep(60)
|
||||
for key in ['google', 'youtube', 'movie', 'apk']:
|
||||
search_key = f'{chat_id}_{key}'
|
||||
if search_key in search_results and search_results[search_key]['message_id'] == message_id:
|
||||
del search_results[search_key]
|
||||
with contextlib.suppress(BaseException):
|
||||
await client.delete_messages(chat_id, message_id)
|
||||
break
|
||||
|
||||
|
||||
def format_spotify_result(data):
|
||||
result = ''
|
||||
for item in data[:15]: # Limit to 15 results
|
||||
result += f'🎵 **{item["title"]}** by {item["artist"]}\n'
|
||||
result += f'Album: {item["album"]}\n'
|
||||
result += f'Duration: {item["duration"]}\n'
|
||||
result += f'Popularity: {item["popularity"]}\n'
|
||||
result += f'Publish Date: {item["publish"]}\n'
|
||||
result += f'[Listen on Spotify]({item["url"]})\n\n'
|
||||
return result
|
||||
|
||||
|
||||
def format_lyrics_result(data):
|
||||
return f'🎵 **{data["fullTitle"]}** by {data["artist"]}\n\n{data["lyrics"]}'
|
||||
|
||||
|
||||
def format_soundcloud_result(data):
|
||||
result = ''
|
||||
for item in data[:15]: # Limit to 15 results
|
||||
result += f'🎵 **{item["title"]}**\n'
|
||||
result += f'Genre: {item["genre"]}\n'
|
||||
result += f'Duration: {item["duration"] // 1000 // 60}:{item["duration"] // 1000 % 60}\n'
|
||||
result += f'Likes: {item["likes"]}\n'
|
||||
result += f'Plays: {item["play"]}\n'
|
||||
result += f'[Listen on SoundCloud]({item["link"]})\n\n'
|
||||
return result
|
||||
|
||||
|
||||
def format_deezer_result(data):
|
||||
result = ''
|
||||
for item in data[:15]: # Limit to 15 results
|
||||
result += f'🎵 **{item["title"]}** by {item["artist"]}\n'
|
||||
result += f'Duration: {item["duration"]}\n'
|
||||
result += f'Rank: {item["rank"]}\n'
|
||||
result += f'[Listen on Deezer]({item["url"]})\n\n'
|
||||
return result
|
||||
|
||||
|
||||
def format_apple_music_result(data):
|
||||
result = ''
|
||||
for item in data[:15]: # Limit to 15 results
|
||||
title = item.get('title', 'Unknown Title')
|
||||
artists = item.get('artists', 'Unknown Artist')
|
||||
music_type = item.get('type', 'Unknown Type')
|
||||
url = item.get('url', '#')
|
||||
result += f'🎵 **{title}** by {artists}\n'
|
||||
result += f'Type: {music_type}\n'
|
||||
result += f'[Listen on Apple Music]({url})\n\n'
|
||||
return result
|
||||
|
||||
|
||||
async def search_music(api_url, format_function, message, query):
|
||||
await message.edit('Searching...')
|
||||
url = f'{api_url}{query}&limit=10'
|
||||
response = requests.get(url, timeout=10)
|
||||
|
||||
if response.status_code == 200:
|
||||
try:
|
||||
data = response.json() # Directly get the JSON data
|
||||
|
||||
if isinstance(data, list):
|
||||
result = format_function(data)
|
||||
elif isinstance(data, dict) and 'data' in data:
|
||||
result = format_function(data['data'])
|
||||
else:
|
||||
result = 'No data found or unexpected format.'
|
||||
|
||||
await message.edit(result, parse_mode=enums.ParseMode.MARKDOWN)
|
||||
except (ValueError, KeyError, TypeError) as e:
|
||||
await message.edit(f'An error occurred while processing the data: {str(e)}')
|
||||
elif response.json()['msg']:
|
||||
await message.edit(response.json()['msg'])
|
||||
else:
|
||||
await message.edit('An error occurred, please try again later.')
|
||||
|
||||
|
||||
@Client.on_message(filters.command(['gsearch'], prefix) & filters.me)
|
||||
async def google_search(client: Client, message: Message):
|
||||
if message.reply_to_message:
|
||||
query = message.reply_to_message.text.strip()
|
||||
elif len(message.command) > 1:
|
||||
query = message.text.split(maxsplit=1)[1]
|
||||
else:
|
||||
return await message.edit_text(f'{prefix}gsearch <query/reply to query>')
|
||||
|
||||
await message.edit('Searching...')
|
||||
url = f'{GOOGLE_SEARCH_URL}{query}'
|
||||
response = requests.get(url, timeout=10)
|
||||
if response.status_code == 200:
|
||||
data = response.json()
|
||||
results, formatted_results = format_google_results(data['data'])
|
||||
search_message = await message.edit(
|
||||
f'**Google Search Results for:** `{query}`\n\n{formatted_results}',
|
||||
parse_mode=enums.ParseMode.MARKDOWN,
|
||||
disable_web_page_preview=True,
|
||||
)
|
||||
search_key = f'{message.chat.id}_google'
|
||||
global search_results
|
||||
search_results[search_key] = {
|
||||
'results': results,
|
||||
'message_id': search_message.id,
|
||||
}
|
||||
google_url = f'https://www.google.com/search?q={query}'
|
||||
await send_screenshot(client, message, google_url)
|
||||
asyncio.create_task(delete_search_data(client, message.chat.id, search_message.id))
|
||||
else:
|
||||
await message.edit('An error occurred, please try again later.')
|
||||
|
||||
|
||||
@Client.on_message(filters.command(['ytsearch'], prefix) & filters.me)
|
||||
async def youtube_search(client: Client, message: Message):
|
||||
if message.reply_to_message:
|
||||
query = message.reply_to_message.text.strip()
|
||||
elif len(message.command) > 1:
|
||||
query = message.text.split(maxsplit=1)[1]
|
||||
else:
|
||||
return await message.edit_text(f'{prefix}ytsearch <query/reply to query>')
|
||||
|
||||
await message.edit('Searching...')
|
||||
url = f'{YOUTUBE_SEARCH_URL}{query}'
|
||||
response = requests.get(url, timeout=10)
|
||||
if response.status_code == 200:
|
||||
data = response.json()
|
||||
results, formatted_results = format_youtube_results(data['data'])
|
||||
search_message = await message.edit(
|
||||
f'**YouTube Search Results for:** `{query}`\n\n{formatted_results}',
|
||||
parse_mode=enums.ParseMode.MARKDOWN,
|
||||
disable_web_page_preview=True,
|
||||
)
|
||||
search_key = f'{message.chat.id}_youtube'
|
||||
global search_results
|
||||
search_results[search_key] = {
|
||||
'results': results,
|
||||
'message_id': search_message.id,
|
||||
}
|
||||
youtube_url = f'https://www.youtube.com/results?search_query={query}'
|
||||
await send_screenshot(client, message, youtube_url)
|
||||
asyncio.create_task(delete_search_data(client, message.chat.id, search_message.id))
|
||||
else:
|
||||
await message.edit('An error occurred, please try again later.')
|
||||
|
||||
|
||||
@Client.on_message(filters.command(['moviesearch'], prefix) & filters.me)
|
||||
async def movie_search(client, message: Message):
|
||||
if message.reply_to_message:
|
||||
query = message.reply_to_message.text.strip()
|
||||
elif len(message.command) > 1:
|
||||
query = message.text.split(maxsplit=1)[1]
|
||||
else:
|
||||
return await message.edit_text(f'{prefix}moviesearch <query/reply to query>')
|
||||
|
||||
await message.edit('Searching...')
|
||||
url = f'{MOVIE_SEARCH_URL}{query}'
|
||||
response = requests.get(url, timeout=10)
|
||||
if response.status_code == 200:
|
||||
data = response.json()
|
||||
results, formatted_results = format_movie_results(data['data'])
|
||||
|
||||
# Split the message into multiple parts if it's too long
|
||||
parts = []
|
||||
part_length = 4096 # Telegram's message length limit
|
||||
for i in range(0, len(formatted_results), part_length):
|
||||
parts.append(formatted_results[i : i + part_length])
|
||||
|
||||
for part in parts:
|
||||
search_message = await message.reply(
|
||||
f'**Movie Search Results for:** `{query}`\n\n{part}',
|
||||
parse_mode=enums.ParseMode.MARKDOWN,
|
||||
disable_web_page_preview=True,
|
||||
)
|
||||
|
||||
search_key = f'{message.chat.id}_movie'
|
||||
global search_results
|
||||
search_results[search_key] = {
|
||||
'results': results,
|
||||
'message_id': search_message.id,
|
||||
}
|
||||
asyncio.create_task(delete_search_data(client, message.chat.id, search_message.id))
|
||||
else:
|
||||
await message.edit('An error occurred, please try again later.')
|
||||
|
||||
|
||||
@Client.on_message(filters.command(['apksearch'], prefix) & filters.me)
|
||||
async def apk_search(client, message: Message):
|
||||
if message.reply_to_message:
|
||||
query = message.reply_to_message.text.strip()
|
||||
elif len(message.command) > 1:
|
||||
query = message.text.split(maxsplit=1)[1]
|
||||
else:
|
||||
return await message.edit_text(f'{prefix}apksearch <query/reply to query>')
|
||||
|
||||
await message.edit('Searching...')
|
||||
url = f'{APK_SEARCH_URL}{query}'
|
||||
response = requests.get(url, timeout=10)
|
||||
if response.status_code == 200:
|
||||
data = response.json()
|
||||
results, formatted_results = format_apk_results(data['BK9'])
|
||||
search_message = await message.edit(
|
||||
f'**APK Search Results for:** `{query}`\n\n{formatted_results}',
|
||||
parse_mode=enums.ParseMode.MARKDOWN,
|
||||
disable_web_page_preview=True,
|
||||
)
|
||||
search_key = f'{message.chat.id}_apk'
|
||||
global search_results
|
||||
search_results[search_key] = {
|
||||
'results': results,
|
||||
'message_id': search_message.id,
|
||||
}
|
||||
|
||||
asyncio.create_task(delete_search_data(client, message.chat.id, search_message.id))
|
||||
else:
|
||||
await message.edit('An error occurred, please try again later.')
|
||||
|
||||
|
||||
@Client.on_message(filters.command(['wgpt', 'gptweb'], prefix) & filters.me)
|
||||
async def gptweb(_, message: Message):
|
||||
if len(message.command) < 2:
|
||||
await message.edit('Usage: `wgpt <query>`')
|
||||
return
|
||||
await message.edit('Thinking...')
|
||||
query = ' '.join(message.command[1:])
|
||||
url = f'{URL}/gptweb?text={query}'
|
||||
response = requests.get(url, timeout=10)
|
||||
if response.status_code == 200:
|
||||
data = response.json()
|
||||
await message.edit(
|
||||
f'**Question:**\n{query}\n**Answer:**\n{data["data"]}',
|
||||
parse_mode=enums.ParseMode.MARKDOWN,
|
||||
)
|
||||
else:
|
||||
await message.edit('An error occurred, please try again later.')
|
||||
|
||||
|
||||
@Client.on_message(filters.command(['wgemini'], prefix) & filters.me)
|
||||
async def gemini(_, message: Message):
|
||||
if len(message.command) < 2:
|
||||
await message.edit('Usage: `wgemini <query>`')
|
||||
return
|
||||
await message.edit('Thinking...')
|
||||
query = ' '.join(message.command[1:])
|
||||
url = f'{URL}/gemini?query={query}'
|
||||
response = requests.get(url, timeout=10)
|
||||
if response.status_code == 200:
|
||||
data = response.json()
|
||||
await message.edit(
|
||||
f'**Question:**\n{query}\n**Answer:**\n{data["message"]}',
|
||||
parse_mode=enums.ParseMode.MARKDOWN,
|
||||
)
|
||||
else:
|
||||
await message.edit('An error occurred, please try again later.')
|
||||
|
||||
|
||||
@Client.on_message(filters.command(['sputify'], prefix) & filters.me)
|
||||
async def spotify_search(_, message: Message):
|
||||
query = message.text.split(maxsplit=1)[1] if len(message.command) > 1 else message.reply_to_message.text
|
||||
if not query:
|
||||
await message.edit('Usage: spotify <query>')
|
||||
return
|
||||
await search_music(f'{BASE_URL}/search/spotify?q=', format_spotify_result, message, query)
|
||||
|
||||
|
||||
@Client.on_message(filters.command(['lyrics'], prefix) & filters.me)
|
||||
async def lyrics_search(_, message: Message):
|
||||
query = message.text.split(maxsplit=1)[1] if len(message.command) > 1 else message.reply_to_message.text
|
||||
if not query:
|
||||
await message.edit('Usage: lyrics <song name>')
|
||||
return
|
||||
await search_music(f'{BASE_URL}/search/letra?query=', format_lyrics_result, message, query)
|
||||
|
||||
|
||||
@Client.on_message(filters.command(['soundcloud'], prefix) & filters.me)
|
||||
async def soundcloud_search(_, message: Message):
|
||||
query = message.text.split(maxsplit=1)[1] if len(message.command) > 1 else message.reply_to_message.text
|
||||
if not query:
|
||||
await message.edit('Usage: soundcloud <query>')
|
||||
return
|
||||
await search_music(f'{BASE_URL}/search/soundcloud?q=', format_soundcloud_result, message, query)
|
||||
|
||||
|
||||
@Client.on_message(filters.command(['deezer'], prefix) & filters.me)
|
||||
async def deezer_search(_, message: Message):
|
||||
query = message.text.split(maxsplit=1)[1] if len(message.command) > 1 else message.reply_to_message.text
|
||||
if not query:
|
||||
await message.edit('Usage: deezer <query>')
|
||||
return
|
||||
await search_music(f'{BASE_URL}/search/deezer?q=', format_deezer_result, message, query)
|
||||
|
||||
|
||||
@Client.on_message(filters.command(['applemusic'], prefix) & filters.me)
|
||||
async def applemusic_search(_, message: Message):
|
||||
query = message.text.split(maxsplit=1)[1] if len(message.command) > 1 else message.reply_to_message.text
|
||||
if not query:
|
||||
await message.edit('Usage: applemusic <query>')
|
||||
return
|
||||
await search_music(f'{BASE_URL}/search/applemusic?text=', format_apple_music_result, message, query)
|
||||
|
||||
|
||||
@Client.on_message(filters.reply & filters.text & filters.me & np)
|
||||
async def handle_reply(client: Client, message: Message):
|
||||
chat_id = message.chat.id
|
||||
search_keys = [
|
||||
f'{chat_id}_google',
|
||||
f'{chat_id}_youtube',
|
||||
f'{chat_id}_movie',
|
||||
f'{chat_id}_apk',
|
||||
]
|
||||
|
||||
for search_key in search_keys:
|
||||
if search_key in search_results:
|
||||
try:
|
||||
# Check if the replied-to message is one of the bot's search result messages
|
||||
if message.reply_to_message.from_user.id != (await client.get_me()).id:
|
||||
return
|
||||
|
||||
index = int(message.text.strip()) - 1
|
||||
results = search_results[search_key]['results']
|
||||
search_message_id = search_results[search_key]['message_id']
|
||||
if message.reply_to_message.id == search_message_id and 0 <= index < len(results):
|
||||
await message.edit('Please wait...')
|
||||
|
||||
if search_key.endswith('_movie'):
|
||||
# Send movie details with image
|
||||
movie = results[index]
|
||||
caption = (
|
||||
f'**{movie["title"]}** ({movie["release_date"]})\n'
|
||||
f'Original Title: {movie["original_title"]}\n'
|
||||
f'Language: {movie["original_language"]}\n'
|
||||
f'Overview: {movie["overview"]}\n'
|
||||
f'Popularity: {movie["popularity"]}\n'
|
||||
f'Rating: {movie["vote_average"]}/10\n'
|
||||
f'Votes: {movie["vote_count"]}'
|
||||
)
|
||||
if 'image' in movie:
|
||||
response = requests.get(movie['image'], timeout=10)
|
||||
if response.status_code == 200:
|
||||
with open('movie_image.jpg', 'wb') as f:
|
||||
f.write(response.content)
|
||||
await message.reply_photo(
|
||||
photo='movie_image.jpg',
|
||||
caption=caption,
|
||||
parse_mode=enums.ParseMode.MARKDOWN,
|
||||
)
|
||||
os.remove('movie_image.jpg')
|
||||
else:
|
||||
await message.reply(caption, parse_mode=enums.ParseMode.MARKDOWN)
|
||||
else:
|
||||
await message.reply(caption, parse_mode=enums.ParseMode.MARKDOWN)
|
||||
elif search_key.endswith('_apk'):
|
||||
apk_url = f'{APK_DOWNLOAD_URL}{results[index]["link"]}'
|
||||
fetch_apk_url = requests.get(apk_url, timeout=10)
|
||||
if fetch_apk_url.status_code != 200:
|
||||
await message.edit('Failed to fetch APK data.')
|
||||
else:
|
||||
data_apk = fetch_apk_url.json()
|
||||
download_url = data_apk['BK9']['link']
|
||||
size_apk = data_apk['BK9']['size']
|
||||
apk_size = float(size_apk.split(' ')[0])
|
||||
|
||||
if 'GB' in size_apk or apk_size > 100:
|
||||
await message.edit('File size is too large to download.')
|
||||
else:
|
||||
apk_file_name = f'{data_apk["BK9"]["title"]}.apk'
|
||||
response = requests.get(download_url, timeout=10)
|
||||
|
||||
if response.status_code != 200:
|
||||
await message.edit('Failed to download the APK file.')
|
||||
else:
|
||||
with open(apk_file_name, 'wb') as f:
|
||||
f.write(response.content)
|
||||
|
||||
await message.reply_document(apk_file_name)
|
||||
os.remove(apk_file_name)
|
||||
else:
|
||||
url = results[index]['url']
|
||||
await send_screenshot(client, message, url)
|
||||
await message.delete()
|
||||
return
|
||||
except ValueError:
|
||||
pass
|
||||
|
||||
|
||||
modules_help['sarethai'] = {
|
||||
'wgpt [query]*': 'Ask anything to GPT-Web',
|
||||
'gptweb [query]*': 'Ask anything to GPT-Web',
|
||||
'wgemini [query]*': 'Ask anything to Gemini',
|
||||
'sputify [query]*': 'Search for songs on Spotify',
|
||||
'lyrics [song name]*': 'Get the lyrics of a song',
|
||||
'soundcloud [query]*': 'Search for songs on SoundCloud',
|
||||
'deezer [query]*': 'Search for songs on Deezer',
|
||||
'applemusic [query]*': 'Search for songs on Apple Music',
|
||||
'gsearch [query]*': 'Searches Google for the query.',
|
||||
'ytsearch [query]*': 'Searches YouTube for the query.',
|
||||
'moviesearch [query]*': 'Searches movies for the query and returns results.',
|
||||
'apksearch [query]*': 'Searches APKs for the query and returns results.',
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
from asyncio import sleep
|
||||
|
||||
from pyrogram import Client, enums, filters
|
||||
from pyrogram.types import Message
|
||||
|
||||
# noinspection PyUnresolvedReferences
|
||||
from utils.misc import modules_help, prefix
|
||||
|
||||
# noinspection PyUnresolvedReferences
|
||||
from utils.scripts import format_exc
|
||||
|
||||
now = {}
|
||||
|
||||
|
||||
@Client.on_message(filters.command(['search'], prefix) & filters.me)
|
||||
async def search_cmd(client: Client, message: Message):
|
||||
if now.get(message.chat.id):
|
||||
return await message.edit(
|
||||
f'<b>You already have a search in progress!\nType: <code>{prefix}scancel</code> to cancel it.</b>',
|
||||
parse_mode=enums.ParseMode.HTML,
|
||||
)
|
||||
|
||||
await message.edit('<b>Start searching...</b>', parse_mode=enums.ParseMode.HTML)
|
||||
finished = False
|
||||
local = False
|
||||
try:
|
||||
cmd = message.command[1]
|
||||
word = message.command[2].lower()
|
||||
timeout = float(message.command[3]) if len(message.command) > 3 else 2
|
||||
except Exception:
|
||||
return await message.edit(
|
||||
f'<b>Usage:</b> <code>{prefix}search [/cmd]* [search_word]* [timeout=2.0]</code>',
|
||||
parse_mode=enums.ParseMode.HTML,
|
||||
)
|
||||
|
||||
now[message.chat.id] = True
|
||||
|
||||
try:
|
||||
await message.reply_text(quote=False, text=cmd, reply_to_message_id=None)
|
||||
while not finished and now[message.chat.id]:
|
||||
async for msg in client.get_chat_history(message.chat.id, limit=2):
|
||||
if msg.from_user.id == message.from_user.id:
|
||||
continue
|
||||
elif word in msg.text.lower():
|
||||
finished = True
|
||||
local = True
|
||||
if not local:
|
||||
await sleep(timeout)
|
||||
await message.reply_text(quote=False, text=cmd, reply_to_message_id=None)
|
||||
else:
|
||||
break
|
||||
if now[message.chat.id]:
|
||||
await message.reply_text('<b>Search finished!</b>', parse_mode=enums.ParseMode.HTML)
|
||||
except Exception as ex:
|
||||
await message.edit(format_exc(ex), parse_mode=enums.ParseMode.HTML)
|
||||
now[message.chat.id] = False
|
||||
|
||||
|
||||
@Client.on_message(filters.command(['scancel'], prefix) & filters.me)
|
||||
async def scancel_cmd(_: Client, message: Message):
|
||||
if not now.get(message.chat.id):
|
||||
return await message.edit('<b>There is no search in progress!</b>', parse_mode=enums.ParseMode.HTML)
|
||||
now[message.chat.id] = False
|
||||
await message.edit('<b>Search cancelled!</b>', parse_mode=enums.ParseMode.HTML)
|
||||
|
||||
|
||||
modules_help['search'] = {
|
||||
'search [/cmd]* [search_word]* [timeout=2.0]': 'Search for a specific word in bot (while)',
|
||||
'scancel': 'Cancel current search',
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
# copyright by https/t.me/shado_hackers
|
||||
|
||||
from pyrogram import Client, filters
|
||||
from pyrogram.types import Message
|
||||
from utils.misc import modules_help, prefix
|
||||
from utils.scripts import format_exc, import_library
|
||||
|
||||
import_library('lxml_html_clean')
|
||||
import_library('newspaper', 'newspaper3k')
|
||||
nltk = import_library('nltk')
|
||||
from newspaper import Article # noqa: E402
|
||||
from newspaper.article import ArticleException # noqa: E402
|
||||
|
||||
nltk.download('all')
|
||||
|
||||
|
||||
@Client.on_message(filters.command('summary', prefix) & filters.me)
|
||||
async def summarize_article(_, message: Message):
|
||||
"""
|
||||
Summarize an article from a given URL.
|
||||
|
||||
Args:
|
||||
client (Client): Pyrogram client instance.
|
||||
message (Message): Incoming message.
|
||||
|
||||
Returns:
|
||||
None
|
||||
"""
|
||||
# Extract the URL from the message text (removing the command part)
|
||||
url = message.text.split(maxsplit=1)[1] if len(message.text.split()) > 1 else None
|
||||
|
||||
if not url:
|
||||
await message.edit_text('Please provide a valid URL after the command.')
|
||||
return
|
||||
|
||||
try:
|
||||
# Extract and summarize the article
|
||||
article = Article(url)
|
||||
article.download()
|
||||
article.parse()
|
||||
article.nlp() # Uses NLP to analyze the article
|
||||
|
||||
response = f"""
|
||||
<b>Article Summary</b>
|
||||
<b>Title:</b> <code>{article.title}</code>
|
||||
<b>Authors:</b> <code>{', '.join(article.authors) if article.authors else 'N/A'}</code>
|
||||
<b>Summary:</b>
|
||||
<pre>{article.summary}</pre>
|
||||
"""
|
||||
await message.edit_text(response)
|
||||
except ArticleException:
|
||||
return await message.edit_text('Unable to extract information from the provided URL.')
|
||||
|
||||
except Exception as e:
|
||||
return await message.edit_text(f'An error occurred: {format_exc(e)}')
|
||||
|
||||
|
||||
modules_help['summary'] = {'summary [url]': 'Reply with article links, getting summary of articles'}
|
||||
@@ -0,0 +1,46 @@
|
||||
# Moon-Userbot - telegram userbot
|
||||
# Copyright (C) 2020-present Moon Userbot Organization
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
from pyrogram import Client, enums, filters
|
||||
from pyrogram.types import Message
|
||||
from utils.misc import modules_help, prefix
|
||||
|
||||
ru_keys = """ёйцукенгшщзхъфывапролджэячсмитьбю.Ё"№;%:?ЙЦУКЕНГШЩЗХЪФЫВАПРОЛДЖЭ/ЯЧСМИТЬБЮ,"""
|
||||
en_keys = """`qwertyuiop[]asdfghjkl;'zxcvbnm,./~@#$%^&QWERTYUIOP{}ASDFGHJKL:"|ZXCVBNM<>?"""
|
||||
table = str.maketrans(ru_keys + en_keys, en_keys + ru_keys)
|
||||
|
||||
|
||||
@Client.on_message(filters.command(['switch', 'sw'], prefix) & filters.me)
|
||||
async def switch(client: Client, message: Message):
|
||||
if len(message.command) == 1:
|
||||
if message.reply_to_message:
|
||||
text = message.reply_to_message.text
|
||||
else:
|
||||
history = await client.get_history(message.chat.id, limit=2)
|
||||
if history and history[1].from_user.is_self and history[1].text:
|
||||
text = history[1].text
|
||||
else:
|
||||
await message.edit('<b>Text to switch not found</b>', parse_mode=enums.ParseMode.HTML)
|
||||
return
|
||||
else:
|
||||
text = message.text.split(maxsplit=1)[1]
|
||||
|
||||
await message.edit(str.translate(text, table), parse_mode=enums.ParseMode.HTML)
|
||||
|
||||
|
||||
modules_help['switch'] = {
|
||||
'sw [reply/text for switch]*': 'Useful when you forgot to change the keyboard layout[RU]',
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
import os
|
||||
import time
|
||||
|
||||
import requests
|
||||
from pyrogram import Client, enums, filters
|
||||
from pyrogram.errors import MessageTooLong
|
||||
from pyrogram.types import Message
|
||||
from utils.misc import modules_help, prefix
|
||||
|
||||
# Replace with your Gladia API key
|
||||
gladia_key = 'your key '
|
||||
gladia_url = 'https://api.gladia.io/v2/transcription/'
|
||||
|
||||
|
||||
# Function to make fetch requests to the Gladia API
|
||||
def make_fetch_request(url, headers, method='GET', data=None):
|
||||
if method == 'POST':
|
||||
response = requests.post(url, headers=headers, json=data, timeout=10)
|
||||
else:
|
||||
response = requests.get(url, headers=headers, timeout=10)
|
||||
return response.json()
|
||||
|
||||
|
||||
@Client.on_message(filters.command('transcribeyt', prefix) & filters.me)
|
||||
async def transcribe_audio(_, message: Message):
|
||||
"""
|
||||
Transcribe an audio URL using the Gladia API.
|
||||
|
||||
Usage: .transcribe <audio_url>
|
||||
"""
|
||||
audio_url = message.text.split(maxsplit=1)[1] if len(message.text.split()) > 1 else None
|
||||
|
||||
# Check if a valid URL was provided
|
||||
if not audio_url:
|
||||
await message.reply('Please provide a valid audio URL.')
|
||||
return
|
||||
|
||||
headers = {'x-gladia-key': gladia_key, 'Content-Type': 'application/json'}
|
||||
|
||||
request_data = {'audio_url': audio_url}
|
||||
|
||||
# Send initial request to Gladia API
|
||||
status_message = await message.reply('- Sending initial request to Gladia API...')
|
||||
initial_response = make_fetch_request(gladia_url, headers, 'POST', request_data)
|
||||
|
||||
# Check if the response contains the result_url
|
||||
if 'result_url' not in initial_response:
|
||||
await status_message.edit(f'Error in transcription request: {initial_response}')
|
||||
return
|
||||
|
||||
result_url = initial_response['result_url']
|
||||
await status_message.edit('Initial request sent. Polling for transcription results...')
|
||||
|
||||
# Polling for transcription result
|
||||
while True:
|
||||
poll_response = make_fetch_request(result_url, headers)
|
||||
|
||||
if poll_response.get('status') == 'done':
|
||||
transcription = poll_response.get('result', {}).get('transcription', {}).get('full_transcript')
|
||||
if transcription:
|
||||
# Format the transcription result with HTML
|
||||
result_html = f"""
|
||||
<u><b>Transcription Result</b></u>
|
||||
<br>
|
||||
<pre>{transcription}</pre>
|
||||
"""
|
||||
try:
|
||||
# Attempt to send transcription as a message
|
||||
await message.reply_text(result_html, parse_mode=enums.ParseMode.HTML)
|
||||
except MessageTooLong:
|
||||
# Save the large response to a file
|
||||
with open('transcription.txt', 'w') as f:
|
||||
f.write(result_html)
|
||||
|
||||
# Read general details to include in the caption
|
||||
general_details = "Here's the transcription result."
|
||||
|
||||
# Send the file with a caption
|
||||
await message.reply_document(
|
||||
'transcription.txt',
|
||||
caption=f'<u><b>General Details</b></u>:\n{general_details}',
|
||||
)
|
||||
|
||||
# Clean up by removing the file
|
||||
os.remove('transcription.html')
|
||||
else:
|
||||
await status_message.edit('Transcription completed, but no transcript was found.')
|
||||
break
|
||||
else:
|
||||
await status_message.edit(f'Transcription status: {poll_response.get("status")}')
|
||||
time.sleep(30) # Wait for a few seconds before polling again
|
||||
|
||||
|
||||
modules_help['transcribeyt'] = {'transcribeyt [yt video url]': 'Reply with a YT video link to get transcribed '}
|
||||
@@ -0,0 +1,133 @@
|
||||
# Moon-Userbot - telegram userbot
|
||||
# Copyright (C) 2020-present Moon Userbot Organization
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
from pyrogram import Client, errors, filters
|
||||
from pyrogram.types import Message
|
||||
from utils.db import db
|
||||
from utils.handlers import NoteSendHandler
|
||||
from utils.misc import modules_help, prefix
|
||||
|
||||
|
||||
@Client.on_message(filters.command(['save'], prefix) & filters.me)
|
||||
async def save_note(client: Client, message: Message):
|
||||
await message.edit('<b>Loading...</b>')
|
||||
|
||||
try:
|
||||
chat = await client.get_chat(db.get('core.notes', 'chat_id', 0))
|
||||
except (errors.RPCError, ValueError, KeyError):
|
||||
# group is not accessible or isn't created
|
||||
chat = await client.create_supergroup('Userbot_Notes_Filters', "Don't touch this group, please")
|
||||
db.set('core.notes', 'chat_id', chat.id)
|
||||
|
||||
chat_id = chat.id
|
||||
|
||||
if message.reply_to_message and len(message.text.split()) >= 2:
|
||||
note_name = message.text.split(maxsplit=1)[1]
|
||||
if message.reply_to_message.media_group_id:
|
||||
checking_note = db.get('core.notes', f'note{note_name}', False)
|
||||
if not checking_note:
|
||||
get_media_group = [
|
||||
_.id for _ in await client.get_media_group(message.chat.id, message.reply_to_message.id)
|
||||
]
|
||||
try:
|
||||
message_id = await client.forward_messages(chat_id, message.chat.id, get_media_group)
|
||||
except errors.ChatForwardsRestricted:
|
||||
await message.edit(
|
||||
'<b>Forwarding messages is restricted by chat admins</b>',
|
||||
)
|
||||
return
|
||||
note = {
|
||||
'MESSAGE_ID': str(message_id[1].id),
|
||||
'MEDIA_GROUP': True,
|
||||
'CHAT_ID': str(chat_id),
|
||||
}
|
||||
db.set('core.notes', f'note{note_name}', note)
|
||||
await message.edit(f'<b>Note {note_name} saved</b>')
|
||||
else:
|
||||
await message.edit('<b>This note already exists</b>')
|
||||
else:
|
||||
checking_note = db.get('core.notes', f'note{note_name}', False)
|
||||
if not checking_note:
|
||||
try:
|
||||
message_id = await message.reply_to_message.forward(chat_id)
|
||||
except errors.ChatForwardsRestricted:
|
||||
message_id = await message.copy(chat_id)
|
||||
note = {
|
||||
'MEDIA_GROUP': False,
|
||||
'MESSAGE_ID': str(message_id.id),
|
||||
'CHAT_ID': str(chat_id),
|
||||
}
|
||||
db.set('core.notes', f'note{note_name}', note)
|
||||
await message.edit(f'<b>Note {note_name} saved</b>')
|
||||
else:
|
||||
await message.edit('<b>This note already exists</b>')
|
||||
elif len(message.text.split()) >= 3:
|
||||
note_name = message.text.split(maxsplit=1)[1].split()[0]
|
||||
checking_note = db.get('core.notes', f'note{note_name}', False)
|
||||
if not checking_note:
|
||||
message_id = await client.send_message(chat_id, message.text.split(note_name)[1].strip())
|
||||
note = {
|
||||
'MEDIA_GROUP': False,
|
||||
'MESSAGE_ID': str(message_id.id),
|
||||
'CHAT_ID': str(chat_id),
|
||||
}
|
||||
db.set('core.notes', f'note{note_name}', note)
|
||||
await message.edit(f'<b>Note {note_name} saved</b>')
|
||||
else:
|
||||
await message.edit('<b>This note already exists</b>')
|
||||
else:
|
||||
await message.edit(
|
||||
f'<b>Example: <code>{prefix}save note_name</code></b>',
|
||||
)
|
||||
|
||||
|
||||
@Client.on_message(filters.command('note', prefix) & filters.me)
|
||||
async def note_send(client: Client, message: Message):
|
||||
handler = NoteSendHandler(client, message)
|
||||
await handler.handle_note_send()
|
||||
|
||||
|
||||
@Client.on_message(filters.command(['notes'], prefix) & filters.me)
|
||||
async def notes(_, message: Message):
|
||||
await message.edit('<b>Loading...</b>')
|
||||
text = 'Available notes:\n\n'
|
||||
collection = db.get_collection('core.notes')
|
||||
for note in collection:
|
||||
if note[:4] == 'note':
|
||||
text += f'<code>{note[4:]}</code>\n'
|
||||
await message.edit(text)
|
||||
|
||||
|
||||
@Client.on_message(filters.command(['clear'], prefix) & filters.me)
|
||||
async def clear_note(_, message: Message):
|
||||
if len(message.text.split()) >= 2:
|
||||
note_name = message.text.split(maxsplit=1)[1]
|
||||
find_note = db.get('core.notes', f'note{note_name}', False)
|
||||
if find_note:
|
||||
db.remove('core.notes', f'note{note_name}')
|
||||
await message.edit(f'<b>Note {note_name} deleted</b>')
|
||||
else:
|
||||
await message.edit('<b>There is no such note</b>')
|
||||
else:
|
||||
await message.edit(f'<b>Example: <code>{prefix}clear note_name</code></b>')
|
||||
|
||||
|
||||
modules_help['notes'] = {
|
||||
'save [name]*': 'Save note',
|
||||
'note [name]*': 'Get saved note',
|
||||
'notes': 'Get note list',
|
||||
'clear [name]*': 'Delete note',
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
# Moon-Userbot - telegram userbot
|
||||
# Copyright (C) 2020-present Moon Userbot Organization
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import datetime
|
||||
import os
|
||||
import time
|
||||
|
||||
import aiofiles
|
||||
from pyrogram import Client, filters
|
||||
from pyrogram.errors import MessageTooLong
|
||||
from pyrogram.types import Message
|
||||
from utils.misc import modules_help, prefix
|
||||
from utils.rentry import paste as rentry_paste
|
||||
from utils.scripts import edit_or_reply, format_exc, progress
|
||||
|
||||
|
||||
async def read_file(file_path):
|
||||
async with aiofiles.open(file_path) as file:
|
||||
content = await file.read()
|
||||
return content
|
||||
|
||||
|
||||
def check_extension(file_path):
|
||||
extensions = {
|
||||
'.txt': "<pre lang='plaintext'>",
|
||||
'.py': "<pre lang='python'>",
|
||||
'.js': "<pre lang='javascript'>",
|
||||
'.json': "<pre lang='json'>",
|
||||
'.smali': "<pre lang='smali'>",
|
||||
'.sh': "<pre lang='shell'>",
|
||||
'.c': "<pre lang='c'>",
|
||||
'.java': "<pre lang='java'>",
|
||||
'.php': "<pre lang='php'>",
|
||||
'.doc': "<pre lang='doc'>",
|
||||
'.docx': "<pre lang='docx'>",
|
||||
'.rtf': "<pre lang='rtf'>",
|
||||
'.s': "<pre lang='asm'>",
|
||||
'.dart': "<pre lang='dart'>",
|
||||
'.cfg': "<pre lang='cfg'>",
|
||||
'.swift': "<pre lang='swift'>",
|
||||
'.cs': "<pre lang='csharp'>",
|
||||
'.vb': "<pre lang='vb'>",
|
||||
'.css': "<pre lang='css'>",
|
||||
'.htm': "<pre lang='html'>",
|
||||
'.html': "<pre lang='html'>",
|
||||
'.rss': "<pre lang='xml'>",
|
||||
'.xhtml': "<pre lang='xtml'>",
|
||||
'.cpp': "<pre lang='cpp'>",
|
||||
}
|
||||
|
||||
ext = os.path.splitext(file_path)[1].lower()
|
||||
|
||||
return extensions.get(ext, '<pre>')
|
||||
|
||||
|
||||
@Client.on_message(filters.command('open', prefix) & filters.me)
|
||||
async def openfile(client: Client, message: Message):
|
||||
if not message.reply_to_message:
|
||||
return await message.edit_text('Kindly Reply to a File')
|
||||
|
||||
try:
|
||||
ms = await edit_or_reply(message, '<b>Downloading...</b>')
|
||||
ct = time.time()
|
||||
file_path = await message.reply_to_message.download(progress=progress, progress_args=(ms, ct, 'Downloading...'))
|
||||
await ms.edit_text('<code>Trying to open file...</code>')
|
||||
file_info = os.stat(file_path)
|
||||
file_name = file_path.split('/')[-1:]
|
||||
file_size = file_info.st_size
|
||||
last_modified = datetime.datetime.fromtimestamp(file_info.st_mtime).strftime('%Y-%m-%d %H:%M:%S')
|
||||
code_start = check_extension(file_path=file_path)
|
||||
content = await read_file(file_path=file_path)
|
||||
await ms.edit_text(
|
||||
f'<b>File Name:</b> <code>{file_name[0]}</code>\n<b>Size:</b> <code>{file_size} bytes</code>\n<b>Last Modified:</b> <code>{last_modified}</code>\n<b>Content:</b> {code_start}{content}</pre>',
|
||||
)
|
||||
|
||||
except MessageTooLong:
|
||||
await ms.edit_text('<code>File Content is too long... Pasting to rentry...</code>')
|
||||
content_new = f'```{code_start[11:-2]}\n{content}```'
|
||||
try:
|
||||
rentry_url, edit_code = await rentry_paste(text=content_new, return_edit=True)
|
||||
except RuntimeError:
|
||||
await ms.edit_text('<b>Error:</b> <code>Failed to paste to rentry</code>')
|
||||
return
|
||||
await client.send_message(
|
||||
'me',
|
||||
f"Here's your edit code for Url: {rentry_url}\nEdit code: <code>{edit_code}</code>",
|
||||
disable_web_page_preview=True,
|
||||
)
|
||||
await ms.edit_text(
|
||||
f'<b>File Name:</b> <code>{file_name[0]}</code>\n<b>Size:</b> <code>{file_size} bytes</code>\n<b>Last Modified:</b> <code>{last_modified}</code>\n<b>Content:</b> {rentry_url}\n<b>Note:</b> <code>Edit Code has been sent to your saved messages</code>',
|
||||
disable_web_page_preview=True,
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
await ms.edit_text(format_exc(e))
|
||||
|
||||
finally:
|
||||
if os.path.exists(file_path):
|
||||
os.remove(file_path)
|
||||
|
||||
|
||||
modules_help['open'] = {'open': "Open content of any text supported filetype and show it's raw data"}
|
||||
@@ -0,0 +1,87 @@
|
||||
import os
|
||||
|
||||
from pyrogram import Client, filters
|
||||
from pyrogram.types import Message
|
||||
from utils.config import gemini_key
|
||||
from utils.misc import modules_help, prefix
|
||||
from utils.scripts import import_library
|
||||
|
||||
import_library('pyzerox', 'py-zerox')
|
||||
|
||||
import litellm # noqa: E402
|
||||
from pyzerox import zerox # noqa: E402
|
||||
from pyzerox.errors import ModelAccessError, NotAVisionModel # noqa: E402
|
||||
|
||||
kwargs = {}
|
||||
|
||||
CUSTOM_SYSTEM_PROMPT = "For the below pdf page, convert it into as accurate markdown format as possible with it's structure intact i.e, tables, charts, layouts etc. Return only the markdown with no explanation text. Do not exclude any content from the page."
|
||||
|
||||
|
||||
MODEL = 'gemini/gemini-1.5-pro'
|
||||
|
||||
|
||||
@Client.on_message(filters.command('pdf2md', prefix) & filters.me)
|
||||
async def pdf2md(client: Client, message: Message):
|
||||
if not message.reply_to_message:
|
||||
await message.edit('Reply to a pdf file')
|
||||
return
|
||||
if not message.reply_to_message.document:
|
||||
await message.edit('Reply to a pdf file')
|
||||
return
|
||||
if message.reply_to_message.document.mime_type != 'application/pdf':
|
||||
await message.edit('Reply to a pdf file')
|
||||
return
|
||||
if gemini_key == '':
|
||||
await message.edit('Set GEMINI_KEY to use this command')
|
||||
return
|
||||
file_name = message.reply_to_message.document.file_name
|
||||
file_name = file_name.split('.')[0]
|
||||
if os.path.exists(f'{file_name}.md'):
|
||||
os.remove(f'{file_name}.md')
|
||||
md = f'{file_name}.md'
|
||||
os.environ['GEMINI_API_KEY'] = gemini_key
|
||||
await message.edit('Downloading pdf...')
|
||||
pdf = await message.reply_to_message.download()
|
||||
await message.edit('Converting pdf to markdown...')
|
||||
try:
|
||||
result = await zerox(
|
||||
file_path=pdf,
|
||||
model=MODEL,
|
||||
custom_system_prompt=CUSTOM_SYSTEM_PROMPT,
|
||||
select_pages=None,
|
||||
**kwargs,
|
||||
)
|
||||
if result:
|
||||
pages = result.pages
|
||||
for page in pages:
|
||||
with open(md, 'a') as f:
|
||||
f.write(page.content)
|
||||
f.write('\n\n')
|
||||
else:
|
||||
await message.edit('No result')
|
||||
return
|
||||
except ModelAccessError:
|
||||
await message.edit('Model not accessible')
|
||||
return
|
||||
except NotAVisionModel:
|
||||
await message.edit('Model is not a vision model')
|
||||
return
|
||||
except litellm.InternalServerError:
|
||||
await message.edit('Internal Server Error')
|
||||
return
|
||||
except Exception as e:
|
||||
await message.edit(f'Error: {e}')
|
||||
return
|
||||
await message.edit('Uploading markdown...')
|
||||
await client.send_document(
|
||||
message.chat.id,
|
||||
document=md,
|
||||
file_name=f'{message.reply_to_message.document.file_name.split(".")[0]}.md',
|
||||
reply_to_message_id=message.reply_to_message.id,
|
||||
)
|
||||
await message.delete()
|
||||
os.remove(pdf)
|
||||
os.remove(md)
|
||||
|
||||
|
||||
modules_help['pdf2md'] = {'pdf2md': 'Convert a pdf to markdown'}
|
||||
@@ -0,0 +1,36 @@
|
||||
import random
|
||||
|
||||
from pyrogram import Client, enums, filters
|
||||
from pyrogram.types import Message
|
||||
from utils.misc import modules_help, prefix
|
||||
from utils.scripts import with_reply
|
||||
|
||||
|
||||
@Client.on_message(filters.command('prus', prefix) & filters.me)
|
||||
@with_reply
|
||||
async def prussian_cmd(_, message: Message):
|
||||
words = [
|
||||
'сука',
|
||||
'нахуй',
|
||||
'блять',
|
||||
'блядь',
|
||||
'пиздец',
|
||||
'еблан',
|
||||
'уебан',
|
||||
'уебок',
|
||||
'пизда',
|
||||
'очко',
|
||||
'хуй',
|
||||
]
|
||||
splitted = message.reply_to_message.text.split()
|
||||
|
||||
for i in range(0, len(splitted), random.randint(2, 3)): # noqa: S311
|
||||
for _j in range(1, 2):
|
||||
splitted.insert(i, random.choice(words)) # noqa: S311
|
||||
|
||||
await message.edit(' '.join(splitted), parse_mode=enums.ParseMode.HTML)
|
||||
|
||||
|
||||
modules_help['perfectrussian'] = {
|
||||
'prus': 'translate your message into perfect 🇷🇺Russian',
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
# Moon-Userbot - telegram userbot
|
||||
# Copyright (C) 2020-present Moon Userbot Organization
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
from pyrogram import Client, filters
|
||||
from pyrogram.types import Message
|
||||
from utils.misc import modules_help, prefix
|
||||
|
||||
|
||||
@Client.on_message(filters.command(['ping', 'p'], prefix) & filters.me)
|
||||
async def ping(client: Client, message: Message):
|
||||
latency = await client.ping()
|
||||
await message.edit(f'<b>Pong! {latency}ms</b>')
|
||||
|
||||
|
||||
modules_help['ping'] = {
|
||||
'ping': 'Check ping to Telegram servers',
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
# Moon-Userbot - telegram userbot
|
||||
# Copyright (C) 2020-present Moon Userbot Organization
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
from pyrogram import Client, filters
|
||||
from pyrogram.types import Message
|
||||
from utils.db import db
|
||||
from utils.misc import modules_help, prefix
|
||||
from utils.scripts import restart
|
||||
|
||||
|
||||
@Client.on_message(filters.command(['sp', 'setprefix'], prefix) & filters.me)
|
||||
async def setprefix(_, message: Message):
|
||||
if len(message.command) > 1:
|
||||
pref = message.command[1]
|
||||
db.set('core.main', 'prefix', pref)
|
||||
await message.edit(f'<b>Prefix [ <code>{pref}</code> ] is set!\nRestarting...</b>')
|
||||
db.set(
|
||||
'core.updater',
|
||||
'restart_info',
|
||||
{
|
||||
'type': 'restart',
|
||||
'chat_id': message.chat.id,
|
||||
'message_id': message.id,
|
||||
},
|
||||
)
|
||||
restart()
|
||||
else:
|
||||
await message.edit('<b>The prefix must not be empty!</b>')
|
||||
|
||||
|
||||
modules_help['prefix'] = {
|
||||
'sp [prefix]': 'Set custom prefix',
|
||||
'setprefix [prefix]': 'Set custom prefix',
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
# Moon-Userbot - telegram userbot
|
||||
# Copyright (C) 2020-present Moon Userbot Organization
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
import asyncio
|
||||
|
||||
from pyrogram import Client, filters
|
||||
from pyrogram.types import Message
|
||||
from utils.misc import modules_help, prefix
|
||||
from utils.scripts import with_reply
|
||||
|
||||
|
||||
@Client.on_message(filters.command('del', prefix) & filters.me)
|
||||
async def del_msg(_, message: Message):
|
||||
await message.delete()
|
||||
await message.reply_to_message.delete()
|
||||
|
||||
|
||||
@Client.on_message(filters.command('purge', prefix) & filters.me)
|
||||
@with_reply
|
||||
async def purge(client: Client, message: Message):
|
||||
chunk = []
|
||||
async for msg in client.get_chat_history(
|
||||
chat_id=message.chat.id,
|
||||
limit=message.id - message.reply_to_message.id + 1,
|
||||
):
|
||||
if msg.id < message.reply_to_message.id:
|
||||
break
|
||||
chunk.append(msg.id)
|
||||
if len(chunk) >= 100:
|
||||
await client.delete_messages(message.chat.id, chunk)
|
||||
chunk.clear()
|
||||
await asyncio.sleep(1)
|
||||
|
||||
if len(chunk) > 0:
|
||||
await client.delete_messages(message.chat.id, chunk)
|
||||
|
||||
|
||||
modules_help['purge'] = {
|
||||
'purge [reply]': 'Purge (delete all messages) chat from replied message to last',
|
||||
'del [reply]': 'Delete replied message',
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
# Moon-Userbot - telegram userbot
|
||||
# Copyright (C) 2020-present Moon Userbot Organization
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
from contextlib import redirect_stdout
|
||||
from io import StringIO
|
||||
|
||||
from pyrogram import Client, filters
|
||||
from pyrogram.types import Message
|
||||
|
||||
# noinspection PyUnresolvedReferences
|
||||
from utils.misc import modules_help, prefix
|
||||
from utils.scripts import format_exc
|
||||
|
||||
# noinspection PyUnresolvedReferences
|
||||
|
||||
|
||||
# noinspection PyUnusedLocal
|
||||
@Client.on_message(filters.command(['ex', 'exec', 'py', 'exnoedit'], prefix) & filters.me)
|
||||
async def user_exec(_: Client, message: Message):
|
||||
if len(message.command) == 1:
|
||||
await message.edit("<b>Code to execute isn't provided</b>")
|
||||
return
|
||||
|
||||
code = message.text.split(maxsplit=1)[1]
|
||||
stdout = StringIO()
|
||||
|
||||
await message.edit('<b>Executing...</b>')
|
||||
|
||||
try:
|
||||
with redirect_stdout(stdout):
|
||||
exec(code) # skipcq # noqa: S102
|
||||
text = f'<b>Code:</b>\n<code>{code}</code>\n\n<b>Result</b>:\n<code>{stdout.getvalue()}</code>'
|
||||
if message.command[0] == 'exnoedit':
|
||||
await message.reply(text)
|
||||
else:
|
||||
await message.edit(text)
|
||||
except Exception as e:
|
||||
await message.edit(format_exc(e))
|
||||
|
||||
|
||||
# noinspection PyUnusedLocal
|
||||
@Client.on_message(filters.command(['ev', 'eval'], prefix) & filters.me)
|
||||
async def user_eval(client: Client, message: Message):
|
||||
if len(message.command) == 1:
|
||||
await message.edit("<b>Code to eval isn't provided</b>")
|
||||
return
|
||||
|
||||
code = message.text.split(maxsplit=1)[1]
|
||||
|
||||
try:
|
||||
result = eval(code) # skipcq # noqa: S307
|
||||
await message.edit(f'<b>Expression:</b>\n<code>{code}</code>\n\n<b>Result</b>:\n<code>{result}</code>')
|
||||
except Exception as e:
|
||||
await message.edit(format_exc(e))
|
||||
|
||||
|
||||
modules_help['python'] = {
|
||||
'ex [python code]': 'Execute Python code',
|
||||
'exnoedit [python code]': 'Execute Python code and return result with reply',
|
||||
'eval [python code]': 'Eval Python code',
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
import random
|
||||
|
||||
from pyrogram import Client, enums, filters
|
||||
from pyrogram.types import Message
|
||||
from utils.misc import modules_help, prefix
|
||||
from utils.scripts import format_exc
|
||||
|
||||
emojis = [
|
||||
'👍',
|
||||
'👎',
|
||||
'❤️',
|
||||
'🔥',
|
||||
'🥰',
|
||||
'👏',
|
||||
'😁',
|
||||
'🤔',
|
||||
'🤯',
|
||||
'😱',
|
||||
'🤬',
|
||||
'😢',
|
||||
'🎉',
|
||||
'🤩',
|
||||
'🤮',
|
||||
'💩',
|
||||
]
|
||||
|
||||
|
||||
@Client.on_message(filters.command('reactspam', prefix) & filters.me)
|
||||
async def reactspam(client: Client, message: Message):
|
||||
await message.edit('<b>One moment...</b>', parse_mode=enums.ParseMode.HTML)
|
||||
try:
|
||||
selected_emojis = random.sample(emojis, 3)
|
||||
print(selected_emojis)
|
||||
await client.send_reaction(
|
||||
message.chat.id,
|
||||
message_id=message.reply_to_message.id,
|
||||
emoji=selected_emojis,
|
||||
)
|
||||
await message.delete()
|
||||
except Exception as e:
|
||||
return await message.edit_text(format_exc(e))
|
||||
|
||||
|
||||
modules_help['reactionspam'] = {'reactspam [amount]* [emoji]*': 'spam reactions'}
|
||||
@@ -0,0 +1,183 @@
|
||||
# Copyright (C) 2020-2021 by DevsExpo@Github, < https://github.com/DevsExpo >.
|
||||
#
|
||||
# This file is part of < https://github.com/DevsExpo/FridayUserBot > project,
|
||||
# and is released under the "GNU v3.0 License Agreement".
|
||||
# Please see < https://github.com/DevsExpo/blob/master/LICENSE >
|
||||
#
|
||||
# All rights reserved.
|
||||
# Modifed by @moonuserbot
|
||||
|
||||
import io
|
||||
import os
|
||||
from datetime import datetime
|
||||
from functools import wraps
|
||||
from io import BytesIO
|
||||
|
||||
import requests
|
||||
from PIL import Image
|
||||
from pyrogram import Client, enums, filters
|
||||
from pyrogram.types import Message
|
||||
from utils.config import rmbg_key
|
||||
from utils.misc import modules_help, prefix
|
||||
from utils.scripts import edit_or_reply, format_exc
|
||||
|
||||
|
||||
async def convert_to_image(message, client) -> None | str:
|
||||
"""Convert Most Media Formats To Raw Image"""
|
||||
if not message:
|
||||
return None
|
||||
if not message.reply_to_message:
|
||||
return None
|
||||
final_path = None
|
||||
if not (
|
||||
message.reply_to_message.video
|
||||
or message.reply_to_message.photo
|
||||
or message.reply_to_message.sticker
|
||||
or message.reply_to_message.media
|
||||
or message.reply_to_message.animation
|
||||
or message.reply_to_message.audio
|
||||
or message.reply_to_message.document
|
||||
):
|
||||
return None
|
||||
if message.reply_to_message.photo:
|
||||
final_path = await message.reply_to_message.download()
|
||||
elif message.reply_to_message.sticker:
|
||||
if message.reply_to_message.sticker.mime_type == 'image/webp':
|
||||
final_path = 'webp_to_png_s_proton.png'
|
||||
path_s = await message.reply_to_message.download()
|
||||
im = Image.open(path_s)
|
||||
im.save(final_path, 'PNG')
|
||||
else:
|
||||
path_s = await client.download_media(message.reply_to_message)
|
||||
final_path = 'lottie_proton.png'
|
||||
cmd = f'lottie_convert.py --frame 0 -if lottie -of png {path_s} {final_path}'
|
||||
await exec(cmd) # skipcq # noqa: S102
|
||||
elif message.reply_to_message.audio:
|
||||
thumb = message.reply_to_message.audio.thumbs[0].file_id
|
||||
final_path = await client.download_media(thumb)
|
||||
elif message.reply_to_message.video or message.reply_to_message.animation:
|
||||
final_path = 'fetched_thumb.png'
|
||||
vid_path = await client.download_media(message.reply_to_message)
|
||||
await exec(f'ffmpeg -i {vid_path} -filter:v scale=500:500 -an {final_path}') # skipcq # noqa: S102
|
||||
elif message.reply_to_message.document:
|
||||
if (
|
||||
message.reply_to_message.document.mime_type == 'image/jpeg'
|
||||
or message.reply_to_message.document.mime_type == 'image/png'
|
||||
):
|
||||
final_path = await message.reply_to_message.download()
|
||||
elif message.reply_to_message.document.mime_type == 'image/webp':
|
||||
final_path = 'webp_to_png_s_proton.png'
|
||||
path_s = await message.reply_to_message.download()
|
||||
im = Image.open(path_s)
|
||||
im.save(final_path, 'PNG')
|
||||
else:
|
||||
return None
|
||||
return final_path
|
||||
|
||||
|
||||
def remove_background(photo_data):
|
||||
with open(photo_data, 'rb') as image_file:
|
||||
image_data = image_file.read()
|
||||
response = requests.post(
|
||||
'https://api.remove.bg/v1.0/removebg',
|
||||
files={'image_file': image_data},
|
||||
data={'size': 'auto'},
|
||||
headers={'X-Api-Key': rmbg_key},
|
||||
timeout=10,
|
||||
)
|
||||
if response.status_code == 200:
|
||||
return BytesIO(response.content)
|
||||
print('Error:', response.status_code, response.text)
|
||||
return None
|
||||
|
||||
|
||||
def _check_rmbg(func):
|
||||
@wraps(func)
|
||||
async def check_rmbg(client: Client, message: Message):
|
||||
if not rmbg_key:
|
||||
await edit_or_reply(
|
||||
message,
|
||||
"<code>Is Your RMBG Api 'rmbg_key' Valid Or You Didn't Add It??</code>",
|
||||
)
|
||||
else:
|
||||
await func(client, message)
|
||||
|
||||
return check_rmbg
|
||||
|
||||
|
||||
@Client.on_message(filters.command('rmbg', prefix) & filters.me)
|
||||
@_check_rmbg
|
||||
async def rmbg(client: Client, message: Message):
|
||||
pablo = await edit_or_reply(message, '<code>Processing...</code>')
|
||||
if not message.reply_to_message:
|
||||
await pablo.edit('<code>Reply To A Image Please!</code>')
|
||||
return
|
||||
cool = await convert_to_image(message, client)
|
||||
if not cool:
|
||||
await pablo.edit('<code>Reply to a valid media first.</code>')
|
||||
return
|
||||
start = datetime.now()
|
||||
await pablo.edit('sending to ReMove.BG')
|
||||
input_file_name = cool
|
||||
files = {
|
||||
'image_file': (input_file_name, open(input_file_name, 'rb')),
|
||||
}
|
||||
r = requests.post(
|
||||
'https://api.remove.bg/v1.0/removebg',
|
||||
headers={'X-Api-Key': rmbg_key},
|
||||
files=files,
|
||||
allow_redirects=True,
|
||||
stream=True,
|
||||
timeout=10,
|
||||
)
|
||||
if os.path.exists(cool):
|
||||
os.remove(cool)
|
||||
output_file_name = r
|
||||
contentType = output_file_name.headers.get('content-type')
|
||||
if 'image' in contentType:
|
||||
with io.BytesIO(output_file_name.content) as remove_bg_image:
|
||||
remove_bg_image.name = 'BG_rem.png'
|
||||
await client.send_document(message.chat.id, remove_bg_image, reply_to_message_id=message.id)
|
||||
end = datetime.now()
|
||||
ms = (end - start).seconds
|
||||
await pablo.edit(f"<code>Removed image's Background in {ms} seconds.")
|
||||
if os.path.exists('BG_rem.png'):
|
||||
os.remove('BG_rem.png')
|
||||
else:
|
||||
await pablo.edit('ReMove.BG API returned Errors.' + f'\n`{output_file_name.content.decode("UTF-8")}')
|
||||
|
||||
|
||||
@Client.on_message(filters.command('rebg', prefix) & filters.me)
|
||||
async def rembg(client: Client, message: Message):
|
||||
await message.edit('<code>Processing...</code>')
|
||||
chat_id = message.chat.id
|
||||
try:
|
||||
try:
|
||||
photo_data = await message.download()
|
||||
except ValueError:
|
||||
try:
|
||||
photo_data = await message.reply_to_message.download()
|
||||
except ValueError:
|
||||
await message.edit('<b>File not found</b>')
|
||||
return
|
||||
background_removed_data = remove_background(photo_data)
|
||||
|
||||
if background_removed_data:
|
||||
await message.delete()
|
||||
await client.send_photo(chat_id, photo=background_removed_data, caption='Background removed!')
|
||||
else:
|
||||
await message.edit_text(
|
||||
"`Is Your RMBG Api 'rmbg_key' Valid Or You Didn't Add It??`\n **Check logs for details**",
|
||||
parse_mode=enums.ParseMode.MARKDOWN,
|
||||
)
|
||||
except Exception as e:
|
||||
await message.reply_text(f'An error occurred: {format_exc(e)}')
|
||||
finally:
|
||||
if os.path.exists(photo_data):
|
||||
os.remove(photo_data)
|
||||
|
||||
|
||||
modules_help['removebg'] = {
|
||||
'rebg [reply to image]*': 'remove background from image without transparency',
|
||||
'rmbg [reply to image]*': 'remove background from image with transparency',
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user