Skip to content

Commit b7c3783

Browse files
authored
2 new modules (#96)
* now supports reply * Added fedutils and getmsg modules
1 parent b813b99 commit b7c3783

File tree

2 files changed

+379
-0
lines changed

2 files changed

+379
-0
lines changed

utils/fedutils.py

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
# Moon-Userbot - telegram userbot
2+
# Copyright (C) 2020-present Moon Userbot Organization
3+
#
4+
# This program is free software: you can redistribute it and/or modify
5+
# it under the terms of the GNU General Public License as published by
6+
# the Free Software Foundation, either version 3 of the License, or
7+
# (at your option) any later version.
8+
9+
# This program is distributed in the hope that it will be useful,
10+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
# GNU General Public License for more details.
13+
14+
# You should have received a copy of the GNU General Public License
15+
# along with this program. If not, see <https://www.gnu.org/licenses/>.
16+
17+
import asyncio
18+
from pyrogram import Client, filters
19+
from pyrogram.types import Message
20+
21+
from utils.db import db
22+
from utils.scripts import format_exc
23+
from utils.misc import modules_help, prefix
24+
25+
@Client.on_message(filters.command("fban", prefix) & filters.me)
26+
async def fban_cmd(client: Client, message: Message):
27+
try:
28+
msg = await message.edit("🌙 Starting Federation Ban...")
29+
30+
# Get target and reason
31+
args = message.text.split()
32+
if len(args) < 2 and not message.reply_to_message:
33+
return await msg.edit("❌ Reply to user or provide ID/username and reason")
34+
35+
if message.reply_to_message:
36+
target = message.reply_to_message.from_user.id
37+
reason = " ".join(args[1:]) if len(args) > 1 else ""
38+
else:
39+
target = args[1]
40+
reason = " ".join(args[2:]) if len(args) > 2 else ""
41+
42+
# Get configuration
43+
fban_group = db.get("core.ats", "FBAN_GROUP_ID")
44+
fed_ids = db.get("core.ats", "FED_IDS", [])
45+
46+
if not fban_group:
47+
return await msg.edit("❌ FBAN group not set! Use `.set_fban_group` first")
48+
49+
if not fed_ids:
50+
return await msg.edit("❌ No federations added! Use `.addfed` first")
51+
52+
# Execute commands in FBAN group
53+
await client.send_message(fban_group, f"/fban {target} {reason}")
54+
await asyncio.sleep(2)
55+
56+
for fed_id in fed_ids:
57+
await client.send_message(fban_group, f"/joinfed {fed_id}")
58+
await asyncio.sleep(3)
59+
await client.send_message(fban_group, f"/fban {target} {reason}")
60+
await asyncio.sleep(3)
61+
62+
await msg.edit(f"✅ Successfully FBanned {target} in {len(fed_ids)} federations\n#MoonUB")
63+
64+
except Exception as e:
65+
await msg.edit(f"⚠️ Error: {format_exc(e)}")
66+
67+
@Client.on_message(filters.command("unfban", prefix) & filters.me)
68+
async def unfban_cmd(client: Client, message: Message):
69+
try:
70+
msg = await message.edit("🌙 Starting Federation Unban...")
71+
72+
# Get target and reason
73+
args = message.text.split()
74+
if len(args) < 2 and not message.reply_to_message:
75+
return await msg.edit("❌ Reply to user or provide ID/username and reason")
76+
77+
if message.reply_to_message:
78+
target = message.reply_to_message.from_user.id
79+
reason = " ".join(args[1:]) if len(args) > 1 else ""
80+
else:
81+
target = args[1]
82+
reason = " ".join(args[2:]) if len(args) > 2 else ""
83+
84+
# Get configuration
85+
fban_group = db.get("core.ats", "FBAN_GROUP_ID")
86+
fed_ids = db.get("core.ats", "FED_IDS", [])
87+
88+
if not fban_group:
89+
return await msg.edit("❌ FBAN group not set! Use `.set_fban_group` first")
90+
91+
if not fed_ids:
92+
return await msg.edit("❌ No federations added! Use `.addfed` first")
93+
94+
# Execute commands in FBAN group
95+
await client.send_message(fban_group, f"/unfban {target} {reason}")
96+
await asyncio.sleep(2)
97+
98+
for fed_id in fed_ids:
99+
await client.send_message(fban_group, f"/joinfed {fed_id}")
100+
await asyncio.sleep(3)
101+
await client.send_message(fban_group, f"/unfban {target} {reason}")
102+
await asyncio.sleep(3)
103+
104+
await msg.edit(f"✅ Successfully UnFBanned {target} in {len(fed_ids)} federations\n#MoonUB")
105+
106+
except Exception as e:
107+
await msg.edit(f"⚠️ Error: {format_exc(e)}")
108+
109+
@Client.on_message(filters.command("set_fban_group", prefix) & filters.me)
110+
async def set_fban_group(_, message: Message):
111+
if len(message.command) < 2:
112+
return await message.edit(f"❌ Usage: `{prefix}set_fban_group <group_id>`")
113+
114+
try:
115+
group_id = int(message.command[1])
116+
db.set("core.ats", "FBAN_GROUP_ID", group_id)
117+
await message.edit(f"✅ FBAN group set to `{group_id}`")
118+
except ValueError:
119+
await message.edit("❌ Invalid group ID. Must be a valid integer.")
120+
except Exception as e:
121+
await message.edit(f"⚠️ Error: {format_exc(e)}")
122+
123+
@Client.on_message(filters.command("addfed", prefix) & filters.me)
124+
async def add_fed(_, message: Message):
125+
if len(message.command) < 2:
126+
return await message.edit(f"❌ Usage: `{prefix}addfed <fed_id>`")
127+
128+
fed_id = message.command[1]
129+
current_feds = db.get("core.ats", "FED_IDS", [])
130+
131+
if fed_id in current_feds:
132+
await message.edit("❌ This federation is already in the list")
133+
else:
134+
current_feds.append(fed_id)
135+
db.set("core.ats", "FED_IDS", current_feds)
136+
await message.edit(f"✅ Added federation: `{fed_id}`")
137+
138+
@Client.on_message(filters.command("delfed", prefix) & filters.me)
139+
async def del_fed(_, message: Message):
140+
if len(message.command) < 2:
141+
return await message.edit(f"❌ Usage: `{prefix}delfed <fed_id>`")
142+
143+
fed_id = message.command[1]
144+
current_feds = db.get("core.ats", "FED_IDS", [])
145+
146+
if fed_id not in current_feds:
147+
await message.edit("❌ Federation not found in list")
148+
else:
149+
current_feds.remove(fed_id)
150+
db.set("core.ats", "FED_IDS", current_feds)
151+
await message.edit(f"✅ Removed federation: `{fed_id}`")
152+
153+
@Client.on_message(filters.command("listfed", prefix) & filters.me)
154+
async def list_fed(_, message: Message):
155+
current_feds = db.get("core.ats", "FED_IDS", [])
156+
if not current_feds:
157+
return await message.edit("❌ No federations in list")
158+
159+
fed_list = "\n".join([f"• `{fed}`" for fed in current_feds])
160+
await message.edit(f"📜 Federation List:\n{fed_list}")
161+
162+
modules_help["fedutils"] = {
163+
"fban [reply]/[userid]* [reason]": "Ban user in multiple federations",
164+
"unfban [reply]/[userid]* [reason]": "Unban user from multiple federations",
165+
"set_fban_group [group_id]*": "Set group for FBAN operations",
166+
"addfed [fed_id]*": "Add federation to ban list",
167+
"delfed [fed_id]*": "Remove federation from ban list",
168+
"listfed": "Show current federation list"
169+
}

utils/getmsg.py

Lines changed: 210 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,210 @@
1+
# Moon-Userbot - telegram userbot
2+
# Copyright (C) 2020-present Moon Userbot Organization
3+
#
4+
# This program is free software: you can redistribute it and/or modify
5+
# it under the terms of the GNU General Public License as published by
6+
# the Free Software Foundation, either version 3 of the License, or
7+
# (at your option) any later version.
8+
9+
# This program is distributed in the hope that it will be useful,
10+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
# GNU General Public License for more details.
13+
14+
# You should have received a copy of the GNU General Public License
15+
# along with this program. If not, see <https://www.gnu.org/licenses/>.
16+
17+
import time
18+
import os
19+
import datetime
20+
from typing import Union
21+
22+
from pyrogram import Client, filters
23+
from pyrogram.types import Message
24+
from pyrogram.errors import (
25+
ChatForwardsRestricted,
26+
PeerIdInvalid,
27+
MessageIdInvalid,
28+
MessageTooLong,
29+
FloodWait
30+
)
31+
from pyrogram.enums import MessageMediaType
32+
33+
from utils.misc import modules_help, prefix
34+
from utils.scripts import format_exc
35+
36+
class ProgressTracker:
37+
def __init__(self):
38+
self.last_update = 0
39+
self.update_interval = 1
40+
41+
def should_update(self):
42+
now = time.time()
43+
if now - self.last_update >= self.update_interval:
44+
self.last_update = now
45+
return True
46+
return False
47+
48+
progress_tracker = ProgressTracker()
49+
50+
async def safe_edit(xx: Message, text: str):
51+
try:
52+
if progress_tracker.should_update():
53+
await xx.edit(text)
54+
except FloodWait as e:
55+
await asyncio.sleep(e.value)
56+
except Exception:
57+
pass
58+
59+
def calculate_eta(current: int, total: int, start_time: float) -> str:
60+
try:
61+
elapsed = time.time() - start_time
62+
if elapsed < 0.1 or total == 0:
63+
return "N/A"
64+
65+
speed = current / elapsed
66+
remaining = total - current
67+
eta = remaining / speed
68+
return str(datetime.timedelta(seconds=int(eta)))
69+
except:
70+
return "N/A"
71+
72+
@Client.on_message(filters.command("getmsg", prefix) & filters.me)
73+
async def get_restricted_msg(client: Client, message: Message):
74+
if len(message.command) < 2:
75+
return await message.edit("❗ Please provide a link!")
76+
77+
link = message.command[1]
78+
xx = await message.edit("🔄 Initializing...")
79+
80+
chat, msg_id = get_chat_and_msgid(link)
81+
if not (chat and msg_id):
82+
return await xx.edit("❌ Invalid link format!\nExample: https://t.me/c/1524685769/40392")
83+
84+
try:
85+
msg = await client.get_messages(chat, msg_id)
86+
except Exception as e:
87+
return await xx.edit(f"🚫 Error retrieving message:\n`{format_exc(e)}`")
88+
89+
if not msg:
90+
return await xx.edit("❌ Message not found")
91+
92+
# Try to copy message first
93+
try:
94+
await msg.copy(message.chat.id)
95+
return await xx.delete()
96+
except ChatForwardsRestricted:
97+
pass
98+
except Exception as e:
99+
await xx.edit(f"⚠️ Forward restricted, trying alternative method...")
100+
101+
# Handle media content
102+
if msg.media:
103+
media_path = None
104+
try:
105+
# Download with progress
106+
dl_start = time.time()
107+
108+
async def dl_progress(current, total):
109+
text = (
110+
f"⬇️ Downloading...\n"
111+
f"`{current * 100 / total:.1f}%` | "
112+
f"ETA: `{calculate_eta(current, total, dl_start)}`"
113+
)
114+
await safe_edit(xx, text)
115+
116+
media_path = await msg.download(progress=dl_progress)
117+
118+
# Upload with original formatting
119+
upload_start = time.time()
120+
121+
async def up_progress(current, total):
122+
text = (
123+
f"⬆️ Uploading...\n"
124+
f"`{current * 100 / total:.1f}%` | "
125+
f"ETA: `{calculate_eta(current, total, upload_start)}`"
126+
)
127+
await safe_edit(xx, text)
128+
129+
common_args = {
130+
"caption": msg.caption or "",
131+
"caption_entities": msg.caption_entities or [],
132+
"progress": up_progress
133+
}
134+
135+
if msg.media == MessageMediaType.VIDEO:
136+
await client.send_video(
137+
message.chat.id,
138+
media_path,
139+
duration=msg.video.duration,
140+
width=msg.video.width,
141+
height=msg.video.height,
142+
supports_streaming=True,
143+
**common_args
144+
)
145+
elif msg.media == MessageMediaType.PHOTO:
146+
await client.send_photo(
147+
message.chat.id,
148+
media_path,
149+
**common_args
150+
)
151+
else:
152+
await client.send_document(
153+
message.chat.id,
154+
media_path,
155+
force_document=False,
156+
**common_args
157+
)
158+
159+
await xx.delete()
160+
except Exception as e:
161+
await xx.edit(f"❌ Error processing media:\n`{format_exc(e)}`")
162+
finally:
163+
if media_path and os.path.exists(media_path):
164+
try:
165+
os.remove(media_path)
166+
except Exception as e:
167+
print(f"Error deleting file: {e}")
168+
else:
169+
# Handle text messages with formatting
170+
try:
171+
await xx.edit(
172+
f"📝 **Message content:**\n\n{msg.text}",
173+
entities=msg.entities or []
174+
)
175+
except MessageTooLong:
176+
txt_path = os.path.abspath("message.txt")
177+
try:
178+
with open(txt_path, "w") as f:
179+
f.write(msg.text)
180+
await client.send_document(
181+
message.chat.id,
182+
txt_path,
183+
caption="Original message formatting preserved in file"
184+
)
185+
await xx.delete()
186+
finally:
187+
if txt_path and os.path.exists(txt_path):
188+
try:
189+
os.remove(txt_path)
190+
except Exception as e:
191+
print(f"Error deleting text file: {e}")
192+
193+
def get_chat_and_msgid(link: str) -> Union[tuple, tuple[None, None]]:
194+
try:
195+
parts = link.strip("/").split("/")
196+
if "c" in parts:
197+
c_index = parts.index("c")
198+
channel_id = int(parts[c_index + 1])
199+
msg_id = int(parts[c_index + 2])
200+
return (-1000000000000 - channel_id), msg_id
201+
else:
202+
msg_id = int(parts[-1])
203+
chat_part = parts[-2]
204+
return int(chat_part) if chat_part.isdigit() else chat_part, msg_id
205+
except (ValueError, IndexError, AttributeError):
206+
return None, None
207+
208+
modules_help["getmsg"] = {
209+
"getmsg [link]": "Fetch messages with full formatting preservation and cleanup",
210+
}

0 commit comments

Comments
 (0)