diff --git a/Database/database.py b/Database/database.py
index 0e8998f..b43d42c 100644
--- a/Database/database.py
+++ b/Database/database.py
@@ -218,13 +218,17 @@ async def get_thumbnail(self, user_id):
async def delete_thumbnail(self, user_id):
await self.files_col.update_one({'id': user_id}, {'$unset': {'thumbnail_file_id': ""}})
- async def save_attach_photo(self, user_id, file_id):
- await self.files_col.update_one({'id': user_id}, {'$set': {'attach_photo_file_id': file_id}}, upsert=True)
-
+ async def save_attach_photo(self, user_id, custom_photo_path):
+ await self.files_col.update_one(
+ {'id': user_id},
+ {'$set': {'attach_photo_file_path': custom_photo_path}},
+ upsert=True
+ )
+
async def get_attach_photo(self, user_id):
file_data = await self.files_col.find_one({'id': user_id})
if file_data:
- return file_data.get('attach_photo_file_id')
+ return file_data.get('attach_photo_file_path')
return None
async def save_merge_state(self, user_id, merge_state):
diff --git a/Dockerfile b/Dockerfile
index 9cd0097..fd7aedd 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -2,7 +2,10 @@
FROM python:3.10
WORKDIR /app
COPY . /app/
+# Install FFmpeg
+RUN apt-get update && \
+ apt-get install -y ffmpeg
+RUN apt -qq update && apt -qq install -y git wget pv jq wget python3-dev ffmpeg mediainfo
RUN pip install -r requirements.txt
CMD ["python", "bot.py"]
-
-#TG: @Sunrises_24
+#TG:@Sunrises_24
diff --git a/Procfile b/Procfile
index 44511d8..d5776f8 100644
--- a/Procfile
+++ b/Procfile
@@ -1,2 +1,2 @@
-web: python bot.py
+web: python3 update.py
#ALL FILES UPLOADED - CREDITS ๐ - @Sunrises_24
diff --git a/README.md b/README.md
index e2a1879..34ec348 100644
--- a/README.md
+++ b/README.md
@@ -9,7 +9,7 @@
## Deploy To Koyeb
-[](https://app.koyeb.com/deploy?type=git&repository=github.com/Aluval/MetaMorpher&env[BOT_TOKEN]&env[API_ID]&env[API_HASH]&env[FSUB_UPDATES]&env[FSUB_GROUP]&env[AUTH_USERS]&env[LOG_CHANNEL_ID]&env[WEBHOOK]=True&env[ADMIN]&env[DATABASE_URI]&env[DATABASE_NAME]=Cluster0&env[SUNRISES_PIC]&env[PORT]=8080&run_command=python%20bot.py&branch=SH24BOTS-GD-REVERSION-PVT&name=MetaMorpher)
+[](https://app.koyeb.com/deploy?type=git&repository=github.com/Aluval/MetaMorpher&env[BOT_TOKEN]&env[API_ID]&env[API_HASH]&env[FSUB_UPDATES]&env[FSUB_GROUP]&env[AUTH_USERS]&env[LOG_CHANNEL_ID]&env[WEBHOOK]=True&env[ADMIN]&env[DATABASE_URI]&env[DATABASE_NAME]=Cluster0&env[SUNRISES_PIC]&env[PORT]=8080&run_command=python%20bot.py&branch=SH24BOTS-GD-REVERSION-GRP&name=MetaMorpher)
## Deploy To Render
@@ -27,7 +27,7 @@ Press Below Button to Deploy!
**ADD YOUR TOKEN.PICKLE For Google Drive Access**
-**This Branch Only In Bot [Private] Support**
+**This Branch Only In Bot [GROUP] Support**
**This Bot Is Follows the 2GB Below Files To Telegram. 2GB Above Files To Google Drive.**
@@ -43,8 +43,12 @@ Press Below Button to Deploy!
- `Extract Audios` - Extract audio from files.
- `Extract Subtitles` - Extract subtitles from files.
- `Extract Video` - Extract video from files.
-- `Change index audio`: Adjusts metadata or index information for audio files.
-- `Change Index Subtitles`: Manages and updates index or metadata for subtitle files.
+- `Stream Remove` - ๐
๐๐๐๐ฃ๐ ๐ด๐ข๐๐๐๐ ๐๐ ๐๐ข๐๐ก๐๐ก๐๐๐
+- `Multitaskfile` - For File Changemetadata, Rename, Changeindexaudio, Changeindexsub = multitaskfile
+- `Multitasklink ` - For link [Workers & Seedr Links] Metadata, Rename, Indexaudio, Indexsub = multitasklink
+- `Compress` - compress the file as 480p ,libopus[Anime & Webseries Best]
+- `Swap Audio`: Adjusts metadata or index information for audio files."
+- `Swap Subtitles`: Manages and updates index or metadata for subtitle files.
- `Attach photo attachment.jpg`: Attaches specific photos like attachment.jpg.
- `Remove tags in files`: Cleans and removes tags or metadata from files.
- `Merge`: Merges files and data [Video + Video].
@@ -72,6 +76,8 @@ Press Below Button to Deploy!
* `AUTH_USERS` - for restart owner id
+* `GROUP` - group id add and admin it
+
* `DATABASE_NAME` - Database Name
* `DATABASE_URI` - Mongdb Url From mongodb.com.
@@ -99,8 +105,12 @@ extractsubtitles - ๐ธ๐ฅ๐ก๐๐๐๐ก ๐ ๐ข๐๐ก๐๐ก๐๐
extractvideo - ๐ธ๐ฅ๐ก๐๐๐๐ก ๐ฃ๐๐๐๐ ๐๐๐๐ ๐๐๐๐๐ .
rename - ๐๐๐๐๐๐ฆ ๐ค๐๐กโ ๐๐๐๐ ๐ก๐ ๐
๐๐๐๐๐๐
gofile - ๐โ๐ ๐น๐๐๐๐ ๐๐๐๐๐๐ ๐๐ ๐บ๐๐๐๐๐ ๐ฟ๐๐๐ ๐
-changeindexaudio - ๐
๐๐๐๐๐๐ ๐กโ๐ ๐ ๐๐๐ข๐๐๐๐ [a-1 ๐๐๐ ๐๐๐๐๐ฃ๐ ๐๐ข๐๐๐ , a-2-1-3-4 ๐๐๐ ๐ ๐ค๐๐ ๐๐ข๐๐๐]
-changeindexsub - ๐
๐๐๐๐๐๐ ๐กโ๐ ๐ ๐๐๐ข๐๐๐๐ [s-1 ๐๐๐ ๐๐๐๐๐ฃ๐ ๐ ๐ข๐๐ก๐๐ก๐๐ , s-2-1-3-4 ๐๐๐ ๐ ๐ค๐๐ ๐ ๐ข๐๐ก๐๐ก๐๐]
+streamremove - ๐
๐๐๐๐ฃ๐ ๐ด๐ข๐๐๐๐ ๐๐ ๐๐ข๐๐ก๐๐ก๐๐๐
+multitaskfile - ๐น๐๐ ๐น๐๐๐ ๐ถโ๐๐๐๐๐๐๐ก๐๐๐๐ก๐, ๐
๐๐๐๐๐, ๐ถโ๐๐๐๐๐๐๐๐๐ฅ๐๐ข๐๐๐, ๐ถโ๐๐๐๐๐๐๐๐๐ฅ๐ ๐ข๐ = ๐๐ข๐๐ก๐๐ก๐๐ ๐๐๐๐๐
+multitasklink - ๐น๐๐ ๐๐๐๐ [๐๐๐๐๐๐๐ & ๐๐๐๐๐ ๐ฟ๐๐๐๐ ] ๐๐๐ก๐๐๐๐ก๐, ๐
๐๐๐๐๐, ๐ผ๐๐๐๐ฅ๐๐ข๐๐๐, ๐ผ๐๐๐๐ฅ๐ ๐ข๐ = ๐๐ข๐๐ก๐๐ก๐๐ ๐๐๐๐๐
+compress - ๐๐๐๐๐๐๐ ๐ ๐กโ๐ ๐๐๐๐ ๐๐ 480๐ ,๐๐๐๐๐๐ข๐ [๐ด๐๐๐๐ & ๐๐๐๐ ๐๐๐๐๐ ๐ต๐๐ ๐ก]
+swapaudio - ๐
๐๐๐๐๐๐ ๐กโ๐ ๐ ๐๐๐ข๐๐๐๐ [a-2-1-3-4 ๐๐๐ ๐ ๐ค๐๐ ๐๐ข๐๐๐]
+swapsubitles - ๐
๐๐๐๐๐๐ ๐กโ๐ ๐ ๐๐๐ข๐๐๐๐ [s-2-1-3-4 ๐๐๐ ๐ ๐ค๐๐ ๐ ๐ข๐๐ก๐๐ก๐๐]
changemetadata - ๐๐๐๐๐ ๐๐๐๐ ๐กโ๐ ๐๐๐ก๐๐๐๐ก๐
removetags - ๐๐ ๐
๐๐๐๐ฃ๐ ๐ด๐๐ ๐๐๐ก๐๐๐๐ก๐ ๐๐๐๐
samplevideo - ๐ถ๐๐๐๐ก๐ ๐ด ๐๐๐๐๐๐ ๐๐๐๐๐ ๐๏ธ
diff --git a/app.json b/app.json
index 86d1c7e..03d0444 100644
--- a/app.json
+++ b/app.json
@@ -2,7 +2,7 @@
"name": "MetaMorpher",
"description": "ADVANCE RENAME BOT WITH THUMBNAIL,CAPTION & HIGH SPEED โก๏ธ",
"logo":"https://graph.org/file/bd91761f6e938e2e6d23a.jpg",
- "repository": "https://github.com/Aluval/ADVANCERENAME24BOT",
+ "repository": "https://github.com/Aluval/MetaMorpher",
"keywords": ["Rename-bot", "Telegram", "ADVANCE RENAME 24 BOT"],
"env": {
"BOT_TOKEN": {
@@ -17,13 +17,42 @@
"description": "Your API_HASH from https://my.telegram.org/apps",
"required": true
},
+ "DATABASE_URI": {
+ "description": "mongoDB URI. Get this value from https://www.mongodb.com. For more help watch this video - https://youtu.be/dsuTn4qV2GA",
+ "value": "",
+ "required": true
+ },
+ "DATABASE_NAME": {
+ "description": "Name of the database in mongoDB. For more contact to admin",
+ "value": "Cluster0",
+ "required": false
+ },
+ "LOG_CHANNEL_ID": {
+ "description": "Add to bot & admin the bot in channel",
+ "value": "",
+ "required": true
+ },
+ "WEBHOOK": {
+ "description": "web true only",
+ "value": "True",
+ "required": true
+ },
+ "PORT": {
+ "description": "8080",
+ "value": "8080",
+ "required": true
+ },
"FSUB_UPDATES": {
"description": "forcesub username channel and admin it",
"required": true
},
"FSUB_GROUP": {
"description": "forcesub username group and admin it",
- "required": true
+ "required": true
+ },
+ "GROUP": {
+ "description": "Group id",
+ "required": true
},
"SUNRISES_PIC": {
"description": "Start Pic",
diff --git a/bot.py b/bot.py
index 8abc596..e3b4d78 100644
--- a/bot.py
+++ b/bot.py
@@ -26,7 +26,7 @@ async def start(self):
await app.setup()
bind_address = "0.0.0.0"
await web.TCPSite(app, bind_address, PORT).start()
- await self.send_message(LOG_CHANNEL_ID, f"{me.first_name} | @{me.username} ๐๐๐ฐ๐๐๐ด๐ณ...โก๏ธ")
+ print(f"{me.first_name} | @{me.username} ๐๐๐ฐ๐๐๐ด๐ณ...โก๏ธ")
diff --git a/config.py b/config.py
index ee9a818..89df2fc 100644
--- a/config.py
+++ b/config.py
@@ -6,18 +6,20 @@
id_pattern = re.compile(r'^.\d+$')
-API_ID = int(os.environ.get("API_ID", "10811400"))
-API_HASH = os.environ.get("API_HASH", "191bf5ae7a6c39771e7b13cf4ffd1279")
-BOT_TOKEN = os.environ.get("BOT_TOKEN", "6487202001:AAHvkz9vPGnVX_QpIPr-YvOJvHMBARepPyY")
-ADMIN = int(os.environ.get("ADMIN", '6469754522'))
+API_ID = os.environ.get("API_ID", "20577207")
+API_HASH = os.environ.get("API_HASH", "40b5e72e7b9607c2e5563fff5c7b0a37")
+BOT_TOKEN = os.environ.get("BOT_TOKEN", "7565764530:AAGCGRi2p23_QX86Vcm4vUIm3t85PIxMTyk")
+ADMIN = int(os.environ.get("ADMIN", '2041855080'))
FSUB_UPDATES = os.environ.get("FSUB_CHANNEL", "Sunrises24BotUpdates")
FSUB_GROUP = os.environ.get("FSUB_GROUP", "Sunrises24BotSupport")
-DATABASE_URI = os.environ.get("DATABASE_URI", "mongodb+srv://UPLOADXPRO24BOT:UPLOADXPRO24BOT@cluster0.hjfk60f.mongodb.net/?retryWrites=true&w=majority&appName=Cluster0")
+DATABASE_URI = os.environ.get("DATABASE_URI", "mongodb+srv://krishnajha2034:8905563700@cluster0.flb9u.mongodb.net/?retryWrites=true&w=majority&appName=Cluster0")
DATABASE_NAME = os.environ.get("DATABASE_NAME", "Cluster0")
CAPTION = os.environ.get("CAPTION", "")
+group = environ.get('GROUP', '-1002425543008)
+GROUP = int(group) if group and id_pattern.search(group) else None
#ALL FILES UPLOADED - CREDITS ๐ - @Sunrises_24
SUNRISES_PIC= "https://graph.org/file/bd91761f6e938e2e6d23a.jpg" # Replace with your Telegraph link
-AUTH_USERS = int(os.environ.get("AUTH_USERS", '6469754522'))
+AUTH_USERS = int(os.environ.get("AUTH_USERS", '7906265673'))
WEBHOOK = bool(os.environ.get("WEBHOOK", True))
PORT = int(os.environ.get("PORT", "8080"))
-LOG_CHANNEL_ID = os.environ.get("LOG_CHANNEL_ID", -1002145984196)
+LOG_CHANNEL_ID = os.environ.get("LOG_CHANNEL_ID", -1002237472046)
diff --git a/main/ffmpeg.py b/main/ffmpeg.py
index 8eff959..3eb6ba8 100644
--- a/main/ffmpeg.py
+++ b/main/ffmpeg.py
@@ -283,3 +283,56 @@ def get_mediainfo(file_path):
if process.returncode != 0:
raise Exception(f"Error getting media info: {stderr.decode().strip()}")
return stdout.decode().strip()
+
+# Function to compress Ffmpeg information using compress command
+def compress_video(input_path, output_path, video_title, audio_title, subtitle_title):
+ command = [
+ 'ffmpeg',
+ '-hide_banner',
+ '-loglevel', 'quiet',
+ '-i', input_path,
+ '-c:v', 'libx264',
+ '-crf', '28',
+ '-pix_fmt', 'yuv420p',
+ '-s', '854x480',
+ '-b:v', '150k',
+ '-c:a', 'libopus',
+ '-b:a', '35k',
+ '-preset', 'veryfast',
+ '-map', '0:v:0', # Map the first video stream
+ '-map', '0:a', # Map all audio streams
+ '-map', '0:s?', # Map all subtitle streams if present
+ '-metadata', f'title={video_title}',
+ '-metadata:s:v:0', f'title={video_title}',
+ '-metadata:s:a', f'title={audio_title}',
+ '-metadata:s:s', f'title={subtitle_title}',
+ '-y',
+ output_path
+ ]
+
+ process = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+ stdout, stderr = process.communicate()
+ if process.returncode != 0:
+ raise Exception(f"FFmpeg error: {stderr.decode('utf-8')}")
+
+# Function to compress mediainfo information using compress command
+async def get_and_upload_mediainfo(bot, output_file, media):
+ media_info_html = get_mediainfo(output_file)
+
+ media_info_html = (
+ f"SUNRISES 24 BOT UPDATES
"
+ f"MediaInfo X
"
+ f"{media_info_html}"
+ f"
Rights Designed By Sแดษดสษชsแดs Hแดสsสแด ๐ธ๐บ ๐ฎ๐ณ แตแดฑแดธ
" + ) + + response = telegraph.post( + title="MediaInfo", + author="SUNRISES 24 BOT UPDATES", + author_url="https://t.me/Sunrises24BotUpdates", + text=media_info_html + ) + link = f"https://graph.org/{response['path']}" + + return media_info_html, link + diff --git a/main/gdrive.py b/main/gdrive.py index 27de243..f26be4e 100644 --- a/main/gdrive.py +++ b/main/gdrive.py @@ -52,6 +52,23 @@ async def upload_to_google_drive(file_path, file_name, sts): return response.get('webViewLink') +#Driveleech +def extract_id_from_driveurl(url): + file_id = None + # Match the different URL patterns for Google Drive links + patterns = [ + r'id=([a-zA-Z0-9-_]+)', # Format 1: ?id=FILE_ID + r'/d/([a-zA-Z0-9-_]+)', # Format 2: /d/FILE_ID/ + r'/file/d/([a-zA-Z0-9-_]+)' # Format 3: /file/d/FILE_ID/ + ] + + for pattern in patterns: + match = re.search(pattern, url) + if match: + file_id = match.group(1) + break + + return file_id #ALL FILES UPLOADED - CREDITS ๐ - @Sunrises_24 diff --git a/main/rename.py b/main/rename.py index 09e5c90..c692964 100644 --- a/main/rename.py +++ b/main/rename.py @@ -1,7 +1,7 @@ -#TG : @Sunrises_24 +#TG :@Sunrises_24 #ALL FILES UPLOADED - CREDITS ๐ - @Sunrises_24 import subprocess -import os +import os, json import time import shutil import zipfile @@ -14,12 +14,12 @@ from pyrogram.errors import MessageNotModified from main.utils import progress_message, humanbytes from pyrogram.types import InlineKeyboardButton, InlineKeyboardMarkup,CallbackQuery -from config import AUTH_USERS, ADMIN, CAPTION -from main.utils import heroku_restart, upload_files, download_media +from config import AUTH_USERS, ADMIN, CAPTION, GROUP +from main.utils import heroku_restart, upload_files, download_media, download_file_from_drive import aiohttp from pyrogram.errors import RPCError, FloodWait import asyncio -from main.ffmpeg import remove_all_tags, change_video_metadata, generate_sample_video, add_photo_attachment, merge_videos, unzip_file, extract_audio_stream, extract_subtitle_stream, extract_video_stream, extract_audios_from_file, extract_subtitles_from_file, extract_video_from_file, get_mediainfo +from main.ffmpeg import remove_all_tags, change_video_metadata, generate_sample_video, add_photo_attachment, merge_videos, unzip_file, extract_audio_stream, extract_subtitle_stream, extract_video_stream, extract_audios_from_file, extract_subtitles_from_file, extract_video_from_file, get_mediainfo, compress_video, get_and_upload_mediainfo from googleapiclient.http import MediaFileUpload from main.gdrive import upload_to_google_drive, extract_id_from_url, copy_file, get_files_in_folder, drive_service from googleapiclient.errors import HttpError @@ -30,6 +30,19 @@ from pymongo.errors import PyMongoError from yt_dlp import YoutubeDL from html_telegraph_poster import TelegraphPoster +from os import execl as osexecl +from sys import executable +from config import * +import logging + +logging.basicConfig( + filename='SunrisesBot.txt', + format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', + level=logging.INFO +) + +# Example of logging a message +logging.info('Bot started successfully!') # Initialize Telegraph telegraph = TelegraphPoster(use_api=True) @@ -52,7 +65,14 @@ CHANGE_INDEX_ENABLED = True MERGE_ENABLED = True EXTRACT_ENABLED = True +MULTITASK_ENABLED = True +STREAMREMOVE_ENABLED = True +COMPRESS_ENABLED = True +SWAP_INDEX_ENABLED = True +#varibles for streameremove +selected_streams = set() +downloaded = None @@ -62,29 +82,34 @@ async def bot_settings_command(_, msg): await display_bot_settings_inline(msg) - # Inline function to display user settings with inline buttons async def display_bot_settings_inline(msg): - global METADATA_ENABLED, PHOTO_ATTACH_ENABLED, MIRROR_ENABLED, RENAME_ENABLED, REMOVETAGS_ENABLED, CHANGE_INDEX_ENABLED + global METADATA_ENABLED, PHOTO_ATTACH_ENABLED, MIRROR_ENABLED, RENAME_ENABLED, REMOVETAGS_ENABLED, SWAP_INDEX_ENABLED, MULTITASK_ENABLED, STREAMREMOVE_ENABLED, COMPRESS_ENABLED metadata_status = "โ Enabled" if METADATA_ENABLED else "โ Disabled" photo_attach_status = "โ Enabled" if PHOTO_ATTACH_ENABLED else "โ Disabled" mirror_status = "โ Enabled" if MIRROR_ENABLED else "โ Disabled" rename_status = "โ Enabled" if RENAME_ENABLED else "โ Disabled" removealltags_status = "โ Enabled" if REMOVETAGS_ENABLED else "โ Disabled" - change_index_status = "โ Enabled" if CHANGE_INDEX_ENABLED else "โ Disabled" - merge_video_status = "โ Enabled" if MERGE_ENABLED else "โ Disabled" - + swap_index_status = "โ Enabled" if SWAP_INDEX_ENABLED else "โ Disabled" + merge_video_status = "โ Enabled" if MERGE_ENABLED else "โ Disabled" + multitask_status = "โ Enabled" if MULTITASK_ENABLED else "โ Disabled" + streamremove_status = "โ Enabled" if STREAMREMOVE_ENABLED else "โ Disabled" + compress_status = "โ Enabled" if COMPRESS_ENABLED else "โ Disabled" + keyboard = InlineKeyboardMarkup( inline_keyboard=[ [InlineKeyboardButton("๐ ", callback_data="sunrises24_bot_updates")], [InlineKeyboardButton(f"{rename_status} Change Rename ๐", callback_data="toggle_rename")], [InlineKeyboardButton(f"{removealltags_status} Remove All Tags ๐", callback_data="toggle_removealltags")], [InlineKeyboardButton(f"{metadata_status} Change Metadata โ๏ธ", callback_data="toggle_metadata")], - [InlineKeyboardButton(f"{change_index_status} Change Index โป๏ธ", callback_data="toggle_change_index")], + [InlineKeyboardButton(f"{swap_index_status} Swap Index โป๏ธ", callback_data="toggle_swap_index")], [InlineKeyboardButton(f"{merge_video_status} Merge Video ๐๏ธ", callback_data="toggle_merge_video")], [InlineKeyboardButton(f"{photo_attach_status} Attach Photo ๐ผ๏ธ", callback_data="toggle_photo_attach")], - [InlineKeyboardButton(f"{mirror_status} Mirror ๐ฝ", callback_data="toggle_mirror")], + [InlineKeyboardButton(f"{mirror_status} Mirror ๐ฝ", callback_data="toggle_mirror")], + [InlineKeyboardButton(f"{multitask_status} MultiTask โฉ", callback_data="toggle_multitask")], + [InlineKeyboardButton(f"{streamremove_status} Stream Remove ๐", callback_data="toggle_streamremove")], + [InlineKeyboardButton(f"{compress_status} Compress ๐๏ธ", callback_data="toggle_compress")], [InlineKeyboardButton("Close โ", callback_data="del")], [InlineKeyboardButton("๐ ", callback_data="sunrises24_bot_updates")] ] @@ -140,11 +165,11 @@ async def toggle_multitask_callback(_, callback_query): MIRROR_ENABLED = not MIRROR_ENABLED await update_settings_message(callback_query.message) -@Client.on_callback_query(filters.regex("^toggle_change_index$")) -async def toggle_change_index_callback(_, callback_query): - global CHANGE_INDEX_ENABLED +@Client.on_callback_query(filters.regex("^toggle_swap_index$")) +async def toggle_swap_index_callback(_, callback_query): + global SWAP_INDEX_ENABLED - CHANGE_INDEX_ENABLED = not CHANGE_INDEX_ENABLED + SWAP_INDEX_ENABLED = not SWAP_INDEX_ENABLED await update_settings_message(callback_query.message) @Client.on_callback_query(filters.regex("^toggle_merge_video$")) @@ -153,6 +178,27 @@ async def toggle_merge_video_callback(_, callback_query): MERGE_ENABLED = not MERGE_ENABLED await update_settings_message(callback_query.message) + +@Client.on_callback_query(filters.regex("^toggle_multitask$")) +async def toggle_multitask_callback(_, callback_query): + global MULTITASK_ENABLED + + MULTITASK_ENABLED = not MULTITASK_ENABLED + await update_settings_message(callback_query.message) + +@Client.on_callback_query(filters.regex("^toggle_streamremove$")) +async def toggle_streamremove_callback(_, callback_query): + global STREAMREMOVE_ENABLED + + STREAMREMOVE_ENABLED = not STREAMREMOVE_ENABLED + await update_settings_message(callback_query.message) + +@Client.on_callback_query(filters.regex("^toggle_compress$")) +async def toggle_compress_callback(_, callback_query): + global COMPRESS_ENABLED + + COMPRESS_ENABLED = not COMPRESS_ENABLED + await update_settings_message(callback_query.message) # Callback query handler for the "sunrises24_bot_updates" button @Client.on_callback_query(filters.regex("^sunrises24_bot_updates$")) @@ -161,7 +207,7 @@ async def sunrises24_bot_updates_callback(_, callback_query): async def update_settings_message(message): - global METADATA_ENABLED, PHOTO_ATTACH_ENABLED, MIRROR_ENABLED, RENAME_ENABLED, REMOVETAGS_ENABLED, CHANGE_INDEX_ENABLED + global METADATA_ENABLED, PHOTO_ATTACH_ENABLED, MIRROR_ENABLED, RENAME_ENABLED, REMOVETAGS_ENABLED, SWAP_INDEX_ENABLED, MULTITASK_ENABLED, STREAMREMOVE_ENABLED, COMPRESS_ENABLED metadata_status = "โ Enabled" if METADATA_ENABLED else "โ Disabled" photo_attach_status = "โ Enabled" if PHOTO_ATTACH_ENABLED else "โ Disabled" @@ -169,8 +215,11 @@ async def update_settings_message(message): rename_status = "โ Enabled" if RENAME_ENABLED else "โ Disabled" removealltags_status = "โ Enabled" if REMOVETAGS_ENABLED else "โ Disabled" change_index_status = "โ Enabled" if CHANGE_INDEX_ENABLED else "โ Disabled" - merge_video_status = "โ Enabled" if MERGE_ENABLED else "โ Disabled" - + merge_video_status = "โ Enabled" if MERGE_ENABLED else "โ Disabled" + multitask_status = "โ Enabled" if MULTITASK_ENABLED else "โ Disabled" + streamremove_status = "โ Enabled" if STREAMREMOVE_ENABLED else "โ Disabled" + compress_status = "โ Enabled" if COMPRESS_ENABLED else "โ Disabled" + keyboard = InlineKeyboardMarkup( inline_keyboard=[ [InlineKeyboardButton("๐ ", callback_data="sunrises24_bot_updates")], @@ -180,7 +229,10 @@ async def update_settings_message(message): [InlineKeyboardButton(f"{change_index_status} Change Index โป๏ธ", callback_data="toggle_change_index")], [InlineKeyboardButton(f"{merge_video_status} Merge Video ๐๏ธ", callback_data="toggle_merge_video")], [InlineKeyboardButton(f"{photo_attach_status} Attach Photo ๐ผ๏ธ", callback_data="toggle_photo_attach")], - [InlineKeyboardButton(f"{multitask_status} Mirror ๐ฝ", callback_data="toggle_mirror")], + [InlineKeyboardButton(f"{mirror_status} Mirror ๐ฝ", callback_data="toggle_mirror")], + [InlineKeyboardButton(f"{multitask_status} MultiTask โฉ", callback_data="toggle_multitask")], + [InlineKeyboardButton(f"{streamremove_status} Stream Remove ๐", callback_data="toggle_streamremove")], + [InlineKeyboardButton(f"{compress_status} Compress ๐๏ธ", callback_data="toggle_compress")], [InlineKeyboardButton("Close โ", callback_data="del")], [InlineKeyboardButton("๐ ", callback_data="sunrises24_bot_updates")] ] @@ -225,7 +277,7 @@ async def sample_video_option(client, callback_query: CallbackQuery): async def back_to_settings(client, callback_query: CallbackQuery): await display_user_settings(client, callback_query.message, edit=True) -@Client.on_message(filters.private & filters.command("usersettings")) +@Client.on_message(filters.command("usersettings") & filters.chat(GROUP)) async def display_user_settings(client, msg, edit=False): user_id = msg.from_user.id @@ -302,12 +354,26 @@ async def set_photo(bot, msg): if not reply or not reply.photo: return await msg.reply_text("Please reply to a photo with the setphoto command") + # Extract custom name from the command + if len(msg.command) < 2: + return await msg.reply_text("Please provide a custom name for the photo.") + + custom_name = msg.command[1] # The custom name is the second part of the command user_id = msg.from_user.id photo_file_id = reply.photo.file_id try: - await db.save_attach_photo(user_id, photo_file_id) - await msg.reply_text("Photo saved successfully.") + # Download the photo file + photo_path = await bot.download_media(photo_file_id) + + # Save the photo with the custom name + custom_photo_path = f"{custom_name}.jpg" + os.rename(photo_path, custom_photo_path) + + # Save the custom photo path to the database + await db.save_attach_photo(user_id, custom_photo_path) + await msg.reply_text(f"Photo saved successfully with the name: {custom_name}.jpg") + except Exception as e: await msg.reply_text(f"Error saving photo: {e}") @@ -339,7 +405,7 @@ async def inline_thumbnail_settings(client, callback_query: CallbackQuery): ) await callback_query.message.edit_text("Thumbnail Settings:", reply_markup=keyboard) -@Client.on_message(filters.private & filters.command("setthumbnail")) +@Client.on_message(filters.command("setthumbnail") & filters.chat(GROUP)) async def set_thumbnail_command(client, message): user_id = message.from_user.id @@ -350,7 +416,7 @@ async def set_thumbnail_command(client, message): else: await message.reply("Send a photo to set as your permanent thumbnail.") -@Client.on_message(filters.photo & filters.private) +@Client.on_message(filters.photo & filters.chat(GROUP)) async def set_thumbnail_handler(client, message): user_id = message.from_user.id photo_file_id = message.photo.file_id @@ -402,8 +468,7 @@ async def inline_preview_gdrive(bot, callback_query): await callback_query.message.reply_text(f"Current Google Drive Folder ID for user `{user_id}`: {gdrive_folder_id}") - -@Client.on_message(filters.private & filters.command("setmetadata")) +@Client.on_message(filters.command("setmetadata") & filters.chat(GROUP)) async def set_metadata_command(client, msg): # Extract titles from the command message if len(msg.command) < 2: @@ -481,11 +546,8 @@ async def inline_preview_gofile_api_key(bot, callback_query): - - - # Command handler for /mirror -@Client.on_message(filters.private & filters.command("mirror")) +@Client.on_message(filters.command("mirror") & filters.chat(GROUP)) async def mirror_to_google_drive(bot, msg: Message): global MIRROR_ENABLED @@ -564,8 +626,15 @@ async def mirror_to_google_drive(bot, msg: Message): #Rename Command -@Client.on_message(filters.private & filters.command("rename")) +@Client.on_message(filters.command("rename") & filters.chat(GROUP)) async def rename_file(bot, msg): + global RENAME_ENABLED + + if not RENAME_ENABLED: + return await msg.reply_text("Rename feature is currently disabled.") + + user_id = msg.from_user.id + if len(msg.command) < 2 or not msg.reply_to_message: return await msg.reply_text("Please reply to a file, video, or audio with the new filename and extension (e.g., .mkv, .mp4, .zip).") @@ -619,7 +688,7 @@ async def rename_file(bot, msg): await sts.delete() #Change Metadata Code -@Client.on_message(filters.private & filters.command("changemetadata")) +@Client.on_message(filters.command("changemetadata") & filters.chat(GROUP)) async def change_metadata(bot, msg: Message): global METADATA_ENABLED @@ -719,7 +788,8 @@ async def change_metadata(bot, msg: Message): #attach photo -@Client.on_message(filters.private & filters.command("attachphoto")) + +@Client.on_message(filters.command("attachphoto") & filters.chat(GROUP)) async def attach_photo(bot, msg: Message): global PHOTO_ATTACH_ENABLED @@ -756,18 +826,24 @@ async def attach_photo(bot, msg: Message): return # Retrieve attachment from the database - attachment_file_id = await db.get_attach_photo(msg.from_user.id) - if not attachment_file_id: + attachment_file_path = await db.get_attach_photo(msg.from_user.id) + if not attachment_file_path: await safe_edit_message(sts, "Please send a photo to be attached using the `setphoto` command.") os.remove(downloaded) return - attachment_path = await bot.download_media(attachment_file_id) + # Ensure the attachment exists and download it if necessary + attachment_path = attachment_file_path + if not os.path.exists(attachment_path): + await safe_edit_message(sts, "Attachment not found.") + os.remove(downloaded) + return output_file = output_filename await safe_edit_message(sts, "๐ Adding photo attachment... โก") try: + # Function to add photo attachment (assume it's defined elsewhere) add_photo_attachment(downloaded, attachment_path, output_file) except Exception as e: await safe_edit_message(sts, f"Error adding photo attachment: {e}") @@ -796,6 +872,7 @@ async def attach_photo(bot, msg: Message): try: # Upload to Google Drive if file size exceeds the limit if filesize > FILE_SIZE_LIMIT: + # Function to upload to Google Drive (assume it's defined elsewhere) file_link = await upload_to_google_drive(output_file, os.path.basename(output_file), sts) button = [[InlineKeyboardButton("โ๏ธ CloudUrl โ๏ธ", url=f"{file_link}")]] await msg.reply_text( @@ -839,22 +916,21 @@ async def attach_photo(bot, msg: Message): - # Command handler # Command handler for changing audio index -@Client.on_message(filters.private & filters.command("changeindexaudio")) -async def change_index_audio(bot, msg): - global CHANGE_INDEX_ENABLED +@Client.on_message(filters.command("swapaudio") & filters.chat(GROUP)) +async def swap_audios(bot, msg): + global SWAP_INDEX_ENABLED - if not CHANGE_INDEX_ENABLED: - return await msg.reply_text("The changeindexaudio feature is currently disabled.") + if not SWAP_INDEX_ENABLED: + return await msg.reply_text("The swap audio index feature is currently disabled.") reply = msg.reply_to_message if not reply: - return await msg.reply_text("Please reply to a media file with the index command\nFormat: `/changeindexaudio a-3 -n filename.mkv` (Audio)") + return await msg.reply_text("Please reply to a media file with the index command\nFormat: `/swapaudio a-3-1-2-4 -n filename.mkv` (Audio)") if len(msg.command) < 3: - return await msg.reply_text("Please provide the index command with a filename\nFormat: `/changeindexaudio a-3 -n filename.mkv` (Audio)") + return await msg.reply_text("Please provide the index command with a filename\nFormat: `/swapaudio a-3-1-2-4 -n filename.mkv` (Audio)") index_cmd = None output_filename = None @@ -871,7 +947,7 @@ async def change_index_audio(bot, msg): return await msg.reply_text("Please provide a filename using the `-n` flag.") if not index_cmd or not index_cmd.startswith("a-"): - return await msg.reply_text("Invalid format. Use `/changeindexaudio a-3 -n filename.mkv` for audio.") + return await msg.reply_text("Invalid format. Use `/swapaudio a-3-1-2-4 -n filename.mkv` for audio.") media = reply.document or reply.audio or reply.video if not media: @@ -894,7 +970,7 @@ async def change_index_audio(bot, msg): indexes = [int(i) - 1 for i in index_params[1:]] # Construct the FFmpeg command to modify indexes - ffmpeg_cmd = ['ffmpeg', '-i', downloaded] + ffmpeg_cmd = ['ffmpeg', '-i', downloaded, '-map', '0:v'] # Always map video stream for idx in indexes: ffmpeg_cmd.extend(['-map', f'0:{stream_type}:{idx}']) @@ -904,7 +980,7 @@ async def change_index_audio(bot, msg): ffmpeg_cmd.extend(['-c', 'copy', output_file, '-y']) - await sts.edit("๐ Changing audio indexing... โก") + await sts.edit("๐ Swaping audio indexing... โก") process = await asyncio.create_subprocess_exec(*ffmpeg_cmd, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE) stdout, stderr = await process.communicate() @@ -949,6 +1025,7 @@ async def change_index_audio(bot, msg): await bot.send_document( msg.chat.id, document=output_file, + file_name=output_filename, # Apply the new file name here thumb=file_thumb, caption=cap, progress=progress_message, @@ -964,23 +1041,22 @@ async def change_index_audio(bot, msg): os.remove(file_thumb) await sts.delete() - #changeindex subtitles # Command to change index subtitle # Command handler for changing subtitle index -@Client.on_message(filters.private & filters.command("changeindexsub")) -async def change_index_subtitle(bot, msg): - global CHANGE_INDEX_ENABLED +@Client.on_message(filters.command("swapsubtitles") & filters.chat(GROUP)) +async def swap_subtitle(bot, msg): + global SWAP_INDEX_ENABLED - if not CHANGE_INDEX_ENABLED: - return await msg.reply_text("The changeindexsub feature is currently disabled.") + if not SWAP_INDEX_ENABLED: + return await msg.reply_text("The swap index subtitles feature is currently disabled.") reply = msg.reply_to_message if not reply: - return await msg.reply_text("Please reply to a media file with the index command\nFormat: `/changeindexsub s-3 -n filename.mkv` (Subtitle)") + return await msg.reply_text("Please reply to a media file with the index command\nFormat: `/swapsubtitles s-2-3-1 -n filename.mkv` (Subtitle)") if len(msg.command) < 3: - return await msg.reply_text("Please provide the index command with a filename\nFormat: `/changeindexsub s-3 -n filename.mkv` (Subtitle)") + return await msg.reply_text("Please provide the index command with a filename\nFormat: `/swapsubtitles s-2-3-1 -n filename.mkv` (Subtitle)") index_cmd = None output_filename = None @@ -997,7 +1073,7 @@ async def change_index_subtitle(bot, msg): return await msg.reply_text("Please provide a filename using the `-n` flag.") if not index_cmd or not index_cmd.startswith("s-"): - return await msg.reply_text("Invalid format. Use `/changeindexsub s-3 -n filename.mkv` for subtitles.") + return await msg.reply_text("Invalid format. Use `/swapsubtitles s-2-3-1 -n filename.mkv` for subtitles.") media = reply.document or reply.audio or reply.video if not media: @@ -1028,7 +1104,7 @@ async def change_index_subtitle(bot, msg): # Copy all audio and video streams ffmpeg_cmd.extend(['-map', '0:v?', '-map', '0:a?', '-c', 'copy', output_file, '-y']) - await safe_edit_message(sts, "๐ Changing subtitle indexing... โก") + await safe_edit_message(sts, "๐ Swap subtitle indexing... โก") process = await asyncio.create_subprocess_exec(*ffmpeg_cmd, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE) stdout, stderr = await process.communicate() @@ -1068,7 +1144,7 @@ async def change_index_subtitle(bot, msg): ) else: try: - await bot.send_document(msg.chat.id, document=output_file, thumb=file_thumb, caption=cap, progress=progress_message, progress_args=("๐ Upload Started... โก", sts, c_time)) + await bot.send_document(msg.chat.id, document=output_file, file_name=output_filename, thumb=file_thumb, caption=cap, progress=progress_message, progress_args=("๐ Upload Started... โก", sts, c_time)) except Exception as e: return await safe_edit_message(sts, f"Error: {e}") @@ -1082,18 +1158,19 @@ async def change_index_subtitle(bot, msg): #merge command # Command to start merging files -@Client.on_message(filters.private & filters.command("merge")) +# Command to start merging files +@Client.on_message(filters.command("merge") & filters.chat(GROUP)) async def start_merge_command(bot, msg: Message): global MERGE_ENABLED if not MERGE_ENABLED: return await msg.reply_text("The merge feature is currently disabled.") user_id = msg.from_user.id - merge_state[user_id] = {"files": [], "output_filename": None} + merge_state[user_id] = {"files": [], "output_filename": None, "is_merging": False} await msg.reply_text("Send up to 10 video/document files one by one. Once done, send `/videomerge filename`.") -@Client.on_message(filters.private & filters.command("videomerge")) +@Client.on_message(filters.command("videomerge") & filters.chat(GROUP)) async def start_video_merge_command(bot, msg: Message): user_id = msg.from_user.id if user_id not in merge_state or not merge_state[user_id]["files"]: @@ -1101,16 +1178,24 @@ async def start_video_merge_command(bot, msg: Message): output_filename = msg.text.split(' ', 1)[1].strip() # Extract output filename from command merge_state[user_id]["output_filename"] = output_filename + merge_state[user_id]["is_merging"] = True # Set the flag to indicate that merging has started await merge_and_upload(bot, msg) -@Client.on_message(filters.document | filters.video & filters.private) +@Client.on_message(filters.document | filters.video & filters.chat(GROUP)) async def handle_media_files(bot, msg: Message): user_id = msg.from_user.id - if user_id in merge_state and len(merge_state[user_id]["files"]) < 10: - merge_state[user_id]["files"].append(msg) - await msg.reply_text("File received. Send another file or use `/videomerge filename` to start merging.") + if user_id in merge_state: + if merge_state[user_id].get("is_merging"): + await msg.reply_text("Merging process has started. No more files can be added.") + return + if len(merge_state[user_id]["files"]) < 10: + merge_state[user_id]["files"].append(msg) + await msg.reply_text("File received. Send another file or use `/videomerge filename` to start merging.") + else: + await msg.reply_text("You have already sent 10 files. Use `/videomerge filename` to start merging.") + async def merge_and_upload(bot, msg: Message): user_id = msg.from_user.id if user_id not in merge_state: @@ -1205,7 +1290,7 @@ async def merge_and_upload(bot, msg: Message): # Leech command handler -@Client.on_message(filters.command("leech") & filters.chat(AUTH_USERS)) +@Client.on_message(filters.command("leech") & filters.chat(GROUP)) async def linktofile(bot, msg: Message): if len(msg.command) < 2 or not msg.reply_to_message: return await msg.reply_text("Please reply to a file, video, audio, or link with the desired filename and extension (e.g., `.mkv`, `.mp4`, `.zip`).") @@ -1349,7 +1434,7 @@ async def safe_edit_message(message, new_text): print(f"Failed to edit message: {e}") # Command to remove tags from media files -@Client.on_message(filters.private & filters.command("removetags")) +@Client.on_message(filters.command("removetags") & filters.chat(GROUP)) async def remove_tags(bot, msg): global REMOVETAGS_ENABLED if not REMOVETAGS_ENABLED: @@ -1454,7 +1539,7 @@ async def remove_tags(bot, msg): await db.save_new_filename(msg.from_user.id, new_filename) #Screenshots Command -@Client.on_message(filters.private & filters.command("screenshots")) +@Client.on_message(filters.command("screenshots") & filters.chat(GROUP)) async def screenshots_command(client, message: Message): user_id = message.from_user.id @@ -1542,8 +1627,7 @@ async def screenshots_command(client, message: Message): await sts.delete() # Delete the status message after completion - -@Client.on_message(filters.private & filters.command("samplevideo")) +@Client.on_message(filters.command("samplevideo") & filters.chat(GROUP)) async def sample_video(bot, msg): user_id = msg.from_user.id @@ -1607,7 +1691,7 @@ async def sample_video(bot, msg): await sts.delete() # Define restart_app command -@Client.on_message(filters.command("restart") & filters.chat(AUTH_USERS)) +@Client.on_message(filters.command("restartheroku") & filters.chat(AUTH_USERS)) async def restart_app(bot, msg): if not f'{msg.from_user.id}' == f'{int(AUTH_USERS)}': return await msg.reply_text("Only authorized user can restart!") @@ -1622,7 +1706,7 @@ async def restart_app(bot, msg): # Command to unzip a zip file -@Client.on_message(filters.private & filters.command("unzip")) +@Client.on_message(filters.command("unzip") & filters.chat(GROUP)) async def unzip(bot, msg): if not msg.reply_to_message: return await msg.reply_text("Please reply to a zip file to unzip.") @@ -1658,12 +1742,11 @@ async def unzip(bot, msg): os.remove(input_path) shutil.rmtree(extract_path) - -@Client.on_message(filters.command("gofile") & filters.private) +@Client.on_message(filters.command("gofile") & filters.chat(GROUP)) async def gofile_upload(bot, msg: Message): user_id = msg.from_user.id - - # Retrieve the user's Gofile API key from database + + # Retrieve the user's Gofile API key from the database gofile_api_key = await db.get_gofile_api_key(user_id) if not gofile_api_key: @@ -1692,13 +1775,21 @@ async def gofile_upload(bot, msg: Message): try: async with aiohttp.ClientSession() as session: - # Get the server to upload the file - async with session.get("https://api.gofile.io/getServer") as resp: + # Get available servers + async with session.get("https://api.gofile.io/servers") as resp: if resp.status != 200: - return await sts.edit(f"Failed to get server. Status code: {resp.status}") + return await sts.edit(f"Failed to get servers. Status code: {resp.status}") data = await resp.json() - server = data["data"]["server"] + servers = data.get("data", {}).get("servers", []) + if not servers: + return await sts.edit("No servers available.") + + server_name = servers[0].get("name") # Use the server name + if not server_name: + return await sts.edit("Server name is missing.") + + upload_url = f"https://{server_name}.gofile.io/contents/uploadfile" # Download the media file downloaded_file = await bot.download_media( @@ -1712,10 +1803,11 @@ async def gofile_upload(bot, msg: Message): with open(downloaded_file, "rb") as file: form_data = aiohttp.FormData() form_data.add_field("file", file, filename=file_name) - form_data.add_field("token", gofile_api_key) + headers = {"Authorization": f"Bearer {gofile_api_key}"} if gofile_api_key else {} async with session.post( - f"https://{server}.gofile.io/uploadFile", + upload_url, + headers=headers, data=form_data ) as resp: if resp.status != 200: @@ -1740,7 +1832,7 @@ async def gofile_upload(bot, msg: Message): -@Client.on_message(filters.private & filters.command("clone")) +@Client.on_message(filters.command("clone") & filters.chat(GROUP)) async def clone_file(bot, msg: Message): user_id = msg.from_user.id @@ -1793,7 +1885,7 @@ async def safe_edit_message(message, new_text): print(f"Failed to edit message: {e}") #extract audio command -@Client.on_message(filters.command("extractaudios") & filters.private) +@Client.on_message(filters.command("extractaudios") & filters.chat(GROUP)) async def extract_audios(bot, msg): global EXTRACT_ENABLED @@ -1853,7 +1945,7 @@ async def extract_audios(bot, msg): #extract subtitles command -@Client.on_message(filters.command("extractsubtitles") & filters.private) +@Client.on_message(filters.command("extractsubtitles") & filters.chat(GROUP)) async def extract_subtitles(bot, msg): global EXTRACT_ENABLED @@ -1912,7 +2004,7 @@ async def extract_subtitles(bot, msg): os.remove(file) ##extract video command -@Client.on_message(filters.command("extractvideo") & filters.private) +@Client.on_message(filters.command("extractvideo") & filters.chat(GROUP)) async def extract_video(bot, msg: Message): global EXTRACT_ENABLED @@ -1970,7 +2062,7 @@ async def extract_video(bot, msg: Message): os.remove(output_file) # Command handler for /list -@Client.on_message(filters.private & filters.command("list")) +@Client.on_message(filters.command("list") & filters.chat(GROUP)) async def list_files(bot, msg: Message): user_id = msg.from_user.id @@ -2033,7 +2125,7 @@ async def list_files(bot, msg: Message): await sts.edit(f"Error: {e}") #cleam command -@Client.on_message(filters.private & filters.command("clean")) +@Client.on_message(filters.command("clean") & filters.chat(GROUP)) async def clean_files(bot, msg: Message): user_id = msg.from_user.id @@ -2099,7 +2191,7 @@ async def hook(d): await safe_edit_message(status_message, "Download finished. ๐") return hook -@Client.on_message(filters.private & filters.command("ytdlleech")) +@Client.on_message(filters.command("ytdlleech") & filters.chat(GROUP)) async def ytdlleech_handler(client: Client, msg: Message): if len(msg.command) < 2: return await msg.reply_text("Please provide a YouTube link.") @@ -2226,8 +2318,7 @@ async def callback_query_handler(client: Client, query): await sts.delete() await query.message.delete() - -@Client.on_message(filters.command("mediainfo") & filters.private) +@Client.on_message(filters.command("mediainfo") & filters.chat(GROUP)) async def mediainfo_handler(client: Client, message: Message): if not message.reply_to_message or (not message.reply_to_message.document and not message.reply_to_message.video): await message.reply_text("Please reply to a document or video to get media info.") @@ -2303,7 +2394,7 @@ async def mediainfo_handler(client: Client, message: Message): # Function to handle "/getmodapk" command -@Client.on_message(filters.private & filters.command("getmodapk")) +@Client.on_message(filters.command("getmodapk") & filters.chat(GROUP)) async def get_mod_apk(bot, msg: Message): if len(msg.command) < 2: return await msg.reply_text("Please provide a URL from getmodsapk.com or gamedva.com.") @@ -2394,8 +2485,7 @@ async def count_users(bot, msg): except Exception as e: await msg.reply_text(f"An error occurred: {e}") - -@Client.on_message(filters.command("stats")) +@Client.on_message(filters.command("stats") & filters.chat(GROUP)) async def stats_command(_, msg): uptime = datetime.datetime.now() - START_TIME uptime_str = str(timedelta(seconds=int(uptime.total_seconds()))) @@ -2508,7 +2598,7 @@ async def about_command(bot, msg): โฏ Dแดแด แดสแดแดแดส ๐ง๐ปโ๐ป : ๐๐๐๐๐๐๐๐โข โก โฏ Uแดแด แดแดแดs ๐ข : ๐๐๐๐๐๐๐ ๐ข โฏ Sแดแดแดแดสแด โจ : ๐๐๐๐๐๐๐ โจ -โฏ Bแดษชสแด Sแดแดแดแดs ๐ : แด 2.4 [Sแดแดสสแด] +โฏ Bแดษชสแด Sแดแดแดแดs ๐ : แด 2.5 [Sแดแดสสแด] """ await msg.reply_text(about_text) @@ -2541,8 +2631,12 @@ async def help_command(bot, msg): /gofile - ๐โ๐ ๐น๐๐๐๐ ๐๐๐๐๐๐ ๐๐ ๐บ๐๐๐๐๐ ๐ฟ๐๐๐ ๐ /mediainfo - ๐๐๐๐๐ & ๐๐๐๐๐ ๐ผ๐๐๐๐๐๐๐ก๐๐๐ โน๏ธ /ytdlleech - ๐ฟ๐๐๐โ ๐กโ๐ ๐๐๐ข๐ก๐ข๐๐ ๐ฟ๐๐๐๐ -/changeindexaudio - ๐ ๐๐๐๐๐๐ ๐กโ๐ ๐ ๐๐๐ข๐๐๐๐ [a-1 ๐๐๐ ๐๐๐๐๐ฃ๐ ๐๐ข๐๐๐ , a-2-1-3-4 ๐๐๐ ๐ ๐ค๐๐ ๐๐ข๐๐๐] -/changeindexsub - ๐ ๐๐๐๐๐๐ ๐กโ๐ ๐ ๐๐๐ข๐๐๐๐ [s-1 ๐๐๐ ๐๐๐๐๐ฃ๐ ๐ ๐ข๐๐ก๐๐ก๐๐ , s-2-1-3-4 ๐๐๐ ๐ ๐ค๐๐ ๐ ๐ข๐๐ก๐๐ก๐๐] +/streamremove - ๐ ๐๐๐๐ฃ๐ ๐ด๐ข๐๐๐๐ ๐๐ ๐๐ข๐๐ก๐๐ก๐๐๐ +/multitaskfile - ๐น๐๐ ๐น๐๐๐ ๐ถโ๐๐๐๐๐๐๐ก๐๐๐๐ก๐, ๐ ๐๐๐๐๐, ๐ถโ๐๐๐๐๐๐๐๐๐ฅ๐๐ข๐๐๐, ๐ถโ๐๐๐๐๐๐๐๐๐ฅ๐ ๐ข๐ = ๐๐ข๐๐ก๐๐ก๐๐ ๐๐๐๐๐ +/multitasklink - ๐น๐๐ ๐๐๐๐ [๐๐๐๐๐๐๐ & ๐๐๐๐๐ ๐ฟ๐๐๐๐ ] ๐๐๐ก๐๐๐๐ก๐, ๐ ๐๐๐๐๐, ๐ผ๐๐๐๐ฅ๐๐ข๐๐๐, ๐ผ๐๐๐๐ฅ๐ ๐ข๐ = ๐๐ข๐๐ก๐๐ก๐๐ ๐๐๐๐๐ +/compress - ๐๐๐๐๐๐๐ ๐ ๐กโ๐ ๐๐๐๐ ๐๐ 480๐ ,๐๐๐๐๐๐ข๐ [๐ด๐๐๐๐ & ๐๐๐๐ ๐๐๐๐๐ ๐ต๐๐ ๐ก] +/swapaudio - ๐ ๐๐๐๐๐๐ ๐กโ๐ ๐ ๐๐๐ข๐๐๐๐ [a-2-1-3-4 ๐๐๐ ๐ ๐ค๐๐ ๐๐ข๐๐๐] +/swapsubitles - ๐ ๐๐๐๐๐๐ ๐กโ๐ ๐ ๐๐๐ข๐๐๐๐ [s-2-1-3-4 ๐๐๐ ๐ ๐ค๐๐ ๐ ๐ข๐๐ก๐๐ก๐๐] /changemetadata - ๐๐๐๐๐ ๐๐๐๐ ๐กโ๐ ๐๐๐ก๐๐๐๐ก๐ /removetags - ๐๐ ๐ ๐๐๐๐ฃ๐ ๐ด๐๐ ๐๐๐ก๐๐๐๐ก๐ ๐๐๐๐ /merge - ๐๐๐๐ ๐ข๐ ๐ก๐ 10 ๐ฃ๐๐๐๐/๐๐๐๐ข๐๐๐๐ก ๐๐๐๐๐ ๐๐๐ ๐๐ฆ ๐๐๐. @@ -2567,7 +2661,7 @@ async def help_command(bot, msg): """ await msg.reply_text(help_text) - + #ALL FILES UPLOADED - CREDITS ๐ - @Sunrises_24 #Ping @@ -2579,7 +2673,852 @@ async def ping(bot, msg): time_taken_s = (end_t - start_t) * 1000 await rm.edit(f"Pong!๐\n{time_taken_s:.3f} ms") - +@Client.on_message(filters.command("multitaskfile") & filters.chat(GROUP)) +async def multitask_file(bot, msg: Message): + global MULTITASK_ENABLED + + if not MULTITASK_ENABLED: + return await msg.reply_text("Multi Task feature are currently disabled.") + + user_id = msg.from_user.id + + # Fetch metadata titles from the database + metadata_titles = await db.get_metadata_titles(user_id) + video_title = metadata_titles.get('video_title', '') + audio_title = metadata_titles.get('audio_title', '') + subtitle_title = metadata_titles.get('subtitle_title', '') + + if not any([video_title, audio_title, subtitle_title]): + return await msg.reply_text("Metadata titles are not set. Please set metadata titles using `/setmetadata video_title audio_title subtitle_title`.") + + reply = msg.reply_to_message + if not reply: + return await msg.reply_text("Please reply to a media file with the change command\nFormat: `/change a-2 -m -n filename.mkv`") + + if len(msg.command) < 5 or '-m' not in msg.command or '-n' not in msg.command: + return await msg.reply_text("Please provide the correct format\nFormat: `/change a-2 -m -n filename.mkv`") + + index_cmd = msg.command[1] + metadata_flag_index = msg.command.index('-m') + output_flag_index = msg.command.index('-n') + output_filename = " ".join(msg.command[output_flag_index + 1:]).strip() + + if not output_filename.lower().endswith(('.mkv', '.mp4', '.avi')): + return await msg.reply_text("Invalid file extension. Please use a valid video file extension (e.g., .mkv, .mp4, .avi).") + + media = reply.document or reply.audio or reply.video + if not media: + return await msg.reply_text("Please reply to a valid media file (audio, video, or document) with the change command.") + + sts = await msg.reply_text("๐ Downloading media... โก") + c_time = time.time() + try: + downloaded = await reply.download(progress=progress_message, progress_args=("๐ Download Started... โก๏ธ", sts, c_time)) + except Exception as e: + await safe_edit_message(sts, f"Error downloading media: {e}") + return + + # Output file path (temporary file) + intermediate_file = os.path.splitext(downloaded)[0] + "_indexed" + os.path.splitext(downloaded)[1] + + index_params = index_cmd.split('-') + stream_type = index_params[0] + indexes = [int(i) - 1 for i in index_params[1:]] + + # Construct the FFmpeg command to modify indexes + ffmpeg_cmd = ['ffmpeg', '-i', downloaded, '-map', '0:v'] # Always map video stream + + for idx in indexes: + ffmpeg_cmd.extend(['-map', f'0:{stream_type}:{idx}']) + + # Copy all subtitle streams if they exist + ffmpeg_cmd.extend(['-map', '0:s?']) + + ffmpeg_cmd.extend(['-c', 'copy', intermediate_file, '-y']) + + await safe_edit_message(sts, "๐ Changing audio indexing... โก") + process = await asyncio.create_subprocess_exec(*ffmpeg_cmd, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE) + stdout, stderr = await process.communicate() + + if process.returncode != 0: + await safe_edit_message(sts, f"โ FFmpeg error: {stderr.decode('utf-8')}") + os.remove(downloaded) + if os.path.exists(intermediate_file): + os.remove(intermediate_file) + return + + output_file = output_filename + + await safe_edit_message(sts, "๐ Changing metadata... โก") + try: + change_video_metadata(intermediate_file, video_title, audio_title, subtitle_title, output_file) + except Exception as e: + await safe_edit_message(sts, f"Error changing metadata: {e}") + os.remove(downloaded) + os.remove(intermediate_file) + return + + # Retrieve thumbnail from the database + thumbnail_file_id = await db.get_thumbnail(user_id) + file_thumb = None + if thumbnail_file_id: + try: + file_thumb = await bot.download_media(thumbnail_file_id) + except Exception: + pass + else: + if hasattr(media, 'thumbs') and media.thumbs: + try: + file_thumb = await bot.download_media(media.thumbs[0].file_id) + except Exception as e: + file_thumb = None + + filesize = os.path.getsize(output_file) + filesize_human = humanbytes(filesize) + cap = f"{output_filename}\n\n๐ Size: {filesize_human}" + + await safe_edit_message(sts, "๐ Uploading... โก") + c_time = time.time() + + if filesize > FILE_SIZE_LIMIT: + file_link = await upload_to_google_drive(output_file, output_filename, sts) + button = [[InlineKeyboardButton("โ๏ธ CloudUrl โ๏ธ", url=f"{file_link}")]] + await msg.reply_text( + f"**File successfully changed audio index and metadata, then uploaded to Google Drive!**\n\n" + f"**Google Drive Link**: [View File]({file_link})\n\n" + f"**Uploaded File**: {output_filename}\n" + f"**Request User:** {msg.from_user.mention}\n\n" + f"**Size**: {filesize_human}", + reply_markup=InlineKeyboardMarkup(button) + ) + else: + try: + await bot.send_document( + msg.chat.id, + document=output_file, + file_name=output_filename, + thumb=file_thumb, + caption=cap, + progress=progress_message, + progress_args=("๐ Upload Started... โก", sts, c_time) + ) + except Exception as e: + return await safe_edit_message(sts, f"Error: {e}") + + os.remove(downloaded) + os.remove(intermediate_file) + os.remove(output_file) + if file_thumb and os.path.exists(file_thumb): + os.remove(file_thumb) + await sts.delete() + +@Client.on_message(filters.command("multitasklink") & filters.chat(GROUP)) +async def changeleech(bot, msg: Message): + if len(msg.command) < 2 or not msg.reply_to_message: + return await msg.reply_text("Please reply to a file, video, audio, or link with the desired filename and extension (e.g., `.mkv`, `.mp4`, `.zip`).Please provide the correct format\nFormat: `/multitasklink a-2 -m -n filename.mkv`") + + reply = msg.reply_to_message + new_name = msg.text.split(" ", 1)[1] + + if not new_name.endswith((".mkv", ".mp4", ".zip")): + return await msg.reply_text("Please specify a filename ending with .mkv, .mp4, or .zip.") + + media = reply.document or reply.audio or reply.video or reply.text + + sts = await msg.reply_text("๐ Downloading... โก") + c_time = time.time() + + if reply.text and ("seedr" in reply.text or "workers" in reply.text): + await handle_link_download_multi(bot, msg, reply.text, new_name, media, sts, c_time) + else: + if not media: + return await msg.reply_text("Please reply to a valid file, video, audio, or link with the desired filename and extension (e.g., `.mkv`, `.mp4`, `.zip`).") + + try: + downloaded = await reply.download(file_name=new_name, progress=progress_message, progress_args=("๐ Download Started... โก๏ธ", sts, c_time)) + except RPCError as e: + return await sts.edit(f"Download failed: {e}") + + if not os.path.exists(downloaded): + return await sts.edit("File not found after download. Please check the reply and try again.") + + filesize = humanbytes(os.path.getsize(downloaded)) + + # Change indexing and metadata if required + if len(msg.command) > 2: + await change_metadata_and_index(bot, msg, downloaded, new_name, media, sts, c_time) + + # Thumbnail handling + thumbnail_file_id = await db.get_thumbnail(msg.from_user.id) + og_thumbnail = None + if thumbnail_file_id: + try: + og_thumbnail = await bot.download_media(thumbnail_file_id) + except Exception: + pass + else: + if hasattr(media, 'thumbs') and media.thumbs: + try: + og_thumbnail = await bot.download_media(media.thumbs[0].file_id) + except Exception: + pass + + await sts.edit("๐ Uploading... โก") + c_time = time.time() + + if os.path.getsize(downloaded) > FILE_SIZE_LIMIT: + file_link = await upload_to_google_drive(downloaded, new_name, sts) + await msg.reply_text(f"File uploaded to Google Drive!\n\n๐ **File Name:** {new_name}\n๐พ **Size:** {filesize}\n๐ **Link:** {file_link}") + else: + try: + await bot.send_document(msg.chat.id, document=downloaded, thumb=og_thumbnail, caption=new_name, progress=progress_message, progress_args=("๐ Upload Started... โก", sts, c_time)) + except ValueError as e: + return await sts.edit(f"Upload failed: {e}") + except TimeoutError as e: + return await sts.edit(f"Upload timed out: {e}") + + try: + if og_thumbnail and os.path.exists(og_thumbnail): + os.remove(og_thumbnail) + if os.path.exists(downloaded): + os.remove(downloaded) + except Exception as e: + print(f"Error deleting files: {e}") + + await sts.delete() + +async def handle_link_download_multi(bot, msg: Message, link: str, new_name: str, media, sts, c_time): + try: + async with aiohttp.ClientSession() as session: + async with session.get(link) as resp: + if resp.status == 200: + with open(new_name, 'wb') as f: + f.write(await resp.read()) + else: + await sts.edit(f"Failed to download file from link. Status code: {resp.status}") + return + except Exception as e: + await sts.edit(f"Error during download: {e}") + return + + if not os.path.exists(new_name): + await sts.edit("File not found after download. Please check the link and try again.") + return + + filesize = humanbytes(os.path.getsize(new_name)) + + # Change indexing and metadata if required + if len(msg.command) > 2: + await change_metadata_and_index(bot, msg, new_name, new_name, media, sts, c_time) + + # Thumbnail handling + thumbnail_file_id = await db.get_thumbnail(msg.from_user.id) + og_thumbnail = None + if thumbnail_file_id: + try: + og_thumbnail = await bot.download_media(thumbnail_file_id) + except Exception: + pass + else: + if hasattr(media, 'thumbs') and media.thumbs: + try: + og_thumbnail = await bot.download_media(media.thumbs[0].file_id) + except Exception: + pass + + await sts.edit("๐ Uploading... โก") + c_time = time.time() + + if os.path.getsize(new_name) > FILE_SIZE_LIMIT: + file_link = await upload_to_google_drive(new_name, new_name, sts) + await msg.reply_text(f"File uploaded to Google Drive!\n\n๐ **File Name:** {new_name}\n๐พ **Size:** {filesize}\n๐ **Link:** {file_link}") + else: + try: + await bot.send_document(msg.chat.id, document=new_name, thumb=og_thumbnail, caption=f"{new_name}\n\n๐ Size: {filesize}", progress=progress_message, progress_args=("๐ Upload Started... โก", sts, c_time)) + except ValueError as e: + return await sts.edit(f"Upload failed: {e}") + except TimeoutError as e: + return await sts.edit(f"Upload timed out: {e}") + + try: + if og_thumbnail and os.path.exists(og_thumbnail): + os.remove(og_thumbnail) + if os.path.exists(new_name): + os.remove(new_name) + except Exception as e: + print(f"Error deleting files: {e}") + + await sts.delete() + +async def change_metadata_and_index(bot, msg, downloaded, new_name, media, sts, c_time): + global METADATA_ENABLED, CHANGE_INDEX_ENABLED + + if not (METADATA_ENABLED and CHANGE_INDEX_ENABLED): + await msg.reply_text("One or more required features are currently disabled.") + return + + user_id = msg.from_user.id + + # Fetch metadata titles from the database + metadata_titles = await db.get_metadata_titles(user_id) + video_title = metadata_titles.get('video_title', '') + audio_title = metadata_titles.get('audio_title', '') + subtitle_title = metadata_titles.get('subtitle_title', '') + + if not any([video_title, audio_title, subtitle_title]): + await msg.reply_text("Metadata titles are not set. Please set metadata titles using `/setmetadata video_title audio_title subtitle_title`.") + return + + if len(msg.command) < 5 or '-m' not in msg.command or '-n' not in msg.command: + await msg.reply_text("Please provide the correct format\nFormat: `/multitasklink a-2 -m -n filename.mkv`") + return + + index_cmd = msg.command[1] + metadata_flag_index = msg.command.index('-m') + output_flag_index = msg.command.index('-n') + output_filename = " ".join(msg.command[output_flag_index + 1:]).strip() + + if not output_filename.lower().endswith(('.mkv', '.mp4', '.avi')): + await msg.reply_text("Invalid file extension. Please use a valid video file extension (e.g., .mkv, .mp4, .avi).") + return + + # Output file path (temporary file) + intermediate_file = os.path.splitext(downloaded)[0] + "_indexed" + os.path.splitext(downloaded)[1] + + index_params = index_cmd.split('-') + stream_type = index_params[0] + indexes = [int(i) - 1 for i in index_params[1:]] + + # Construct the FFmpeg command to modify indexes + ffmpeg_cmd = ['ffmpeg', '-i', downloaded, '-map', '0:v'] # Always map video stream + + for idx in indexes: + ffmpeg_cmd.extend(['-map', f'0:{stream_type}:{idx}']) + + # Copy all subtitle streams if they exist + ffmpeg_cmd.extend(['-map', '0:s?']) + + ffmpeg_cmd.extend(['-c', 'copy', intermediate_file, '-y']) + + await safe_edit_message(sts, "๐ Changing audio indexing... โก") + process = await asyncio.create_subprocess_exec(*ffmpeg_cmd, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE) + stdout, stderr = await process.communicate() + + if process.returncode != 0: + await safe_edit_message(sts, f"โ FFmpeg error: {stderr.decode('utf-8')}") + os.remove(downloaded) + if os.path.exists(intermediate_file): + os.remove(intermediate_file) + return + + output_file = output_filename + + await safe_edit_message(sts, "๐ Changing metadata... โก") + try: + change_video_metadata(intermediate_file, video_title, audio_title, subtitle_title, output_file) + except Exception as e: + await safe_edit_message(sts, f"Error changing metadata: {e}") + os.remove(downloaded) + os.remove(intermediate_file) + return + + # Retrieve thumbnail from the database + thumbnail_file_id = await db.get_thumbnail(user_id) + file_thumb = None + if thumbnail_file_id: + try: + file_thumb = await bot.download_media(thumbnail_file_id) + except Exception: + pass + else: + if hasattr(media, 'thumbs') and media.thumbs: + try: + file_thumb = await bot.download_media(media.thumbs[0].file_id) + except Exception as e: + file_thumb = None + + filesize = os.path.getsize(output_file) + filesize_human = humanbytes(filesize) + cap = f"{output_filename}\n\n๐ Size: {filesize_human}" + + await safe_edit_message(sts, "๐ Uploading... โก") + c_time = time.time() + + if filesize > FILE_SIZE_LIMIT: + file_link = await upload_to_google_drive(output_file, output_filename, sts) + button = [[InlineKeyboardButton("โ๏ธ CloudUrl โ๏ธ", url=f"{file_link}")]] + await msg.reply_text( + f"**File successfully changed audio index and metadata, then uploaded to Google Drive!**\n\n" + f"**Google Drive Link**: [View File]({file_link})\n\n" + f"**Uploaded File**: {output_filename}\n" + f"**Request User:** {msg.from_user.mention}\n\n" + f"**Size**: {filesize_human}", + reply_markup=InlineKeyboardMarkup(button) + ) + else: + try: + await bot.send_document( + msg.chat.id, + document=output_file, + file_name=output_filename, + thumb=file_thumb, + caption=cap, + progress=progress_message, + progress_args=("๐ Upload Started... โก", sts, c_time) + ) + except Exception as e: + return await safe_edit_message(sts, f"Error: {e}") + + os.remove(downloaded) + os.remove(intermediate_file) + os.remove(output_file) + if file_thumb and os.path.exists(file_thumb): + os.remove(file_thumb) + await sts.delete() + +#handler is streamremove +@Client.on_message(filters.command("streamremove") & filters.chat(GROUP)) +async def streamremove(bot, msg): + global STREAMREMOVE_ENABLED + global selected_streams + global downloaded + global output_filename + + if not STREAMREMOVE_ENABLED: + return await msg.reply_text("๐ซ The streamremove feature is currently disabled.") + + reply = msg.reply_to_message + if not reply: + return await msg.reply_text("โ Please reply to a media file with the command\nFormat: `/streamremove -n filename.mkv`") + + if len(msg.command) < 3 or msg.command[1] != "-n": + return await msg.reply_text("Please provide the filename with the `-n` flag\nFormat: `/streamremove -n filename.mkv`") + + output_filename = " ".join(msg.command[2:]).strip() + + if not output_filename.lower().endswith(('.mkv', '.mp4', '.avi')): + return await msg.reply_text("Invalid file extension. Please use a valid video file extension (e.g., .mkv, .mp4, .avi).") + + media = reply.document or reply.audio or reply.video + if not media: + return await msg.reply_text("โ Please reply to a valid media file (audio, video, or document) with the command.") + + sts = await msg.reply_text("๐ Downloading media... โก") + c_time = time.time() + try: + downloaded = await reply.download(progress=progress_message, progress_args=("๐ Download Started... โก๏ธ", sts, c_time)) + except Exception as e: + await sts.edit(f"โ Error downloading media: {e}") + return + + # Get the available streams + ffprobe_cmd = [ + 'ffprobe', '-v', 'error', '-show_entries', 'stream=index:stream_tags=language:stream=codec_type', '-of', 'json', downloaded + ] + process = await asyncio.create_subprocess_exec(*ffprobe_cmd, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE) + stdout, stderr = await process.communicate() + + if process.returncode != 0: + await sts.edit(f"โ FFprobe error: {stderr.decode('utf-8')}") + os.remove(downloaded) + return + + streams = json.loads(stdout.decode('utf-8')).get('streams', []) + audio_video_streams = [] + subtitle_streams = [] + + for stream in streams: + stream_index = stream['index'] + language = stream.get('tags', {}).get('language', 'unknown') + codec_type = stream['codec_type'] + + if codec_type == 'audio': + if language == 'tel': + audio_video_streams.append(f"{stream_index} ๐ต Telugu Audio") + elif language == 'tam': + audio_video_streams.append(f"{stream_index} ๐ต Tamil Audio") + elif language == 'hin': + audio_video_streams.append(f"{stream_index} ๐ต Hindi Audio") + else: + audio_video_streams.append(f"{stream_index} ๐ต Audio - {language}") + elif codec_type == 'subtitle': + if language == 'eng': + subtitle_streams.append(f"{stream_index} ๐ English Subtitle") + else: + subtitle_streams.append(f"{stream_index} ๐ {language} - Subtitle") + elif codec_type == 'video': + audio_video_streams.append(f"{stream_index} ๐น Video") + + # Build the inline keyboard with available streams + buttons = [] + max_len = max(len(audio_video_streams), len(subtitle_streams)) + for i in range(max_len): + row = [] + if i < len(audio_video_streams): + row.append(InlineKeyboardButton(f"{audio_video_streams[i]}", callback_data=f"toggle_{audio_video_streams[i].split()[0]}")) + if i < len(subtitle_streams): + row.append(InlineKeyboardButton(f"{subtitle_streams[i]}", callback_data=f"toggle_{subtitle_streams[i].split()[0]}")) + buttons.append(row) + + buttons.append([InlineKeyboardButton("๐ Reverse Selection", callback_data="reverse")]) + buttons.append([InlineKeyboardButton("โ Cancel", callback_data="cancel"), InlineKeyboardButton("โ Done", callback_data="done")]) + markup = InlineKeyboardMarkup(buttons) + + selected_streams.clear() + start_time = time.time() + message = await sts.edit("Select the streams you want to remove (you have 60 seconds):", reply_markup=markup) + + # Wait for 60 seconds + await asyncio.sleep(60) + + if time.time() - start_time < 60: + # If the user has not interacted within 60 seconds, cancel the process + if message: + await message.edit("๐ Time's up! Selection process has been canceled.") + await asyncio.sleep(5) # Keep the message visible for a short time before deleting + await message.delete() + if downloaded: + os.remove(downloaded) + + + +@Client.on_callback_query(filters.regex(r'toggle_\d+|done|cancel|reverse')) +async def callback_query_handler(bot, callback_query: CallbackQuery): + global selected_streams + global downloaded + global output_filename + data = callback_query.data + + # Check if the user who initiated the command matches the callback query user + if callback_query.from_user.id != callback_query.message.reply_to_message.from_user.id: + return + + if data == "cancel": + await callback_query.message.delete() + if downloaded: + os.remove(downloaded) + return + + if data == "reverse": + buttons = callback_query.message.reply_markup.inline_keyboard + all_indices = {btn.callback_data.split('_')[1] for row in buttons for btn in row if btn.callback_data.startswith('toggle_')} + selected_streams.symmetric_difference_update(all_indices) + + # Update button text + for row in buttons: + for button in row: + if button.callback_data.startswith("toggle_"): + index = button.callback_data.split('_')[1] + if index in selected_streams: + button.text = f"โ {button.text.lstrip('โ ').strip()}" + else: + button.text = button.text.lstrip('โ ').strip() + + await callback_query.message.edit_reply_markup(reply_markup=InlineKeyboardMarkup(buttons)) + return + + if data == "done": + sts = await callback_query.message.edit_text("๐ Removing selected streams... โก") + await process_media(bot, callback_query, selected_streams, downloaded, output_filename, sts) + return + + # Toggle selection state + index = data.split('_')[1] + if index in selected_streams: + selected_streams.remove(index) + else: + selected_streams.add(index) + + # Update buttons to reflect selection + buttons = callback_query.message.reply_markup.inline_keyboard + for row in buttons: + for button in row: + if button.callback_data == f"toggle_{index}": + if button.text.startswith("โ "): + button.text = button.text[2:] # Remove the checkmark + else: + button.text = f"โ {button.text}" # Add the checkmark + break + + await callback_query.message.edit_reply_markup(reply_markup=InlineKeyboardMarkup(buttons)) + +# Process media function +async def process_media(bot, callback_query, selected_streams, downloaded, output_filename, sts): + user_id = callback_query.from_user.id + original_message = callback_query.message.reply_to_message + output_file = output_filename + + # Construct FFmpeg command to process media + ffmpeg_cmd = ['ffmpeg', '-i', downloaded, '-map', '0'] + for idx in selected_streams: + ffmpeg_cmd.extend(['-map', f'-0:{idx}']) + ffmpeg_cmd.extend(['-c', 'copy', output_file, '-y']) + + # Execute FFmpeg command + process = await asyncio.create_subprocess_exec( + *ffmpeg_cmd, + stdout=asyncio.subprocess.PIPE, + stderr=asyncio.subprocess.PIPE + ) + stdout, stderr = await process.communicate() + + if process.returncode != 0: + await safe_edit_message(sts, f"โ FFmpeg error: {stderr.decode('utf-8')}") + os.remove(downloaded) + if os.path.exists(output_file): + os.remove(output_file) + return + + # Retrieve thumbnail from the database + thumbnail_file_id = await db.get_thumbnail(user_id) + file_thumb = None + if thumbnail_file_id: + try: + file_thumb = await bot.download_media(thumbnail_file_id) + except Exception: + pass + else: + if hasattr(original_message, 'thumbs') and original_message.thumbs: + try: + file_thumb = await bot.download_media(original_message.thumbs[0].file_id) + except Exception as e: + file_thumb = None + + filesize = os.path.getsize(output_file) + filesize_human = humanbytes(filesize) + cap = f"{output_filename}\n\n๐ Size: {filesize_human}" + + await safe_edit_message(sts, "๐ Uploading... โก") + c_time = time.time() + + if filesize > FILE_SIZE_LIMIT: + file_link = await upload_to_google_drive(output_file, output_filename, sts) + button = [[InlineKeyboardButton("โ๏ธ CloudUrl โ๏ธ", url=file_link)]] + await bot.send_message( + chat_id=user_id, + text=( + f"**File successfully stream removed and uploaded to Google Drive!**\n\n" + f"**Google Drive Link**: [View File]({file_link})\n\n" + f"**Uploaded File**: {output_filename}\n" + f"**Request User:** {callback_query.from_user.mention}\n\n" + f"**Size**: {filesize_human}" + ), + reply_markup=InlineKeyboardMarkup(button) + ) + else: + try: + await bot.send_document( + chat_id=user_id, + document=output_file, + thumb=file_thumb, + caption=cap, + progress=progress_message, + progress_args=("๐ Upload Started... โก", sts, c_time) + ) + except Exception as e: + await safe_edit_message(sts, f"Error: {e}") + + # Send a message to the user after the file is sent to their PM + group_message_text = ( + f"โ๐ฅ **File Name:** {output_filename}\n" + f"โ ๐พ **Size:** {filesize_human}\n" + f"โ โป๏ธ **Mode:** Stream Remove\n" + f"โ๐น **Request User:** {callback_query.from_user.mention}\n\n" + f"โ **File has been sent in Bot PM!**" + ) + await bot.send_message( + chat_id=GROUP, # Send the group message to the user + text=group_message_text + ) + + os.remove(downloaded) + os.remove(output_file) + if file_thumb and os.path.exists(file_thumb): + os.remove(file_thumb) + await sts.delete() + +#handler is Compress +@Client.on_message(filters.command("compress") & filters.chat(GROUP)) +async def compress_media(bot, msg: Message): + global COMPRESS_ENABLED + + if not COMPRESS_ENABLED: + return await msg.reply_text("Compress feature is currently disabled.") + + user_id = msg.from_user.id + + reply = msg.reply_to_message + if not reply: + return await msg.reply_text("Please reply to a media file with the compress command\nFormat: `compress -n output_filename`") + + if len(msg.command) < 3 or msg.command[1] != "-n": + return await msg.reply_text("Please provide the output filename with the `-n` flag\nFormat: `compress -n output_filename`") + + output_filename = " ".join(msg.command[2:]).strip() + + if not output_filename.lower().endswith(('.mkv', '.mp4', '.avi')): + return await msg.reply_text("Invalid file extension. Please use a valid video file extension (e.g., .mkv, .mp4, .avi).") + + media = reply.document or reply.audio or reply.video + if not media: + return await msg.reply_text("Please reply to a valid media file (audio, video, or document) with the compress command.") + + sts = await msg.reply_text("๐ Downloading media... โก") + c_time = time.time() + try: + downloaded = await reply.download(progress=progress_message, progress_args=("๐ Download Started... โก๏ธ", sts, c_time)) + except Exception as e: + await safe_edit_message(sts, f"Error downloading media: {e}") + return + + output_file = output_filename + + # Retrieve metadata from the database + metadata_titles = await db.get_metadata_titles(user_id) + video_title = metadata_titles.get('video_title', '') + audio_title = metadata_titles.get('audio_title', '') + subtitle_title = metadata_titles.get('subtitle_title', '') + + await safe_edit_message(sts, "๐ Compressing media... โก") + try: + compress_video(downloaded, output_file, video_title, audio_title, subtitle_title) + except Exception as e: + await safe_edit_message(sts, f"Error compressing media: {e}") + os.remove(downloaded) + return + + # Retrieve thumbnail from the database + thumbnail_file_id = await db.get_thumbnail(user_id) + file_thumb = None + if thumbnail_file_id: + try: + file_thumb = await bot.download_media(thumbnail_file_id) + except Exception: + pass + else: + if hasattr(media, 'thumbs') and media.thumbs: + try: + file_thumb = await bot.download_media(media.thumbs[0].file_id) + except Exception as e: + file_thumb = None + + # Get media info and upload to Telegraph + media_info_html, media_info_link = await get_and_upload_mediainfo(bot, output_file, media) + + filesize = os.path.getsize(output_file) + filesize_human = humanbytes(filesize) + cap = f"{output_filename}\n\n๐ Size: {filesize_human}\n\n[MediaInfo โน๏ธ]({media_info_link})" + + await safe_edit_message(sts, "๐ Uploading... โก") + c_time = time.time() + + if filesize > FILE_SIZE_LIMIT: + file_link = await upload_to_google_drive(output_file, output_filename, sts) + button = [[InlineKeyboardButton("โ๏ธ CloudUrl โ๏ธ", url=f"{file_link}")]] + await msg.reply_text( + f"**File successfully compressed and uploaded to Google Drive!**\n\n" + f"**Google Drive Link**: [View File]({file_link})\n\n" + f"**Uploaded File**: {output_filename}\n" + f"**Request User:** {msg.from_user.mention}\n\n" + f"**Size**: {filesize_human}\n" + f"[MediaInfo โน๏ธ]({media_info_link})", + reply_markup=InlineKeyboardMarkup(button) + ) + else: + try: + await bot.send_document(msg.chat.id, document=output_file, thumb=file_thumb, caption=cap, progress=progress_message, progress_args=("๐ Upload Started... โก", sts, c_time)) + except Exception as e: + return await safe_edit_message(sts, f"Error: {e}") + + os.remove(downloaded) + os.remove(output_file) + if file_thumb and os.path.exists(file_thumb): + os.remove(file_thumb) + await sts.delete() + +@Client.on_message(filters.command("dleech") & filters.chat(GROUP)) +async def drive_leech(bot, msg: Message): + global MIRROR_ENABLED + + if not MIRROR_ENABLED: + return await msg.reply_text("Rename feature is currently disabled.") + + user_id = msg.from_user.id + + if len(msg.command) < 2 or not msg.reply_to_message: + return await msg.reply_text("Please reply to a file, video, or audio with the new filename and extension (e.g., .mkv, .mp4, .zip).") + + reply = msg.reply_to_message + media = reply.document or reply.audio or reply.video or reply.text + if not media: + return await msg.reply_text("Please reply to a file, video, or audio with the new filename and extension (e.g., .mkv, .mp4, .zip).") + + new_name = msg.text.split(" ", 1)[1] + sts = await msg.reply_text("๐ Downloading... โก") + + # Extract the Google Drive link from the caption or message text + drive_url = reply.text or reply.caption + file_id = extract_id_from_url(drive_url) + + if not file_id: + return await sts.edit("โ Invalid Google Drive link.") + + # Download the file from Google Drive with progress updates + downloaded_file = await download_file_from_drive(drive_service, file_id, new_name, sts) + filesize = humanbytes(os.path.getsize(downloaded_file)) + + if CAPTION: + try: + cap = CAPTION.format(file_name=new_name, file_size=filesize) + except KeyError as e: + return await sts.edit(text=f"Caption error: unexpected keyword ({e})") + else: + cap = f"{new_name}\n\n๐ Size: {filesize}" + + # Retrieve thumbnail from the database + thumbnail_file_id = await db.get_thumbnail(msg.from_user.id) + og_thumbnail = None + if thumbnail_file_id: + try: + og_thumbnail = await bot.download_media(thumbnail_file_id) + except Exception: + pass + else: + if hasattr(media, 'thumbs') and media.thumbs: + try: + og_thumbnail = await bot.download_media(media.thumbs[0].file_id) + except Exception: + pass + + await sts.edit("๐ Uploading... โก") + + try: + await bot.send_document(msg.chat.id, document=downloaded_file, thumb=og_thumbnail, caption=cap, progress=progress_message, progress_args=("๐ Upload Started... โก", sts, time.time())) + except Exception as e: + return await sts.edit(f"Error: {e}") + + os.remove(downloaded_file) + await sts.delete() + +@Client.on_message(filters.command('restart') & filters.user(ADMIN)) +async def restart_message(app, message): + reply = await message.reply_text('Restarting...') + textx = f"Done Restart...โ " + await reply.edit_text(textx) + try: + exit() + finally: + osexecl(executable, executable, "bot.py") + + +@Client.on_message(filters.command('logs') & filters.user(ADMIN)) +async def log_file(b, m): + try: + await m.reply_document('SunrisesBot.txt') + except Exception as e: + await m.reply(str(e)) + + if __name__ == '__main__': app = Client("my_bot", bot_token=BOT_TOKEN) app.run() diff --git a/main/utils.py b/main/utils.py index 0d54993..d18badd 100644 --- a/main/utils.py +++ b/main/utils.py @@ -2,6 +2,8 @@ from pyrogram.types import InlineKeyboardButton, InlineKeyboardMarkup import heroku3 import os +import io +from googleapiclient.http import MediaIoBaseDownload #ALL FILES UPLOADED - CREDITS ๐ - @Sunrises_24 PROGRESS_BAR = """ @@ -19,6 +21,7 @@ โ โฐโโโโโโโโโโโโโโโโโโ""" + #ALL FILES UPLOADED - CREDITS ๐ - @Sunrises_24 async def progress_message(current, total, ud_type, message, start): now = time.time() @@ -55,6 +58,7 @@ async def progress_message(current, total, ud_type, message, start): print(f"Error editing message: {e}") + #ALL FILES UPLOADED - CREDITS ๐ - @Sunrises_24 def TimeFormatter(milliseconds: int) -> str: seconds, milliseconds = divmod(milliseconds, 1000) @@ -134,3 +138,43 @@ async def upload_files(bot, chat_id, directory, base_path=""): elif os.path.isdir(item_path): await upload_files(bot, chat_id, item_path, base_path=os.path.join(base_path, item)) +async def drive_progress(current, total, ud_type, message, start): + now = time.time() + diff = now - start + + # Calculate the percentage and speed + percentage = current * 100 / total + speed = humanbytes(current / diff) + "/s" + # Create a short progress message + progress = f"{round(percentage, 2)}% - {humanbytes(current)} of {humanbytes(total)} @ {speed}" + try: + # Update the bot message with the short progress + await message.edit( + text=f"{ud_type}\n\nProgress: {progress}", + reply_markup=InlineKeyboardMarkup([[InlineKeyboardButton("๐ Jแดษชษด Us ๐", url="https://t.me/Sunrises24botupdates")]]) + ) + except Exception as e: + print(f"Error editing message: {e}") + +async def download_file_from_drive(service, file_id, file_name, message): + request = service.files().get_media(fileId=file_id) + file_buffer = io.BytesIO() + downloader = MediaIoBaseDownload(file_buffer, request) + + done = False + start_time = time.time() + + while not done: + status, done = downloader.next_chunk() + if status: + current_size = status.resumable_progress + total_size = status.total_size + + # Update progress message + await drive_progress(current_size, total_size, "๐ Downloading from Google Drive... โก", message, start_time) + + file_buffer.seek(0) + with open(file_name, 'wb') as f: + f.write(file_buffer.read()) + + return file_name diff --git a/requirements.txt b/requirements.txt index e933fd4..4118b39 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,4 @@ -pyrogram==2.0.83 -pyrofork +pyrogram==2.0.83 Tgcrypto ffmpeg-python rarfile @@ -20,3 +19,5 @@ lxml_html_clean motor pymongo datetime +psutil +ujson diff --git a/run.sh b/run.sh new file mode 100644 index 0000000..4d3190c --- /dev/null +++ b/run.sh @@ -0,0 +1 @@ +python3 update.py && python3 bot.py diff --git a/update.py b/update.py new file mode 100644 index 0000000..5e532f9 --- /dev/null +++ b/update.py @@ -0,0 +1,29 @@ + +from subprocess import run as srun +from os import path as ospath +from sys import executable +from os import execl as osexecl + +UPSTREAM_REPO = 'https://github.com/harsha7668/metabor' +UPSTREAM_BRANCH = 'SH24BOTS-GD-REVERSION-GRP' + +if UPSTREAM_REPO is not None: + if ospath.exists('.git'): + srun(["rm", "-rf", ".git"]) + + update = srun([f"git init -q \ + && git config --global user.email sunriseseditsoffical249@gmail.com \ + && git config --global user.name metamorpher \ + && git add . \ + && git commit -sm update -q \ + && git remote add origin {UPSTREAM_REPO} \ + && git fetch origin -q \ + && git reset --hard origin/{UPSTREAM_BRANCH} -q"], shell=True) + + + if update.returncode == 0: + osexecl(executable, executable, "bot.py") + else: + print('Something went wrong while updating, check UPSTREAM_REPO if valid or not!') + +osexecl(executable, executable, "bot.py") diff --git a/versions.txt b/versions.txt new file mode 100644 index 0000000..9dfcae7 --- /dev/null +++ b/versions.txt @@ -0,0 +1,88 @@ +โโใ Version v.1.0 ใโโ +โข Initial commit + +โโใ Version V.2.0 ใโโ +โข /Rename ,/help, /about ,/ping commands. +โข Adding button. + +โโใ Version V.2.1 ใโโ +โข Added Start With Forcesub. +โข Dual Forcesub +โข New variables: +[FSUB_CHANNEL, FSUB_GROUP] + +โโใ Version V.2.2 ใโโ +โข Auth fix. +โข Precommit file fixed. +โข Variables errors fixed. + +โโใ Version V.2.3 ใโโ +โข New Command: + /usersettings + /bsettings + /changemetadata + /changeindexaudio + /Changeindexsub + /removetags + /screenshots + /samplevideo + /attachphoto + -setphoto cmd +โข Sort imports +โข Removed useless imports. +โข Removed useless codes. +โข Format python code. +โข print() function use. +โข Group & Private Branch Separate +โข updates.txt file for updates logs. + +โโใ Version V.2.4 ใโโ +โขNew Comamnd : + /gofile + /gofilesetup + /gdriveid - setup + /mirror + /clone + /clean + /list +โข Implemented Progress Status Bar. +โข Added Google drive For Above 2GB files upload - For all commands +โข Small changes and fixes. + +โโใ Version V.2.5 ใโโ +**Major Update** +โข Database Support. +โข Implemented Settings. +โข New Command: + /ytdlleech + /mediainfo + /stats +โข Admin Command: + /clear - Clear Database + /ban + /unban + /users + /broadcast +โข Log Channel +โข Small changes and fixes. +โข Support Render, Koyeb Support. +โข Docker File Updated : Mediainfo, Ffmpeg +โข Use pyrofork for Peer ID Invalid error +โข version.txt file for updates logs. + +โโใ Version V.2.6 ใโโ +**Minor Update** +โข Implemented Settings. +โข New Command: + /streamremove + /multitaskfile + /multitasklink + /compress +โข Implement Some Help Command + +โโใ Version V.2.7 ใโโ +Minor Update +โข New Commands: + /Logs + /Restart + /Dleech (drive link leech) (2GB)