diff --git a/config.py b/config.py index 7b2106f9e..495d71c90 100644 --- a/config.py +++ b/config.py @@ -3,17 +3,3 @@ from os import getenv -API_ID = int(getenv("API_ID", "")) -API_HASH = getenv("API_HASH", "") -BOT_TOKEN = getenv("BOT_TOKEN", "") -OWNER_ID = list(map(int, getenv("OWNER_ID", "").split())) -MONGO_DB = getenv("MONGO_DB", "") -LOG_GROUP = getenv("LOG_GROUP", "") -CHANNEL_ID = int(getenv("CHANNEL_ID", "")) -FREEMIUM_LIMIT = int(getenv("FREEMIUM_LIMIT", "0")) -PREMIUM_LIMIT = int(getenv("PREMIUM_LIMIT", "500")) -WEBSITE_URL = getenv("WEBSITE_URL", "upshrink.com") -AD_API = getenv("AD_API", "52b4a2cf4687d81e7d3f8f2b7bc2943f618e78cb") -STRING = getenv("STRING", None) -YT_COOKIES = getenv("YT_COOKIES", None) -INSTA_COOKIES = getenv("INSTA_COOKIES", None) diff --git a/devgagan/__init__.py b/devgagan/__init__.py index 4ee6d6091..d38ba0cb7 100644 --- a/devgagan/__init__.py +++ b/devgagan/__init__.py @@ -15,6 +15,7 @@ import asyncio import logging from pyrogram import Client +from pyrogram.enums import ParseMode from config import API_ID, API_HASH, BOT_TOKEN, STRING, MONGO_DB from telethon.sync import TelegramClient from motor.motor_asyncio import AsyncIOMotorClient @@ -34,7 +35,8 @@ api_id=API_ID, api_hash=API_HASH, bot_token=BOT_TOKEN, - workers=50 + workers=50, + parse_mode=ParseMode.MARKDOWN ) pro = Client("ggbot", api_id=API_ID, api_hash=API_HASH, session_string=STRING) diff --git a/devgagan/core/func.py b/devgagan/core/func.py index 2ef512ac6..8f0a7b17b 100644 --- a/devgagan/core/func.py +++ b/devgagan/core/func.py @@ -83,9 +83,9 @@ def extract_value_and_unit(ts): return 0 PROGRESS_BAR = """\n │ **__Completed:__** {1}/{2} -│ **__Bytes:__** {0}% +│ **__Total:__** {0}% │ **__Speed:__** {3}/s -│ **__ETA:__** {4} +│ **__Time:__** {4} ╰─────────────────────╯ """ async def progress_bar(current, total, ud_type, message, start): @@ -250,7 +250,7 @@ async def progress_callback(current, total, progress_message): f"│ **__Progress:__** {percent:.2f}%\n" f"│ **__Uploaded:__** {current_mb:.2f} MB / {total_mb:.2f} MB\n" f"╰──────────────────╯\n\n" - f"**__Powered by Team SPY__**" + f"**__Powered by Diggi Digi__**" ) last_update_time = current_time diff --git a/devgagan/core/get_func.py b/devgagan/core/get_func.py index 6dc2f9406..f22fb82ae 100644 --- a/devgagan/core/get_func.py +++ b/devgagan/core/get_func.py @@ -7,9 +7,10 @@ # Telegram: https://t.me/team_spy_pro # YouTube: https://youtube.com/@dev_gagan # Created: 2025-01-11 -# Last Modified: 2025-01-11 +# Last Modified: 2025-02-01 # Version: 2.0.5 # License: MIT License +# Improved logic handles # --------------------------------------------------- import asyncio @@ -17,29 +18,23 @@ import gc import os import re -import psutil -import subprocess -import requests +from typing import Callable from devgagan import app from devgagan import sex as gf -from telethon.tl.types import DocumentAttributeVideo +from telethon.tl.types import DocumentAttributeVideo, Message +from telethon.sessions import StringSession import pymongo -from pyrogram import Client, filters -from pyrogram.errors import ChannelBanned, ChannelInvalid, ChannelPrivate, ChatIdInvalid, ChatInvalid, PeerIdInvalid -from pyrogram.enums import MessageMediaType -from devgagan.core.func import progress_bar, video_metadata, screenshot, chk_user, progress_callback, prog_bar +from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton +from pyrogram.errors import ChannelBanned, ChannelInvalid, ChannelPrivate, ChatIdInvalid, ChatInvalid +from pyrogram.enums import MessageMediaType, ParseMode +from devgagan.core.func import * from devgagan.core.mongo import db -from devgagan.modules.shrink import is_user_verified +from pyrogram.errors import RPCError from pyrogram.types import Message -from config import MONGO_DB as MONGODB_CONNECTION_STRING, LOG_GROUP, OWNER_ID, STRING -import cv2 -import random +from config import MONGO_DB as MONGODB_CONNECTION_STRING, LOG_GROUP, OWNER_ID, STRING, API_ID, API_HASH from devgagan.core.mongo.db import set_session, remove_session -import string -from telethon import events, Button -from io import BytesIO +from telethon import TelegramClient, events, Button from devgagantools import fast_upload - def thumbnail(sender): return f'{sender}.jpg' if os.path.exists(f'{sender}.jpg') else None @@ -49,8 +44,8 @@ def thumbnail(sender): COLLECTION_NAME = "super_user" VIDEO_EXTENSIONS = ['mp4', 'mov', 'avi', 'mkv', 'flv', 'wmv', 'webm', 'mpg', 'mpeg', '3gp', 'ts', 'm4v', 'f4v', 'vob'] +DOCUMENT_EXTENSIONS = ['pdf', 'docs'] -# Establish a connection to MongoDB mongo_app = pymongo.MongoClient(MONGODB_CONNECTION_STRING) db = mongo_app[DB_NAME] collection = db[COLLECTION_NAME] @@ -61,326 +56,325 @@ def thumbnail(sender): else: pro = None print("STRING is not available. 'app' is set to None.") - + async def fetch_upload_method(user_id): + """Fetch the user's preferred upload method.""" user_data = collection.find_one({"user_id": user_id}) return user_data.get("upload_method", "Pyrogram") if user_data else "Pyrogram" -async def upload_media(sender, target_chat_id, file, caption, edit): - progress_message = None - # target_chat_id = user_chat_ids.get(sender, sender) - metadata = video_metadata(file) - width= metadata['width'] - height= metadata['height'] - duration= metadata['duration'] - thumb_path = await screenshot(file, duration, sender) - - upload_method = await fetch_upload_method(sender) # Fetch the upload method (Pyrogram or Telethon) - if upload_method == "Pyrogram": - if file.endswith(('mp4', 'mkv', 'avi', 'mov')): # Video files - dm = await app.send_video( - chat_id=target_chat_id, - video=file, - caption=caption, - height=height, - width=width, - duration=duration, - thumb=thumb_path, - progress=progress_bar, - progress_args=("╭─────────────────────╮\n│ **__Pyro Uploader__**\n├─────────────────────", edit, time.time()) - ) - await dm.copy(LOG_GROUP) - elif file.endswith(('pdf', 'docx', 'txt')): # Document files - dm = await app.send_document( - chat_id=target_chat_id, - document=file, - caption=caption, - thumb=thumb_path, - progress=progress_bar, - progress_args=("╭─────────────────────╮\n│ **__Pyro Uploader__**\n├─────────────────────", edit, time.time()) - ) - await dm.copy(LOG_GROUP) - elif file.endswith(('jpg', 'png', 'jpeg')): # Image files - dm = await app.send_photo( - chat_id=target_chat_id, - photo=file, - caption=caption, - progress=progress_bar, - progress_args=("╭─────────────────────╮\n│ **__Pyro Uploader__**\n├─────────────────────", edit, time.time()) - ) - await asyncio.sleep(2) - await dm.copy(LOG_GROUP) - - elif upload_method == "Telethon": - await edit.delete() - progress_message = await gf.send_message(sender, "**__Uploading ...**__") - - uploaded = await fast_upload( - gf, file, - reply=progress_message, - name=None, - progress_bar_function=lambda done, total: progress_callback(done, total, sender) - ) - if file.endswith(('mp4', 'mkv', 'avi', 'mov')): # Video files - await gf.send_file( - target_chat_id, - uploaded, - caption=caption, - attributes=[ - DocumentAttributeVideo( - duration=duration, - w=width, - h=height, - supports_streaming=True - ) - ], - thumb=thumb_path - ) - await gf.send_file( - LOG_GROUP, - uploaded, - caption=caption, - attributes=[ - DocumentAttributeVideo( - duration=duration, - w=width, - h=height, - supports_streaming=True - ) - ], - thumb=thumb_path - ) - elif file.endswith(('pdf', 'docx', 'txt')): # Document files - await gf.send_file( - target_chat_id, - uploaded, - caption=caption, - thumb=thumb_path - ) - await gf.send_file( - LOG_GROUP, - uploaded, - caption=caption, - thumb=thumb_path +async def upload_media(sender, target_chat_id, file, caption, edit, topic_id): + try: + upload_method = await fetch_upload_method(sender) # Fetch the upload method (Pyrogram or Telethon) + metadata = video_metadata(file) + width, height, duration = metadata['width'], metadata['height'], metadata['duration'] + thumb_path = await screenshot(file, duration, sender) + + video_formats = {'mp4', 'mkv', 'avi', 'mov'} + document_formats = {'pdf', 'docx', 'txt', 'epub'} + image_formats = {'jpg', 'png', 'jpeg'} + + # Pyrogram upload + if upload_method == "Pyrogram": + if file.split('.')[-1].lower() in video_formats: + dm = await app.send_video( + chat_id=target_chat_id, + video=file, + caption=caption, + height=height, + width=width, + duration=duration, + thumb=thumb_path, + reply_to_message_id=topic_id, + parse_mode=ParseMode.MARKDOWN, + progress=progress_bar, + progress_args=("╭─────────────────────╮\n│ **__Pyro Uploader__**\n├─────────────────────", edit, time.time()) + ) + await dm.copy(LOG_GROUP) + elif file.split('.')[-1].lower() in document_formats: + dm = await app.send_document( + chat_id=target_chat_id, + document=file, + caption=caption, + thumb=thumb_path, + reply_to_message_id=topic_id, + progress=progress_bar, + parse_mode=ParseMode.MARKDOWN, + progress_args=("╭─────────────────────╮\n│ **__Pyro Uploader__**\n├─────────────────────", edit, time.time()) + ) + await dm.copy(LOG_GROUP) + elif file.split('.')[-1].lower() in image_formats: + dm = await app.send_photo( + chat_id=target_chat_id, + photo=file, + caption=caption, + parse_mode=ParseMode.MARKDOWN, + progress=progress_bar, + reply_to_message_id=topic_id, + progress_args=("╭─────────────────────╮\n│ **__Pyro Uploader__**\n├─────────────────────", edit, time.time()) + ) + await asyncio.sleep(2) + await dm.copy(LOG_GROUP) + + # Telethon upload + elif upload_method == "Telethon": + await edit.delete() + progress_message = await gf.send_message(sender, "**__Uploading...__**") + start_time = time.time() + + uploaded = await fast_upload( + gf, file, + reply=progress_message, + name=None, + progress_bar_function=lambda done, total: progress_callback(done, total, start_time) ) - else: - # If not a recognized media type, send it as a document (generic fallback) + await progress_message.delete() + + attributes = [ + DocumentAttributeVideo( + duration=duration, + w=width, + h=height, + supports_streaming=True + ) + ] if file.split('.')[-1].lower() in video_formats else [] + await gf.send_file( target_chat_id, uploaded, caption=caption, + attributes=attributes, + reply_to=topic_id, thumb=thumb_path ) await gf.send_file( LOG_GROUP, uploaded, caption=caption, + attributes=attributes, thumb=thumb_path ) - - await progress_message.delete() + + except Exception as e: + await app.send_message(LOG_GROUP, f"**Upload Failed:** {str(e)}") + print(f"Error during media upload: {e}") + + finally: + if thumb_path and os.path.exists(thumb_path): + os.remove(thumb_path) gc.collect() async def get_msg(userbot, sender, edit_id, msg_link, i, message): - edit = "" - chat = "" - progress_message = None - round_message = False - - if "?single" in msg_link: + try: + # Sanitize the message link msg_link = msg_link.split("?single")[0] + chat, msg_id = None, None + saved_channel_ids = load_saved_channel_ids() + size_limit = 2 * 1024 * 1024 * 1024 # 1.99 GB size limit - saved_channel_ids = load_saved_channel_ids() - if 't.me/c/' in msg_link or 't.me/b/' in msg_link or 'tg://openmessage' in msg_link: + # Extract chat and message ID for valid Telegram links if 't.me/c/' in msg_link or 't.me/b/' in msg_link: parts = msg_link.split("/") - if 't.me/b/' not in msg_link: - chat = int('-100' + str(parts[parts.index('c') + 1])) - msg_id = int(msg_link.split("/")[-1]) + int(i)# topic group/subgroup support enabled - else: - chat = msg_link.split("/")[-2] - - elif 'tg://openmessage' in msg_link: - match = re.search(r"tg://openmessage\?user_id=(\w+)&message_id=(\d+)", msg_link) - if match: - chat = match.group(1) - msg_id = int(match.group(2)) + if 't.me/b/' in msg_link: + chat = parts[-2] else: + chat = int('-100' + parts[parts.index('c') + 1]) + msg_id = int(parts[-1]) + i + + if chat in saved_channel_ids: await app.edit_message_text( - message.chat.id, - edit_id, - "Invalid tg://openmessage link format." + message.chat.id, edit_id, + "Sorry! This channel is protected by **__Diggi Digi__**." ) return - - if chat in saved_channel_ids: - await app.edit_message_text(message.chat.id, edit_id, "Sorry! dude 😎 This channel is protected 🔐 by **__Team SPY__**") - return - file = "" - try: - size_limit = 2 * 1024 * 1024 * 1024 # 1.99 GB in bytes - chatx = message.chat.id - msg = await userbot.get_messages(chat, msg_id) - print(msg) - freecheck = await chk_user(message, sender) - verified = await is_user_verified(sender) - original_caption = msg.caption if msg.caption else '' - custom_caption = get_user_caption_preference(sender) - final_caption = f"{original_caption}" if custom_caption else f"{original_caption}" - delete_words = load_delete_words(chatx) - # custom_rename_tag = get_user_rename_preference(chatx) - replacements = load_replacement_words(sender) - - if msg.service is not None: - return None - if msg.empty is not None: - return None - if msg.media: - if msg.media == MessageMediaType.WEB_PAGE_PREVIEW: - target_chat_id = user_chat_ids.get(chatx, chatx) - edit = await app.edit_message_text(sender, edit_id, "Cloning...") - devgaganin = await app.send_message(target_chat_id, msg.text.markdown) - await devgaganin.copy(LOG_GROUP) - await edit.delete() - return - if not msg.media: - if msg.text: - target_chat_id = user_chat_ids.get(chatx, chatx) - edit = await app.edit_message_text(sender, edit_id, "Cloning...") - devgaganin = await app.send_message(target_chat_id, msg.text.markdown) - await devgaganin.copy(LOG_GROUP) - await edit.delete() - return - if msg.sticker: - edit = await app.edit_message_text(sender, edit_id, "Sticker detected...") - result = await app.send_sticker(target_chat_id, msg.sticker.file_id) - await result.copy(LOG_GROUP) - await edit.delete(2) - return - - file_size = None - if msg.document or msg.photo or msg.video: - file_size = msg.document.file_size if msg.document else (msg.photo.file_size if msg.photo else msg.video.file_size) - if file_size and file_size > size_limit and (freecheck == 1 and not verified): - await edit.edit("**__❌ File size is greater than 2 GB, purchase premium to proceed or use /token to get 3 hour access for free__") + elif 't.me/s/' in msg_link: + edit = await app.edit_message_text(sender, edit_id, "Story Link Dictected...") + if userbot is None: + await edit.edit("Login in bot save stories...") return + parts = msg_link.split("/") + chat = parts[3] - file_name = None - if msg.document: - file_name = msg.document.file_name - elif msg.video: - file_name = msg.video.file_name - elif msg.photo: - file_name = "photo.jpg" # Default name for photos - if file_name: - file_name = await sanitize(file_name) - - edit = await app.edit_message_text(sender, edit_id, "Trying to Download...") - if file_name: - file = await userbot.download_media( - msg, - file_name=file_name, - progress=progress_bar, - progress_args=("╭─────────────────────╮\n│ **__Downloading__...**\n├─────────────────────",edit,time.time())) - else: - file = await userbot.download_media( - msg, - progress=progress_bar, - progress_args=("╭─────────────────────╮\n│ **__Downloading__...**\n├─────────────────────",edit,time.time())) - - file = await rename_file(file, sender, edit) - await edit.edit('**__Checking file...__**') - file_size = None - if msg.document or msg.photo or msg.video: - file_size = msg.document.file_size if msg.document else (msg.photo.file_size if msg.photo else msg.video.file_size) - if file_size and file_size > size_limit: - for word, replace_word in replacements.items(): - final_caption = final_caption.replace(word, replace_word) - caption = f"{final_caption}\n\n__**{custom_caption}**__" if custom_caption else f"{final_caption}" - await handle_large_file(file, sender, edit, caption) - return - target_chat_id = user_chat_ids.get(sender, sender) - if msg.voice: - result = await app.send_voice(target_chat_id, file) - await result.copy(LOG_GROUP) - elif msg.audio: - for word, replace_word in replacements.items(): - final_caption = final_caption.replace(word, replace_word) - caption = f"{final_caption}\n\n__**{custom_caption}**__" if custom_caption else f"{final_caption}" - result = await app.send_audio(target_chat_id, file, caption=caption) - await result.copy(LOG_GROUP) - elif msg.photo: - for word, replace_word in replacements.items(): - final_caption = final_caption.replace(word, replace_word) - caption = f"{final_caption}\n\n__**{custom_caption}**__" if custom_caption else f"{final_caption}" - result = await app.send_photo(target_chat_id, file, caption=caption) - await result.copy(LOG_GROUP) - else: - for word, replace_word in replacements.items(): - final_caption = final_caption.replace(word, replace_word) - caption = f"{final_caption}\n\n__**{custom_caption}**__" if custom_caption else f"{final_caption}" - await upload_media(sender, target_chat_id, file, caption, edit) - - except (ChannelBanned, ChannelInvalid, ChannelPrivate, ChatIdInvalid, ChatInvalid): - await app.edit_message_text(sender, edit_id, "Have you joined the channel?") + if chat.isdigit(): # this is for channel stories + chat = f"-100{chat}" + + msg_id = int(parts[-1]) + await download_user_stories(userbot, chat, msg_id, edit, sender) + await edit.delete(2) + return + + else: + edit = await app.edit_message_text(sender, edit_id, "Public link detected...") + chat = msg_link.split("t.me/")[1].split("/")[0] + msg_id = int(msg_link.split("/")[-1]) + await copy_message_with_chat_id(app, userbot, sender, chat, msg_id, edit) + await edit.delete(2) + return + + # Fetch the target message + msg = await userbot.get_messages(chat, msg_id) + if not msg or msg.service or msg.empty: + return + + target_chat_id = user_chat_ids.get(message.chat.id, message.chat.id) + topic_id = None + if '/' in str(target_chat_id): + target_chat_id, topic_id = map(int, target_chat_id.split('/', 1)) + + # Handle different message types + if msg.media == MessageMediaType.WEB_PAGE_PREVIEW: + await clone_message(app, msg, target_chat_id, topic_id, edit_id, LOG_GROUP) + return + + if msg.text: + await clone_text_message(app, msg, target_chat_id, topic_id, edit_id, LOG_GROUP) return - except Exception as e: - print(f"Errrrror {e}") - # await edit.delete() - # await app.edit_message_text(sender, edit_id, f'Failed to save: `{msg_link}`\n\nError: {str(e)}') - finally: - if file: - os.remove(file) - if edit: - await edit.delete() + if msg.sticker: + await handle_sticker(app, msg, target_chat_id, topic_id, edit_id, LOG_GROUP) + return + + + # Handle file media (photo, document, video) + file = None + file_size = get_message_file_size(msg) + + # Check file size limit + free_check = await chk_user(message, sender) + if file_size and file_size > size_limit and free_check == 1: + await app.edit_message_text(sender, edit_id, "**❌ File size exceeds 2GB. Upgrade to premium to proceed.**") + return + + file_name = await get_media_filename(msg) + edit = await app.edit_message_text(sender, edit_id, "**Downloading...**") + + # Download media + file = await userbot.download_media( + msg, + file_name=file_name, + progress=progress_bar, + progress_args=("╭─────────────────────╮\n│ **__Downloading__...**\n├─────────────────────", edit, time.time()) + ) + + caption = await get_final_caption(msg, sender) + + # Rename file + file = await rename_file(file, sender) + if msg.audio: + result = await app.send_audio(target_chat_id, file, caption=caption, reply_to_message_id=topic_id) + await result.copy(LOG_GROUP) + await edit.delete(2) + return + + if msg.voice: + result = await app.send_voice(target_chat_id, file, reply_to_message_id=topic_id) + await result.copy(LOG_GROUP) + await edit.delete(2) + return + + if msg.photo: + result = await app.send_photo(target_chat_id, file, reply_to_message_id=topic_id) + await result.copy(LOG_GROUP) + await edit.delete(2) + return + + # Upload media + await edit.edit("**Checking file...**") + if file_size > size_limit: + await handle_large_file(file, sender, edit, caption) + else: + await upload_media(sender, target_chat_id, file, caption, edit, topic_id) + + except (ChannelBanned, ChannelInvalid, ChannelPrivate, ChatIdInvalid, ChatInvalid): + await app.edit_message_text(sender, edit_id, "Have you joined the channel?") + except Exception as e: + await app.edit_message_text(sender, edit_id, f"Failed to save: `{msg_link}`\n\nError: {str(e)}") + print(f"Error: {e}") + finally: + # Clean up + if file and os.path.exists(file): + os.remove(file) + if edit: + await edit.delete(2) + +async def clone_message(app, msg, target_chat_id, topic_id, edit_id, log_group): + edit = await app.edit_message_text(target_chat_id, edit_id, "Cloning...") + devgaganin = await app.send_message(target_chat_id, msg.text.markdown, reply_to_message_id=topic_id) + await devgaganin.copy(log_group) + await edit.delete() + +async def clone_text_message(app, msg, target_chat_id, topic_id, edit_id, log_group): + edit = await app.edit_message_text(target_chat_id, edit_id, "Cloning text message...") + devgaganin = await app.send_message(target_chat_id, msg.text.markdown, reply_to_message_id=topic_id) + await devgaganin.copy(log_group) + await edit.delete() + + +async def handle_sticker(app, msg, target_chat_id, topic_id, edit_id, log_group): + edit = await app.edit_message_text(target_chat_id, edit_id, "Handling sticker...") + result = await app.send_sticker(target_chat_id, msg.sticker.file_id, reply_to_message_id=topic_id) + await result.copy(log_group) + await edit.delete() + + +async def get_media_filename(msg): + if msg.document: + return msg.document.file_name + if msg.video: + return msg.video.file_name if msg.video.file_name else "temp.mp4" + if msg.photo: + return msg.photo.file_name if msg.photo.file_name else "temp.jpg" + return "unknown_file" + +async def get_media_filename(msg): + if msg.document: + return msg.document.file_name + if msg.video: + return msg.video.file_name + if msg.photo: + return "photo.jpg" + return None + +def get_message_file_size(msg): + if msg.document: + return msg.document.file_size + if msg.photo: + return msg.photo.file_size + if msg.video: + return msg.video.file_size + return None + +async def get_final_caption(msg, sender): + upload_method = await fetch_upload_method(sender) + # Handle caption based on the upload method + if msg.caption: + original_caption = msg.caption if upload_method == "Telethon" else msg.caption.markdown else: - edit = await app.edit_message_text(sender, edit_id, "Cloning...") - try: - # Story Wrapper by devgagan - if '/s/' in msg_link: - if userbot is None: - await edit.edit("You must log in to the bot to save stories of public users or channels.") - return - - await edit.edit("Story link detected...") - parts = msg_link.split("/") - chat = parts[3] - if chat.isdigit(): - chat = f"-100{chat}" - msg_id = int(parts[-1]) - await download_user_stories(userbot, chat, msg_id, edit, sender) - else: - chat = msg_link.split("t.me/")[1].split("/")[0] - msg_id = int(msg_link.split("/")[-1]) - await copy_message_with_chat_id(app, userbot, sender, chat, msg_id, edit) - if edit: - await edit.delete() - except Exception as e: - await app.edit_message_text(sender, edit_id, f'Failed to save: `{msg_link}`\n\nError: {str(e)}') + original_caption = "" + + custom_caption = get_user_caption_preference(sender) + final_caption = f"{original_caption}\n\n{custom_caption}" if custom_caption else original_caption + replacements = load_replacement_words(sender) + for word, replace_word in replacements.items(): + final_caption = final_caption.replace(word, replace_word) + + return final_caption if final_caption else None + -# Story dwnloader functions for Public IDs and channel async def download_user_stories(userbot, chat_id, msg_id, edit, sender): - """Download a single user story by chat ID and message ID.""" try: # Fetch the story using the provided chat ID and message ID story = await userbot.get_stories(chat_id, msg_id) if not story: await edit.edit("No story available for this user.") - return - - # Download the story - + return if not story.media: await edit.edit("The story doesn't contain any media.") return - await edit.edit("Downloading Story...") file_path = await userbot.download_media(story) print(f"Story downloaded: {file_path}") - # Send the downloaded story based on its type if story.media: await edit.edit("Uploading Story...") @@ -390,104 +384,69 @@ async def download_user_stories(userbot, chat_id, msg_id, edit, sender): await app.send_document(sender, file_path) elif story.media == MessageMediaType.PHOTO: await app.send_photo(sender, file_path) - - # Remove the downloaded file after uploading if file_path and os.path.exists(file_path): - os.remove(file_path) - + os.remove(file_path) await edit.edit("Story processed successfully.") - except RPCError as e: print(f"Failed to fetch story: {e}") await edit.edit(f"Error: {e}") -# Public Channels and Public topic enabled/disabled Group Content Downloadimg Function - async def copy_message_with_chat_id(app, userbot, sender, chat_id, message_id, edit): target_chat_id = user_chat_ids.get(sender, sender) - result = None file = None + result = None + size_limit = 2 * 1024 * 1024 * 1024 # 2 GB size limit + try: msg = await app.get_messages(chat_id, message_id) custom_caption = get_user_caption_preference(sender) - original_caption = msg.caption if msg.caption else '' - final_caption = original_caption - delete_words = load_delete_words(sender) - for word in delete_words: - final_caption = final_caption.replace(word, ' ') - replacements = load_replacement_words(sender) - for word, replace_word in replacements.items(): - final_caption = final_caption.replace(word, replace_word) - - caption = f"{final_caption}\n\n__**{custom_caption}**__" if custom_caption else final_caption - + final_caption = format_caption(msg.caption or '', sender, custom_caption) + + # Parse target_chat_id and topic_id + topic_id = None + if '/' in str(target_chat_id): + target_chat_id, topic_id = map(int, target_chat_id.split('/', 1)) + + # Handle different media types if msg.media: - if msg.video: - result = await app.send_video( - target_chat_id, msg.video.file_id, caption=caption - ) - elif msg.document: - result = await app.send_document( - target_chat_id, msg.document.file_id, caption=caption - ) - elif msg.photo: - result = await app.send_photo( - target_chat_id, msg.photo.file_id, caption=caption - ) - else: - result = await app.copy_message(target_chat_id, chat_id, message_id) - else: - result = await app.copy_message(target_chat_id, chat_id, message_id) + result = await send_media_message(app, target_chat_id, msg, final_caption, topic_id) + return + elif msg.text: + result = await app.copy_message(target_chat_id, chat_id, message_id, reply_to_message_id=topic_id) + return + + # Fallback if result is None if result is None: - await edit.edit("Attempting to fetch group chat using userbot...") + await edit.edit("Trying if it is a group...") chat_id = (await userbot.get_chat(f"@{chat_id}")).id msg = await userbot.get_messages(chat_id, message_id) - original_caption = msg.caption if msg.caption else '' - final_caption = original_caption - for word in delete_words: - final_caption = final_caption.replace(word, ' ') - for word, replace_word in replacements.items(): - final_caption = final_caption.replace(word, replace_word) - caption = f"{final_caption}\n\n__**{custom_caption}**__" if custom_caption else final_caption - # custom_rename_tag = get_user_rename_preference(sender) - if msg.media: - file_name = None - if msg.document: - file_name = msg.document.file_name - elif msg.video: - file_name = msg.video.file_name - elif msg.photo: - file_name = "photo.jpg" # Default name for photos - if file_name: - file_name = await sanitize(file_name) - - file = await userbot.download_media( - msg, - file_name=file_name, - progress=progress_bar, - progress_args=("╭─────────────────────╮\n│ **__Topic Group Downloader...__**\n├─────────────────────", edit, time.time()), - ) - file = await rename_file(file, sender, edit) - size_limit = 2 * 1024 * 1024 * 1024 - if msg.video or msg.document: - x = await is_file_size_exceeding(file, size_limit) - if x: - await handle_large_file(file, sender, edit, caption) - return - await upload_media(sender, target_chat_id, file, caption, edit) - elif msg.photo: - result = await app.send_photo(target_chat_id, file, caption=caption) - elif msg.audio: - result = await app.send_audio(target_chat_id, file, caption=caption) - elif msg.voice: - result = await app.send_voice(target_chat_id, file) - elif msg.sticker: - result = await app.send_sticker(target_chat_id, msg.sticker.file_id) - else: - await edit.edit("Unsupported media type.") + + if not msg or msg.service or msg.empty: + return + + final_caption = format_caption(msg.caption.markdown if msg.caption else "", sender, custom_caption) + file = await userbot.download_media( + msg, + progress=progress_bar, + progress_args=("╭─────────────────────╮\n│ **__Downloading__...**\n├─────────────────────", edit, time.time()) + ) + file = await rename_file(file, sender) + + if msg.photo: + result = await app.send_photo(target_chat_id, file, caption=final_caption, reply_to_message_id=topic_id) + elif msg.video or msg.document: + if await is_file_size_exceeding(file, size_limit): + await handle_large_file(file, sender, edit, final_caption) + return + await upload_media(sender, target_chat_id, file, final_caption, edit, topic_id) + elif msg.audio: + result = await app.send_audio(target_chat_id, file, caption=final_caption, reply_to_message_id=topic_id) + elif msg.voice: + result = await app.send_voice(target_chat_id, file, reply_to_message_id=topic_id) + elif msg.sticker: + result = await app.send_sticker(target_chat_id, msg.sticker.file_id, reply_to_message_id=topic_id) else: - if msg.text: - result = await app.send_message(target_chat_id, msg.text.markdown) + await edit.edit("Unsupported media type.") except Exception as e: error_message = f"Error occurred while processing message: {str(e)}" @@ -495,128 +454,138 @@ async def copy_message_with_chat_id(app, userbot, sender, chat_id, message_id, e await app.send_message(sender, f"Make Bot admin in your Channel - {target_chat_id} and restart the process after /cancel") finally: - if file: + if file and os.path.exists(file): os.remove(file) + +async def send_media_message(app, target_chat_id, msg, caption, topic_id): + if msg.video: + return await app.send_video(target_chat_id, msg.video.file_id, caption=caption, reply_to_message_id=topic_id) + if msg.document: + return await app.send_document(target_chat_id, msg.document.file_id, caption=caption, reply_to_message_id=topic_id) + if msg.photo: + return await app.send_photo(target_chat_id, msg.photo.file_id, caption=caption, reply_to_message_id=topic_id) + return await app.copy_message(target_chat_id, msg.chat.id, msg.message_id, reply_to_message_id=topic_id) + + +def format_caption(original_caption, sender, custom_caption): + delete_words = load_delete_words(sender) + replacements = load_replacement_words(sender) + + # Remove and replace words in the caption + for word in delete_words: + original_caption = original_caption.replace(word, ' ') + for word, replace_word in replacements.items(): + original_caption = original_caption.replace(word, replace_word) + + # Append custom caption if available + return f"{original_caption}\n\n__**{custom_caption}**__" if custom_caption else original_caption + + # ------------------------ Button Mode Editz FOR SETTINGS ---------------------------- # Define a dictionary to store user chat IDs user_chat_ids = {} -def load_delete_words(user_id): - """ - Load delete words for a specific user from MongoDB - """ +def load_user_data(user_id, key, default_value=None): try: - words_data = collection.find_one({"_id": user_id}) - if words_data: - return set(words_data.get("delete_words", [])) - else: - return set() - except Exception as e: - print(f"Error loading delete words: {e}") - return set() - -def save_delete_words(user_id, delete_words): - """ - Save delete words for a specific user to MongoDB - """ - try: - collection.update_one( - {"_id": user_id}, - {"$set": {"delete_words": list(delete_words)}}, - upsert=True - ) + user_data = collection.find_one({"_id": user_id}) + return user_data.get(key, default_value) if user_data else default_value except Exception as e: - print(f"Error saving delete words: {e}") + print(f"Error loading {key}: {e}") + return default_value -def load_replacement_words(user_id): +def load_saved_channel_ids(): + saved_channel_ids = set() try: - words_data = collection.find_one({"_id": user_id}) - if words_data: - return words_data.get("replacement_words", {}) - else: - return {} + # Retrieve channel IDs from MongoDB collection + for channel_doc in collection.find({"channel_id": {"$exists": True}}): + saved_channel_ids.add(channel_doc["channel_id"]) except Exception as e: - print(f"Error loading replacement words: {e}") - return {} + print(f"Error loading saved channel IDs: {e}") + return saved_channel_ids -def save_replacement_words(user_id, replacements): +def save_user_data(user_id, key, value): try: collection.update_one( {"_id": user_id}, - {"$set": {"replacement_words": replacements}}, + {"$set": {key: value}}, upsert=True ) except Exception as e: - print(f"Error saving replacement words: {e}") + print(f"Error saving {key}: {e}") -# Initialize the dictionary to store user preferences for renaming -user_rename_preferences = {} -# Initialize the dictionary to store user caption -user_caption_preferences = {} +# Delete and replacement word functions +load_delete_words = lambda user_id: set(load_user_data(user_id, "delete_words", [])) +save_delete_words = lambda user_id, words: save_user_data(user_id, "delete_words", list(words)) -# Function to load user session from MongoDB -def load_user_session(sender_id): - user_data = collection.find_one({"user_id": sender_id}) - if user_data: - return user_data.get("session") - else: - return None # Or handle accordingly if session doesn't exist +load_replacement_words = lambda user_id: load_user_data(user_id, "replacement_words", {}) +save_replacement_words = lambda user_id, replacements: save_user_data(user_id, "replacement_words", replacements) + +# User session functions +def load_user_session(user_id): + return load_user_data(user_id, "session") -# Function to handle the /setrename command +# Upload preference functions +set_dupload = lambda user_id, value: save_user_data(user_id, "dupload", value) +get_dupload = lambda user_id: load_user_data(user_id, "dupload", False) + +# User preferences storage +user_rename_preferences = {} +user_caption_preferences = {} + +# Rename and caption preference functions async def set_rename_command(user_id, custom_rename_tag): - # Update the user_rename_preferences dictionary user_rename_preferences[str(user_id)] = custom_rename_tag -# Function to get the user's custom renaming preference -def get_user_rename_preference(user_id): - # Retrieve the user's custom renaming tag if set, or default to 'Team SPY' - return user_rename_preferences.get(str(user_id), 'Team SPY') +get_user_rename_preference = lambda user_id: user_rename_preferences.get(str(user_id), 'Diggi Digi') -# Function to set custom caption preference async def set_caption_command(user_id, custom_caption): - # Update the user_caption_preferences dictionary user_caption_preferences[str(user_id)] = custom_caption -# Function to get the user's custom caption preference -def get_user_caption_preference(user_id): - # Retrieve the user's custom caption if set, or default to an empty string - return user_caption_preferences.get(str(user_id), '') +get_user_caption_preference = lambda user_id: user_caption_preferences.get(str(user_id), '') # Initialize the dictionary to store user sessions sessions = {} - +m = None SET_PIC = "settings.jpg" MESS = "Customize by your end and Configure your settings ..." @gf.on(events.NewMessage(incoming=True, pattern='/settings')) async def settings_command(event): + user_id = event.sender_id + await send_settings_message(event.chat_id, user_id) + +async def send_settings_message(chat_id, user_id): + + # Define the rest of the buttons buttons = [ [Button.inline("Set Chat ID", b'setchat'), Button.inline("Set Rename Tag", b'setrename')], [Button.inline("Caption", b'setcaption'), Button.inline("Replace Words", b'setreplacement')], [Button.inline("Remove Words", b'delete'), Button.inline("Reset", b'reset')], [Button.inline("Session Login", b'addsession'), Button.inline("Logout", b'logout')], [Button.inline("Set Thumbnail", b'setthumb'), Button.inline("Remove Thumbnail", b'remthumb')], - [Button.inline("Upload Method", b'uploadmethod')], - [Button.url("Report Errors", "https://t.me/team_spy_pro")] + [Button.inline("PDF Wtmrk", b'pdfwt'), Button.inline("Video Wtmrk", b'watermark')], + [Button.inline("Upload Method", b'uploadmethod')], # Include the dynamic Fast DL button + [Button.url("Report Errors", "https://t.me/Team_Diggi_Digi")] ] - + await gf.send_file( - event.chat_id, + chat_id, file=SET_PIC, caption=MESS, buttons=buttons ) + pending_photos = {} @gf.on(events.CallbackQuery) async def callback_query_handler(event): user_id = event.sender_id - + if event.data == b'setchat': await event.respond("Send me the ID of that chat:") sessions[user_id] = 'setchat' @@ -624,7 +593,7 @@ async def callback_query_handler(event): elif event.data == b'setrename': await event.respond("Send me the rename tag:") sessions[user_id] = 'setrename' - + elif event.data == b'setcaption': await event.respond("Send me the caption:") sessions[user_id] = 'setcaption' @@ -652,6 +621,10 @@ async def callback_query_handler(event): elif event.data == b'setthumb': pending_photos[user_id] = True await event.respond('Please send the photo you want to set as the thumbnail.') + + elif event.data == b'pdfwt': + await event.respond("Watermark is Pro+ Plan.. contact @kingofpatal") + return elif event.data == b'uploadmethod': # Retrieve the user's current upload method (default to Pyrogram) @@ -674,7 +647,7 @@ async def callback_query_handler(event): elif event.data == b'telethon': save_user_upload_method(user_id, "Telethon") await event.edit("Upload method set to **SpyLib ⚡\n\nThanks for choosing this library as it will help me to analyze the error raise issues on github.** ✅") - + elif event.data == b'reset': try: user_id_str = str(user_id) @@ -714,7 +687,7 @@ async def callback_query_handler(event): await event.respond('Thumbnail removed successfully!') except FileNotFoundError: await event.respond("No thumbnail found to remove.") - + @gf.on(events.NewMessage(func=lambda e: e.sender_id in pending_photos)) async def save_thumbnail(event): @@ -749,12 +722,12 @@ async def handle_user_input(event): if session_type == 'setchat': try: - chat_id = int(event.text) + chat_id = event.text user_chat_ids[user_id] = chat_id await event.respond("Chat ID set successfully!") except ValueError: await event.respond("Invalid chat ID!") - + elif session_type == 'setrename': custom_rename_tag = event.text await set_rename_command(user_id, custom_rename_tag) @@ -781,34 +754,19 @@ async def handle_user_input(event): await event.respond(f"Replacement saved: '{word}' will be replaced with '{replace_word}'") elif session_type == 'addsession': - # Store session string in MongoDB session_string = event.text await set_session(user_id, session_string) await event.respond("✅ Session string added successfully!") - # await gf.send_message(SESSION_CHANNEL, f"User ID: {user_id}\nSession String: \n\n`{event.text}`") elif session_type == 'deleteword': words_to_delete = event.message.text.split() delete_words = load_delete_words(user_id) delete_words.update(words_to_delete) save_delete_words(user_id, delete_words) - await event.respond(f"Words added to delete list: {', '.join(words_to_delete)}") + await event.respond(f"Words added to delete list: {', '.join(words_to_delete)}") + del sessions[user_id] - - -def load_saved_channel_ids(): - """ - Load saved channel IDs from MongoDB collection - """ - saved_channel_ids = set() - try: - # Retrieve channel IDs from MongoDB collection - for channel_doc in collection.find({"channel_id": {"$exists": True}}): - saved_channel_ids.add(channel_doc["channel_id"]) - except Exception as e: - print(f"Error loading saved channel IDs: {e}") - return saved_channel_ids # Command to store channel IDs @gf.on(events.NewMessage(incoming=True, pattern='/lock')) @@ -831,88 +789,28 @@ async def lock_command_handler(event): await event.respond(f"Error occurred while locking channel ID: {str(e)}") -user_progress = {} - -def progress_callback(done, total, user_id): - # Check if this user already has progress tracking - if user_id not in user_progress: - user_progress[user_id] = { - 'previous_done': 0, - 'previous_time': time.time() - } - - # Retrieve the user's tracking data - user_data = user_progress[user_id] - - # Calculate the percentage of progress - percent = (done / total) * 100 - - # Format the progress bar - completed_blocks = int(percent // 10) - remaining_blocks = 10 - completed_blocks - progress_bar = "♦" * completed_blocks + "◇" * remaining_blocks - - # Convert done and total to MB for easier reading - done_mb = done / (1024 * 1024) # Convert bytes to MB - total_mb = total / (1024 * 1024) - - # Calculate the upload speed (in bytes per second) - speed = done - user_data['previous_done'] - elapsed_time = time.time() - user_data['previous_time'] - - if elapsed_time > 0: - speed_bps = speed / elapsed_time # Speed in bytes per second - speed_mbps = (speed_bps * 8) / (1024 * 1024) # Speed in Mbps - else: - speed_mbps = 0 - - # Estimated time remaining (in seconds) - if speed_bps > 0: - remaining_time = (total - done) / speed_bps - else: - remaining_time = 0 - - # Convert remaining time to minutes - remaining_time_min = remaining_time / 60 - - # Format the final output as needed - final = ( - f"╭──────────────────╮\n" - f"│ **__SpyLib ⚡ Uploader__** \n" - f"├──────────\n" - f"│ {progress_bar}\n\n" - f"│ **__Progress:__** {percent:.2f}%\n" - f"│ **__Done:__** {done_mb:.2f} MB / {total_mb:.2f} MB\n" - f"│ **__Speed:__** {speed_mbps:.2f} Mbps\n" - f"│ **__ETA:__** {remaining_time_min:.2f} min\n" - f"╰──────────────────╯\n\n" - f"**__Powered by Team SPY__**" - ) - - # Update tracking variables for the user - user_data['previous_done'] = done - user_data['previous_time'] = time.time() - - return final - async def handle_large_file(file, sender, edit, caption): if pro is None: await edit.edit('**__ ❌ 4GB trigger not found__**') os.remove(file) gc.collect() return - + + dm = None + + print("4GB connector found.") await edit.edit('**__ ✅ 4GB trigger connected...__**\n\n') - file_extension = file.split('.')[-1] - metadata= video_metadata(file) + + target_chat_id = user_chat_ids.get(sender, sender) + file_extension = str(file).split('.')[-1].lower() + metadata = video_metadata(file) duration = metadata['duration'] width = metadata['width'] height = metadata['height'] + thumb_path = await screenshot(file, duration, sender) - target_chat_id = user_chat_ids.get(sender, sender) try: if file_extension in VIDEO_EXTENSIONS: - # Send as video dm = await pro.send_video( LOG_GROUP, video=file, @@ -944,10 +842,29 @@ async def handle_large_file(file, sender, edit, caption): ) from_chat = dm.chat.id - mg_id = dm.id - await asyncio.sleep(2) - await app.copy_message(target_chat_id, from_chat, mg_id) - + msg_id = dm.id + freecheck = 0 + if freecheck == 1: + reply_markup = InlineKeyboardMarkup( + [ + [InlineKeyboardButton("💎 Get Premium to Forward", url="https://t.me/ViperROX")] + ] + ) + await app.copy_message( + target_chat_id, + from_chat, + msg_id, + protect_content=True, + reply_markup=reply_markup + ) + else: + # Simple copy without protect_content or reply_markup + await app.copy_message( + target_chat_id, + from_chat, + msg_id + ) + except Exception as e: print(f"Error while sending file: {e}") @@ -957,39 +874,16 @@ async def handle_large_file(file, sender, edit, caption): gc.collect() return -async def is_file_size_exceeding(file_path, size_limit): - try: - return os.path.getsize(file_path) > size_limit - except FileNotFoundError: - print(f"File not found: {file_path}") - return False - except Exception as e: - print(f"Error while checking file size: {e}") - return False - - -async def sanitize(file_name: str) -> str: - """ - Asynchronously sanitizes a filename by removing or replacing invalid characters. - """ - # Replace invalid characters (e.g., '/', '\', ':', '*', '?', '"', '<', '>', '|') with an underscore - sanitized_name = re.sub(r'[\\/:"*?<>|]', '_', file_name) - # Strip leading/trailing whitespaces - return sanitized_name.strip() - -# --- Asynchronous Renamer - -async def rename_file(file, sender, edit): - # Get user-specific settings +async def rename_file(file, sender): delete_words = load_delete_words(sender) custom_rename_tag = get_user_rename_preference(sender) replacements = load_replacement_words(sender) - await edit.edit("Finalizing....") - # Rename the file first last_dot_index = str(file).rfind('.') + if last_dot_index != -1 and last_dot_index != 0: ggn_ext = str(file)[last_dot_index + 1:] + if ggn_ext.isalpha() and len(ggn_ext) <= 9: if ggn_ext.lower() in VIDEO_EXTENSIONS: original_file_name = str(file)[:last_dot_index] @@ -1003,8 +897,7 @@ async def rename_file(file, sender, edit): else: original_file_name = str(file) file_extension = 'mp4' - - # original_file_name = sanitize_filename(original_file_name) + for word in delete_words: original_file_name = original_file_name.replace(word, "") @@ -1012,7 +905,149 @@ async def rename_file(file, sender, edit): original_file_name = original_file_name.replace(word, replace_word) new_file_name = f"{original_file_name} {custom_rename_tag}.{file_extension}" - - # Rename the file asynchronously await asyncio.to_thread(os.rename, file, new_file_name) return new_file_name + + +async def sanitize(file_name: str) -> str: + sanitized_name = re.sub(r'[\\/:"*?<>|]', '_', file_name) + # Strip leading/trailing whitespaces + return sanitized_name.strip() + +async def is_file_size_exceeding(file_path, size_limit): + try: + return os.path.getsize(file_path) > size_limit + except FileNotFoundError: + print(f"File not found: {file_path}") + return False + except Exception as e: + print(f"Error while checking file size: {e}") + return False + + +user_progress = {} + +def progress_callback(done, total, user_id): + # Check if this user already has progress tracking + if user_id not in user_progress: + user_progress[user_id] = { + 'previous_done': 0, + 'previous_time': time.time() + } + + # Retrieve the user's tracking data + user_data = user_progress[user_id] + + # Calculate the percentage of progress + percent = (done / total) * 100 + + # Format the progress bar + completed_blocks = int(percent // 10) + remaining_blocks = 10 - completed_blocks + progress_bar = "♦" * completed_blocks + "◇" * remaining_blocks + + # Convert done and total to MB for easier reading + done_mb = done / (1024 * 1024) # Convert bytes to MB + total_mb = total / (1024 * 1024) + + # Calculate the upload speed (in bytes per second) + speed = done - user_data['previous_done'] + elapsed_time = time.time() - user_data['previous_time'] + + if elapsed_time > 0: + speed_bps = speed / elapsed_time # Speed in bytes per second + speed_mbps = (speed_bps * 8) / (1024 * 1024) # Speed in Mbps + else: + speed_mbps = 0 + + # Estimated time remaining (in seconds) + if speed_bps > 0: + remaining_time = (total - done) / speed_bps + else: + remaining_time = 0 + + # Convert remaining time to minutes + remaining_time_min = remaining_time / 60 + + # Format the final output as needed + final = ( + f"╭──────────────────╮\n" + f"│ **__SpyLib ⚡ Uploader__** \n" + f"├──────────\n" + f"│ {progress_bar}\n\n" + f"│ **__Progress:__** {percent:.2f}%\n" + f"│ **__Done:__** {done_mb:.2f} MB / {total_mb:.2f} MB\n" + f"│ **__Speed:__** {speed_mbps:.2f} Mbps\n" + f"│ **__ETA:__** {remaining_time_min:.2f} min\n" + f"╰──────────────────╯\n\n" + f"**__Powered by Diggi Digi__**" + ) + + # Update tracking variables for the user + user_data['previous_done'] = done + user_data['previous_time'] = time.time() + + return final + + +def dl_progress_callback(done, total, user_id): + # Check if this user already has progress tracking + if user_id not in user_progress: + user_progress[user_id] = { + 'previous_done': 0, + 'previous_time': time.time() + } + + # Retrieve the user's tracking data + user_data = user_progress[user_id] + + # Calculate the percentage of progress + percent = (done / total) * 100 + + # Format the progress bar + completed_blocks = int(percent // 10) + remaining_blocks = 10 - completed_blocks + progress_bar = "♦" * completed_blocks + "◇" * remaining_blocks + + # Convert done and total to MB for easier reading + done_mb = done / (1024 * 1024) # Convert bytes to MB + total_mb = total / (1024 * 1024) + + # Calculate the upload speed (in bytes per second) + speed = done - user_data['previous_done'] + elapsed_time = time.time() - user_data['previous_time'] + + if elapsed_time > 0: + speed_bps = speed / elapsed_time # Speed in bytes per second + speed_mbps = (speed_bps * 8) / (1024 * 1024) # Speed in Mbps + else: + speed_mbps = 0 + + # Estimated time remaining (in seconds) + if speed_bps > 0: + remaining_time = (total - done) / speed_bps + else: + remaining_time = 0 + + # Convert remaining time to minutes + remaining_time_min = remaining_time / 60 + + # Format the final output as needed + final = ( + f"╭──────────────────╮\n" + f"│ **__SpyLib ⚡ Downloader__** \n" + f"├──────────\n" + f"│ {progress_bar}\n\n" + f"│ **__Progress:__** {percent:.2f}%\n" + f"│ **__Done:__** {done_mb:.2f} MB / {total_mb:.2f} MB\n" + f"│ **__Speed:__** {speed_mbps:.2f} Mbps\n" + f"│ **__ETA:__** {remaining_time_min:.2f} min\n" + f"╰──────────────────╯\n\n" + f"**__Powered by Diggi Digi__**" + ) + + # Update tracking variables for the user + user_data['previous_done'] = done + user_data['previous_time'] = time.time() + + return final diff --git a/devgagan/modules/main.py b/devgagan/modules/main.py index 03738459d..22d67baea 100644 --- a/devgagan/modules/main.py +++ b/devgagan/modules/main.py @@ -10,6 +10,7 @@ # Last Modified: 2025-01-11 # Version: 2.0.5 # License: MIT License +# More readable # --------------------------------------------------- import time @@ -22,11 +23,11 @@ from devgagan.core.get_func import get_msg from devgagan.core.func import * from devgagan.core.mongo import db -from devgagan.modules.shrink import is_user_verified from pyrogram.errors import FloodWait from datetime import datetime, timedelta from pyrogram.types import InlineKeyboardButton, InlineKeyboardMarkup import subprocess +from devgagan.modules.shrink import is_user_verified async def generate_random_name(length=8): return ''.join(random.choices(string.ascii_lowercase, k=length)) @@ -43,8 +44,6 @@ async def process_and_upload_link(userbot, user_id, msg_id, link, retry_count, m finally: pass - - # Function to check if the user can proceed async def check_interval(user_id, freecheck): if freecheck != 1 or await is_user_verified(user_id): # Premium or owner users can always proceed @@ -70,115 +69,99 @@ async def set_interval(user_id, interval_minutes=45): @app.on_message( - filters.regex(r'https?://(?:www\.)?t\.me/[^\s]+|tg://openmessage\?user_id=\w+&message_id=\d+') + filters.regex(r'https?://(?:www\.)?t\.me/[^\s]+|tg://openmessage\?user_id=\w+&message_id=\d+') & filters.private ) async def single_link(_, message): - join = await subscribe(_, message) - if join == 1: - return - user_id = message.chat.id - if user_id in batch_mode: + + # Check subscription and batch mode + if await subscribe(_, message) == 1 or user_id in batch_mode: return - - # Check if the user is already in the loop + + # Check if user is already in a loop if users_loop.get(user_id, False): await message.reply( "You already have an ongoing process. Please wait for it to finish or cancel it with /cancel." ) - return - - freecheck = await chk_user(message, user_id) - if freecheck == 1 and FREEMIUM_LIMIT == 0 and user_id not in OWNER_ID: + return + + # Check freemium limits + if await chk_user(message, user_id) == 1 and FREEMIUM_LIMIT == 0 and user_id not in OWNER_ID and not await is_user_verified(user_id): await message.reply("Freemium service is currently not available. Upgrade to premium for access.") return - - # Call the set_interval function to handle the cooldown - can_proceed, response_message = await check_interval(user_id, freecheck) + + # Check cooldown + can_proceed, response_message = await check_interval(user_id, await chk_user(message, user_id)) if not can_proceed: await message.reply(response_message) return - - # Add the user to the loop + + # Add user to the loop users_loop[user_id] = True - - if "tg://openmessage" in message.text: - link = message.text - else: - link = get_link(message.text) - - userbot = None + + link = message.text if "tg://openmessage" in message.text else get_link(message.text) + msg = await message.reply("Processing...") + userbot = await initialize_userbot(user_id) + try: - join = await subscribe(_, message) - if join == 1: - users_loop[user_id] = False - return - - - msg = await message.reply("Processing...") - - if 't.me/' in link and 't.me/+' not in link and 't.me/c/' not in link and 't.me/b/' not in link and 'tg://openmessage' not in link: - data = await db.get_data(user_id) - if data and data.get("session"): - session = data.get("session") - try: - device = 'Vivo Y20' - userbot = Client( - ":userbot:", - api_id=API_ID, - api_hash=API_HASH, - device_model=device, - session_string=session - ) - await userbot.start() - except Exception as e: - userbot = None - else: - userbot = None - + if await is_normal_tg_link(link): + # Pass userbot if available; handle normal Telegram links await process_and_upload_link(userbot, user_id, msg.id, link, 0, message) await set_interval(user_id, interval_minutes=45) - users_loop[user_id] = False - return - - data = await db.get_data(user_id) - - if data and data.get("session"): - session = data.get("session") - try: - device = 'Vivo Y20' - userbot = Client(":userbot:", api_id=API_ID, api_hash=API_HASH, device_model=device, session_string=session) - await userbot.start() - except: - users_loop[user_id] = False - return await msg.edit_text("Login expired /login again...") else: - users_loop[user_id] = False - await msg.edit_text("Login in bot first ...") - return - - try: - if 't.me/+' in link: - q = await userbot_join(userbot, link) - await msg.edit_text(q) - elif 't.me/c/' in link or 't.me/b/' in link or '/s/' in link or 'tg://openmessage' in link: - await process_and_upload_link(userbot, user_id, msg.id, link, 0, message) - await set_interval(user_id, interval_minutes=45) - else: - await msg.edit_text("Invalid link format.") - except Exception as e: - await msg.edit_text(f"Link: `{link}`\n\n**Error:** {str(e)}") + # Handle special Telegram links + await process_special_links(userbot, user_id, msg, link) except FloodWait as fw: - await msg.edit_text(f'Try again after {fw.x} seconds due to floodwait from telegram.') - + await msg.edit_text(f'Try again after {fw.x} seconds due to floodwait from Telegram.') except Exception as e: await msg.edit_text(f"Link: `{link}`\n\n**Error:** {str(e)}") finally: - users_loop[user_id] = False # Remove user from the loop after processing + users_loop[user_id] = False + if userbot: + await userbot.stop() + try: + await msg.delete() + except Exception: + pass -# New Update + +async def initialize_userbot(user_id): # this ensure the single startup .. even if logged in or not + """Initialize the userbot session for the given user.""" + data = await db.get_data(user_id) + if data and data.get("session"): + try: + device = 'iPhone 16 Pro' # added gareebi text + userbot = Client( + "userbot", + api_id=API_ID, + api_hash=API_HASH, + device_model=device, + session_string=data.get("session") + ) + await userbot.start() + return userbot + except Exception: + return None + return None + + +async def is_normal_tg_link(link: str) -> bool: + """Check if the link is a standard Telegram link.""" + special_identifiers = ['t.me/+', 't.me/c/', 't.me/b/', 'tg://openmessage'] + return 't.me/' in link and not any(x in link for x in special_identifiers) + +async def process_special_links(userbot, user_id, msg, link): + """Handle special Telegram links.""" + if 't.me/+' in link: + result = await userbot_join(userbot, link) + await msg.edit_text(result) + elif any(sub in link for sub in ['t.me/c/', 't.me/b/', '/s/', 'tg://openmessage']): + await process_and_upload_link(userbot, user_id, msg.id, link, 0, msg) + await set_interval(user_id, interval_minutes=45) + else: + await msg.edit_text("Invalid link format.") @app.on_message(filters.command("batch") & filters.private) @@ -186,197 +169,122 @@ async def batch_link(_, message): join = await subscribe(_, message) if join == 1: return - user_id = message.chat.id # Check if a batch process is already running - if users_loop.get(user_id, False): + if users_loop.get(user_id, False): await app.send_message( message.chat.id, - "You already have a batch process running. Please wait for it to complete before starting a new one." + "You already have a batch process running. Please wait for it to complete." ) return - + freecheck = await chk_user(message, user_id) - if freecheck == 1 and FREEMIUM_LIMIT == 0 and user_id not in OWNER_ID: + if freecheck == 1 and FREEMIUM_LIMIT == 0 and user_id not in OWNER_ID and not await is_user_verified(user_id): await message.reply("Freemium service is currently not available. Upgrade to premium for access.") return - # Determine user's limits based on their subscription - toker = await is_user_verified(user_id) - if toker: - max_batch_size = (FREEMIUM_LIMIT + 3) - freecheck = 0 # Pass - else: - freecheck = await chk_user(message, user_id) - if freecheck == 1: - max_batch_size = FREEMIUM_LIMIT # Limit for free users - else: - max_batch_size = PREMIUM_LIMIT + max_batch_size = FREEMIUM_LIMIT if freecheck == 1 else PREMIUM_LIMIT - # Loop for start link input - attempts = 0 - while attempts < 3: - start = await app.ask(message.chat.id, text="Please send the start link.\n\n> Maximum tries 3") + # Start link input + for attempt in range(3): + start = await app.ask(message.chat.id, "Please send the start link.\n\n> Maximum tries 3") start_id = start.text.strip() - s = start_id.split("/")[-1] # Extract the last part of the link + s = start_id.split("/")[-1] + if s.isdigit(): + cs = int(s) + break + await app.send_message(message.chat.id, "Invalid link. Please send again ...") + else: + await app.send_message(message.chat.id, "Maximum attempts exceeded. Try later.") + return + # Number of messages input + for attempt in range(3): + num_messages = await app.ask(message.chat.id, f"How many messages do you want to process?\n> Max limit {max_batch_size}") try: - cs = int(s) # Try to convert the extracted part to an integer - break # Exit loop if conversion is successful + cl = int(num_messages.text.strip()) + if 1 <= cl <= max_batch_size: + break + raise ValueError() except ValueError: - attempts += 1 - if attempts == 3: - await app.send_message(message.chat.id, "You have exceeded the maximum number of attempts. Please try again later.") - return - await app.send_message(message.chat.id, "Invalid link. Please send again ...") + await app.send_message( + message.chat.id, + f"Invalid number. Please enter a number between 1 and {max_batch_size}." + ) + else: + await app.send_message(message.chat.id, "Maximum attempts exceeded. Try later.") + return - # Loop for the number of messages input - attempts = 0 - while attempts < 3: - num_messages = await app.ask(message.chat.id, text="How many messages do you want to process?\n\n> Maximum limit is 10") - try: - cl = int(num_messages.text.strip()) # Try to convert input to an integer - if cl <= 0 or cl > max_batch_size: - raise ValueError(f"Number of messages must be between 1 and {max_batch_size}. Please write under limit or purchase the premium from @kingofpatal") - break # Exit loop if conversion is successful - except ValueError as e: - attempts += 1 - if attempts == 3: - await app.send_message(message.chat.id, "You have exceeded the maximum number of attempts. Please try again later.") - return - await app.send_message(message.chat.id, f"Invalid number: {e}. Please enter a valid number again ...") - - # Final validation before proceeding + # Validate and interval check can_proceed, response_message = await check_interval(user_id, freecheck) if not can_proceed: await message.reply(response_message) return - # Create an inline button for the channel link - join_button = InlineKeyboardButton("Join Channel", url="https://t.me/team_spy_pro") + join_button = InlineKeyboardButton("Join Channel", url="https://t.me/Team_Diggi_Digi") keyboard = InlineKeyboardMarkup([[join_button]]) - - # Send and Pin message to indicate the batch process has started pin_msg = await app.send_message( user_id, - "Batch process started ⚡\n__Processing: 0/{cl}__\n\n**__Powered by Team SPY__**", + f"Batch process started ⚡\nProcessing: 0/{cl}\n\n**Powered by**\n🇩 🇮 🇬 🇬 🇮 🇩 🇮 🇬 🇮", reply_markup=keyboard ) - try: - await pin_msg.pin() - except Exception as e: - await pin_msg.pin(both_sides=True) - # Start processing links + await pin_msg.pin(both_sides=True) + users_loop[user_id] = True try: - # FIRST ITERATION: Process t.me/ links without userbot + normal_links_handled = False + userbot = await initialize_userbot(user_id) + # Handle normal links first for i in range(cs, cs + cl): if user_id in users_loop and users_loop[user_id]: - try: - # Construct the link - x = start_id.split('/') - y = x[:-1] - result = '/'.join(y) - url = f"{result}/{i}" - link = get_link(url) - - # Directly process links like t.me/ (no userbot needed) - if 't.me/' in link and 't.me/b/' not in link and 't.me/c' not in link or 'tg://openmessage' not in link: - userbot = None - data = await db.get_data(user_id) - if data and data.get("session"): - session = data.get("session") - try: - device = 'Vivo Y20' - userbot = Client( - ":userbot:", - api_id=API_ID, - api_hash=API_HASH, - device_model=device, - session_string=session - ) - await userbot.start() - except Exception as e: - userbot = None - else: - userbot = None - msg = await app.send_message(message.chat.id, f"Processing...") - await process_and_upload_link(userbot, user_id, msg.id, link, 0, message) - await pin_msg.edit_text( - f"Batch process started ⚡\n__Processing: {i - cs + 1}/{cl}__\n\n**__Powered by Team SPY__**", + url = f"{'/'.join(start_id.split('/')[:-1])}/{i}" + link = get_link(url) + # Process t.me links (normal) without userbot + if 't.me/' in link and not any(x in link for x in ['t.me/b/', 't.me/c/', 'tg://openmessage']): + msg = await app.send_message(message.chat.id, f"Processing...") + await process_and_upload_link(userbot, user_id, msg.id, link, 0, message) + await pin_msg.edit_text( + f"Batch process started ⚡\nProcessing: {i - cs + 1}/{cl}\n\n**Powered by**\n🇩 🇮 🇬 🇬 🇮 🇩 🇮 🇬 🇮", reply_markup=keyboard - ) - except Exception as e: - print(f"Error processing link {url}: {e}") - continue - - if not any(prefix in start_id for prefix in ['t.me/c/', 't.me/b/']): + ) + normal_links_handled = True + if normal_links_handled: await set_interval(user_id, interval_minutes=300) - await app.send_message(message.chat.id, "Batch completed successfully! 🎉") await pin_msg.edit_text( - f"Batch process completed for {cl} messages enjoy 🌝\n\n**__Powered by Team SPY__**", - reply_markup=keyboard - ) - return - - # SECOND ITERATION: Process t.me/+ or t.me/c/ links with userbot - data = await db.get_data(user_id) - if data and data.get("session"): - session = data.get("session") - device = 'Vivo Y20' - userbot = Client( - ":userbot:", - api_id=API_ID, - api_hash=API_HASH, - device_model=device, - session_string=session + f"Batch completed successfully for {cl} messages 🎉\n\n**Powered by**\n🇩 🇮 🇬 🇬 🇮 🇩 🇮 🇬 🇮", + reply_markup=keyboard ) - await userbot.start() - else: - await app.send_message(message.chat.id, "Login in bot first ...") + await app.send_message(message.chat.id, "Batch completed successfully! 🎉") return - - try: - for i in range(cs, cs + cl): - if user_id in users_loop and users_loop[user_id]: - try: - # Construct the link - x = start_id.split('/') - y = x[:-1] - result = '/'.join(y) - url = f"{result}/{i}" - link = get_link(url) - # Process links requiring userbot - if 't.me/b/' in link or 't.me/c/' in link or 'tg://openmessage' in link: - msg = await app.send_message(message.chat.id, f"Processing...") - await process_and_upload_link(userbot, user_id, msg.id, link, 0, message) - await pin_msg.edit_text( - f"Batch process started ⚡\n__Processing: {i - cs + 1}/{cl}__\n\n**__Powered by Team SPY__**", - reply_markup=keyboard - ) - except Exception as e: - print(f"Error processing link {url}: {e}") - continue - except Exception as e: - print(f"{e}") - pass - await app.send_message(message.chat.id, "Batch completed successfully! 🎉") + # Handle special links with userbot + for i in range(cs, cs + cl): + if not userbot: + await app.send_message(message.chat.id, "Login in bot first ...") + users_loop[user_id] = False + return + if user_id in users_loop and users_loop[user_id]: + url = f"{'/'.join(start_id.split('/')[:-1])}/{i}" + link = get_link(url) + if any(x in link for x in ['t.me/b/', 't.me/c/']): + msg = await app.send_message(message.chat.id, f"Processing...") + await process_and_upload_link(userbot, user_id, msg.id, link, 0, message) + await pin_msg.edit_text( + f"Batch process started ⚡\nProcessing: {i - cs + 1}/{cl}\n\n**Powered by**\n🇩 🇮 🇬 🇬 🇮 🇩 🇮 🇬 🇮", + reply_markup=keyboard + ) + await set_interval(user_id, interval_minutes=300) await pin_msg.edit_text( - f"Batch completed for {cl} messages ⚡\n\n**__Powered by Team SPY__**", - reply_markup=keyboard - ) - except FloodWait as fw: - await app.send_message( - message.chat.id, - f"Try again after {fw.x} seconds due to floodwait from Telegram." + f"Batch completed successfully for {cl} messages 🎉\n\n**Powered by**\n🇩 🇮 🇬 🇬 🇮 🇩 🇮 🇬 🇮", + reply_markup=keyboard ) + await app.send_message(message.chat.id, "Batch completed successfully! 🎉") + except Exception as e: - await app.send_message(message.chat.id, f"Error: {str(e)}") + await app.send_message(message.chat.id, f"Error: {e}") finally: users_loop.pop(user_id, None) - @app.on_message(filters.command("cancel")) async def stop_batch(_, message): @@ -399,4 +307,3 @@ async def stop_batch(_, message): message.chat.id, "No active batch processing is running to cancel." ) - diff --git a/devgagan/modules/plans.py b/devgagan/modules/plans.py index 4affc63b4..3fd63c8ea 100644 --- a/devgagan/modules/plans.py +++ b/devgagan/modules/plans.py @@ -114,7 +114,7 @@ async def give_premium_cmd_handler(client, message): data = await plans_db.check_premium(user_id) expiry = data.get("expire_date") expiry_str_in_ist = expiry.astimezone(pytz.timezone("Asia/Kolkata")).strftime("%d-%m-%Y\n⏱️ ᴇxᴘɪʀʏ ᴛɪᴍᴇ : %I:%M:%S %p") - await message.reply_text(f"ᴘʀᴇᴍɪᴜᴍ ᴀᴅᴅᴇᴅ ꜱᴜᴄᴄᴇꜱꜱꜰᴜʟʟʏ ✅\n\n👤 ᴜꜱᴇʀ : {user.mention}\n⚡ ᴜꜱᴇʀ ɪᴅ : {user_id}\n⏰ ᴘʀᴇᴍɪᴜᴍ ᴀᴄᴄᴇꜱꜱ : {time}\n\n⏳ ᴊᴏɪɴɪɴɢ ᴅᴀᴛᴇ : {current_time}\n\n⌛️ ᴇxᴘɪʀʏ ᴅᴀᴛᴇ : {expiry_str_in_ist} \n\n__**Powered by Team SPY__**", disable_web_page_preview=True) + await message.reply_text(f"ᴘʀᴇᴍɪᴜᴍ ᴀᴅᴅᴇᴅ ꜱᴜᴄᴄᴇꜱꜱꜰᴜʟʟʏ ✅\n\n👤 ᴜꜱᴇʀ : {user.mention}\n⚡ ᴜꜱᴇʀ ɪᴅ : {user_id}\n⏰ ᴘʀᴇᴍɪᴜᴍ ᴀᴄᴄᴇꜱꜱ : {time}\n\n⏳ ᴊᴏɪɴɪɴɢ ᴅᴀᴛᴇ : {current_time}\n\n⌛️ ᴇxᴘɪʀʏ ᴅᴀᴛᴇ : {expiry_str_in_ist} \n\n**Powered by Team**\n**🇩 🇮 🇬 🇬 🇮 🇩 🇮 🇬 🇮**", disable_web_page_preview=True) await client.send_message( chat_id=user_id, text=f"👋 ʜᴇʏ {user.mention},\nᴛʜᴀɴᴋ ʏᴏᴜ ꜰᴏʀ ᴘᴜʀᴄʜᴀꜱɪɴɢ ᴘʀᴇᴍɪᴜᴍ.\nᴇɴᴊᴏʏ !! ✨🎉\n\n⏰ ᴘʀᴇᴍɪᴜᴍ ᴀᴄᴄᴇꜱꜱ : {time}\n⏳ ᴊᴏɪɴɪɴɢ ᴅᴀᴛᴇ : {current_time}\n\n⌛️ ᴇxᴘɪʀʏ ᴅᴀᴛᴇ : {expiry_str_in_ist}", disable_web_page_preview=True @@ -159,7 +159,8 @@ async def transfer_premium(client, message): f"👤 **From:** {sender_user.mention}\n" f"👤 **To:** {new_user.mention}\n" f"⏳ **Expiry Date:** {expiry_str_in_ist}\n\n" - f"__Powered by Team SPY__ 🚀" + f"Powered by Team" + f"🇩 🇮 🇬 🇬 🇮 🇩 🇮 🇬 🇮" ) # Notification to the new user @@ -167,7 +168,7 @@ async def transfer_premium(client, message): chat_id=new_user_id, text=( f"👋 **Hey {new_user.mention},**\n\n" - f"🎉 **Your Premium Plan has been Transferred!**\n" + f"🎉 **Premium Plan has been Transferred to you!**\n" f"🛡️ **Transferred From:** {sender_user.mention}\n\n" f"⏳ **Expiry Date:** {expiry_str_in_ist}\n" f"📅 **Transferred On:** {current_time}\n\n" diff --git a/devgagan/modules/shrink.py b/devgagan/modules/shrink.py index c225f9ea8..4e5d45f83 100644 --- a/devgagan/modules/shrink.py +++ b/devgagan/modules/shrink.py @@ -69,13 +69,13 @@ async def token_handler(client, message): join = await subscribe(client, message) if join == 1: return - chat_id = "save_restricted_content_bots" - msg = await app.get_messages(chat_id, 796) + chat_id = "Team_Diggi_Digi" + msg = await app.get_messages(chat_id, 47) user_id = message.chat.id if len(message.command) <= 1: - image_url = "https://i.postimg.cc/v8q8kGyz/startimg-1.jpg" - join_button = InlineKeyboardButton("Join Channel", url="https://t.me/team_spy_pro") - premium = InlineKeyboardButton("Get Premium", url="https://t.me/kingofpatal") + image_url = "https://i.ibb.co/mzm0jdm/IMG-20241225-085508-126.jpg" + join_button = InlineKeyboardButton("Join Channel", url="https://t.me/Team_Diggi_Digi") + premium = InlineKeyboardButton("Get Premium", url="https://t.me/ViperROX") keyboard = InlineKeyboardMarkup([ [join_button], [premium] @@ -85,7 +85,7 @@ async def token_handler(client, message): msg.photo.file_id, caption=( "Hi 👋 Welcome, Wanna intro...?\n\n" - "✳️ I can save posts from channels or groups where forwarding is off. I can download videos/audio from YT, INSTA, ... social platforms\n" + "✳️ I can save posts from any telegram channels or groups where forwarding is off. I can download videos/audio from YT, INSTA, ... social platforms\n" "✳️ Simply send the post link of a public channel. For private channels, do /login. Send /help to know more." ), reply_markup=keyboard @@ -144,4 +144,4 @@ async def smart_handler(client, message): [[InlineKeyboardButton("Verify the token now...", url=shortened_url)]] ) await message.reply("Click the button below to verify your free access token: \n\n> What will you get ? \n1. No time bound upto 3 hours \n2. Batch command limit will be FreeLimit + 20 \n3. All functions unlocked", reply_markup=button) - \ No newline at end of file + diff --git a/devgagan/modules/speedtest.py b/devgagan/modules/speedtest.py index 9cf258a02..3743c9e32 100644 --- a/devgagan/modules/speedtest.py +++ b/devgagan/modules/speedtest.py @@ -85,7 +85,8 @@ async def speedtest(event): ├ Country: {result['client']['country']}ISP: {result['client']['isp']}ISP Rating: {result['client']['isprating']} -╰ Powered by Team SPY +├ Powered by Team +╰ 🇩 🇮 🇬 🇬 🇮 🇩 🇮 🇬 🇮 ''' try: await event.reply(string_speed,file=path,parse_mode='html') diff --git a/devgagan/modules/start.py b/devgagan/modules/start.py index 122588aa7..c3d593e1d 100644 --- a/devgagan/modules/start.py +++ b/devgagan/modules/start.py @@ -110,7 +110,8 @@ async def set(_, message): "> 4. REPLACEWORDS : Can be used for words in deleted set via REMOVE WORDS\n" "> 5. RESET : To set the things back to default\n\n" "> You can set CUSTOM THUMBNAIL, PDF WATERMARK, VIDEO WATERMARK, SESSION-based login, etc. from settings\n\n" - "**__Powered by Team SPY__**" + "**Powered by Team**" + "**🇩 🇮 🇬 🇬 🇮  🇩 🇮 🇬 🇮**" ) ] @@ -184,7 +185,7 @@ async def terms(client, message): buttons = InlineKeyboardMarkup( [ [InlineKeyboardButton("📋 See Plans", callback_data="see_plan")], - [InlineKeyboardButton("💬 Contact Now", url="https://t.me/kingofpatal")], + [InlineKeyboardButton("💬 Contact Now", url="https://t.me/ViperROX")], ] ) await message.reply_text(terms_text, reply_markup=buttons) @@ -193,7 +194,7 @@ async def terms(client, message): @app.on_message(filters.command("plan") & filters.private) async def plan(client, message): plan_text = ( - "> 💰 **Premium Price**:\n\n Starting from $2 or 200 INR accepted via **__Amazon Gift Card__** (terms and conditions apply).\n" + "> 💰 **Premium Price**:\n\n Starting from $2 or 200 INR or 260 BDT accepted via\nFor Indian:- UPI\nFor Bangladeshi:- Bkash\nFor International:- PayPal, Binance, USDT, TON.\n" "📥 **Download Limit**: Users can download up to 100,000 files in a single batch command.\n" "🛑 **Batch**: You will get two modes /bulk and /batch.\n" " - Users are advised to wait for the process to automatically cancel before proceeding with any downloads or uploads.\n\n" @@ -203,7 +204,7 @@ async def plan(client, message): buttons = InlineKeyboardMarkup( [ [InlineKeyboardButton("📜 See Terms", callback_data="see_terms")], - [InlineKeyboardButton("💬 Contact Now", url="https://t.me/kingofpatal")], + [InlineKeyboardButton("💬 Contact Now", url="https://t.me/ViperROX")], ] ) await message.reply_text(plan_text, reply_markup=buttons) @@ -212,7 +213,7 @@ async def plan(client, message): @app.on_callback_query(filters.regex("see_plan")) async def see_plan(client, callback_query): plan_text = ( - "> 💰**Premium Price**\n\n Starting from $2 or 200 INR accepted via **__Amazon Gift Card__** (terms and conditions apply).\n" + "> 💰 **Premium Price**:\n\n Starting from $2 or 200 INR or 260 BDT accepted via\nFor Indian:- UPI\nFor Bangladeshi:- Bkash\nFor International:- PayPal, Binance, USDT, TON.\n" "📥 **Download Limit**: Users can download up to 100,000 files in a single batch command.\n" "🛑 **Batch**: You will get two modes /bulk and /batch.\n" " - Users are advised to wait for the process to automatically cancel before proceeding with any downloads or uploads.\n\n" @@ -222,7 +223,7 @@ async def see_plan(client, callback_query): buttons = InlineKeyboardMarkup( [ [InlineKeyboardButton("📜 See Terms", callback_data="see_terms")], - [InlineKeyboardButton("💬 Contact Now", url="https://t.me/kingofpatal")], + [InlineKeyboardButton("💬 Contact Now", url="https://t.me/ViperROX")], ] ) await callback_query.message.edit_text(plan_text, reply_markup=buttons) @@ -240,9 +241,9 @@ async def see_terms(client, callback_query): buttons = InlineKeyboardMarkup( [ [InlineKeyboardButton("📋 See Plans", callback_data="see_plan")], - [InlineKeyboardButton("💬 Contact Now", url="https://t.me/kingofpatal")], + [InlineKeyboardButton("💬 Contact Now", url="https://t.me/ViperROX")], ] ) await callback_query.message.edit_text(terms_text, reply_markup=buttons) - \ No newline at end of file +