diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b6e4761 --- /dev/null +++ b/.gitignore @@ -0,0 +1,129 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +pip-wheel-metadata/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +.python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index 0bd91ea..0000000 --- a/Dockerfile +++ /dev/null @@ -1,8 +0,0 @@ -FROM python:3.9.2-slim-buster -RUN mkdir /app && chmod 777 /app -WORKDIR /app -ENV DEBIAN_FRONTEND=noninteractive -RUN apt -qq update && apt -qq install -y git python3 python3-pip ffmpeg -COPY . . -RUN pip3 install --no-cache-dir -r requirements.txt -CMD ["bash","bash.sh"] diff --git a/app.json b/app.json index d27f2e8..142f17a 100644 --- a/app.json +++ b/app.json @@ -1,15 +1,16 @@ { - "name": "Save restricted content bot", - "description": "Telegram bot to save restricted content.", + "name": "Save Restricted", + "description": "Save restricted content", "logo": "", "keywords": [ + "Best", "telegram", - "Save restricted content", + "save restricted", "bot" ], - "repository": "https://github.com/8769ANURAG/SaveRestrictedContentBot", + "repository": "https://github.com/AM-ROBOTS/SaveRestrictedContentBot", "website": "", - "success_url": "https://t.me/sources_cods", + "success_url": "https://github.com/AM-ROBOTS/SaveRestrictedContentBot", "env": { "API_HASH": { "description": "Your API HASH from my.telegram.org", @@ -24,15 +25,7 @@ "value": "" }, "SESSION": { - "description": "Pyrogram string session.", - "value": "" - }, - "AUTH": { - "description": "User ID of Bot owner.", - "value": "" - }, - "FORCESUB": { - "description": "Username name of public channel without using '@'.", + "description": "pyrogram string session.", "value": "" } }, diff --git a/bash.sh b/bash.sh deleted file mode 100644 index 4bafc42..0000000 --- a/bash.sh +++ /dev/null @@ -1,2 +0,0 @@ -echo "starting Bot ~@Am_RoBots"; -python3 -m main diff --git a/main/__init__.py b/main/__init__.py index bb46c12..57ece5e 100644 --- a/main/__init__.py +++ b/main/__init__.py @@ -1,12 +1,9 @@ #Github.com/8769Anurag -from pyrogram import Client - -from telethon.sessions import StringSession -from telethon.sync import TelegramClient - +from telethon import TelegramClient from decouple import config -import logging, time, sys +import logging +import time logging.basicConfig(format='[%(levelname) 5s/%(asctime)s] %(name)s: %(message)s', level=logging.WARNING) @@ -16,31 +13,5 @@ API_HASH = config("API_HASH", default=None) BOT_TOKEN = config("BOT_TOKEN", default=None) SESSION = config("SESSION", default=None) -FORCESUB = config("FORCESUB", default=None) -AUTH = config("AUTH", default=None, cast=int) bot = TelegramClient('bot', API_ID, API_HASH).start(bot_token=BOT_TOKEN) - -userbot = Client( - session_name=SESSION, - api_hash=API_HASH, - api_id=API_ID) - -try: - userbot.start() -except BaseException: - print("Userbot Error ! Have you added SESSION while deploying??") - sys.exit(1) - -Bot = Client( - "SaveRestricted", - bot_token=BOT_TOKEN, - api_id=int(API_ID), - api_hash=API_HASH -) - -try: - Bot.start() -except Exception as e: - print(e) - sys.exit(1) diff --git a/main/__main__.py b/main/__main__.py index dc516af..ffaa319 100644 --- a/main/__main__.py +++ b/main/__main__.py @@ -15,9 +15,7 @@ plugin_name = patt.stem load_plugins(plugin_name.replace(".py", "")) -#Don't be a thief print("Successfully deployed!") -print("By Anurag Maheshwari • Am_RoBots") if __name__ == "__main__": bot.run_until_disconnected() diff --git a/main/plugins/batch.py b/main/plugins/batch.py deleted file mode 100644 index c0e0706..0000000 --- a/main/plugins/batch.py +++ /dev/null @@ -1,103 +0,0 @@ -#Tg:sources_cods/Am_RoBots -#Github.com/8769Anurag - -""" -Plugin for both public & private channels! -""" - -import time, os, asyncio - -from .. import bot as Drone -from .. import userbot, Bot, AUTH -from .. import FORCESUB as fs -from main.plugins.pyroplug import check, get_bulk_msg -from main.plugins.helpers import get_link, screenshot - -from telethon import events, Button, errors -from telethon.tl.types import DocumentAttributeVideo - -from pyrogram import Client -from pyrogram.errors import FloodWait - -from ethon.pyfunc import video_metadata -from ethon.telefunc import force_sub - -ft = f"To use this bot you've to join @{fs}." - -batch = [] - -async def get_pvt_content(event, chat, id): - msg = await userbot.get_messages(chat, ids=id) - await event.client.send_message(event.chat_id, msg) - -@Drone.on(events.NewMessage(incoming=True, from_users=AUTH, pattern='/batch')) -async def _batch(event): - if not event.is_private: - return - # wtf is the use of fsub here if the command is meant for the owner? - # well am too lazy to clean - s, r = await force_sub(event.client, fs, event.sender_id, ft) - if s == True: - await event.reply(r) - return - if f'{event.sender_id}' in batch: - return await event.reply("You've already started one batch, wait for it to complete you dumbfuck owner!") - async with Drone.conversation(event.chat_id) as conv: - if s != True: - await conv.send_message("Send me the message link you want to start saving from, as a reply to this message.", buttons=Button.force_reply()) - try: - link = await conv.get_reply() - try: - _link = get_link(link.text) - except Exception: - await conv.send_message("No link found.") - except Exception as e: - print(e) - return await conv.send_message("Cannot wait more longer for your response!") - await conv.send_message("Send me the number of files/range you want to save from the given message, as a reply to this message.", buttons=Button.force_reply()) - try: - _range = await conv.get_reply() - except Exception as e: - print(e) - return await conv.send_message("Cannot wait more longer for your response!") - try: - value = int(_range.text) - if value > 100: - return await conv.send_message("You can only get upto 100 files in a single batch.") - except ValueError: - return await conv.send_message("Range must be an integer!") - s, r = await check(userbot, Bot, _link) - if s != True: - await conv.send_message(r) - return - batch.append(f'{event.sender_id}') - await run_batch(userbot, Bot, event.sender_id, _link, value) - conv.cancel() - batch.pop(0) - - -async def run_batch(userbot, client, sender, link, _range): - for i in range(_range): - timer = 60 - if i < 25: - timer = 5 - if i < 50 and i > 25: - timer = 10 - if i < 100 and i > 50: - timer = 15 - if not 't.me/c/' in link: - if i < 25: - timer = 2 - else: - timer = 3 - try: - await get_bulk_msg(userbot, client, sender, link, i) - except FloodWait as fw: - await asyncio.sleep(fw.seconds + 5) - await get_bulk_msg(userbot, client, sender, link, i) - protection = await client.send_message(sender, f"Sleeping for `{timer}` seconds to avoid Floodwaits and Protect account!") - time.sleep(timer) - await protection.delete() - - - diff --git a/main/plugins/progress.py b/main/plugins/display_progress.py similarity index 100% rename from main/plugins/progress.py rename to main/plugins/display_progress.py diff --git a/main/plugins/frontend.py b/main/plugins/frontend.py deleted file mode 100644 index 69f4680..0000000 --- a/main/plugins/frontend.py +++ /dev/null @@ -1,46 +0,0 @@ -#Github.com/8769Anurag - -import time, os - -from .. import bot as Drone -from .. import userbot, Bot -from .. import FORCESUB as fs -from main.plugins.pyroplug import get_msg -from main.plugins.helpers import get_link, join, screenshot - -from telethon import events - -from ethon.telefunc import force_sub - -ft = f"To use this bot you've to join @{fs}." - -message = "Send me the message link you want to start saving from, as a reply to this message." - -# To-Do: -# Make these codes shorter and clean -# ofc will never do it. - -@Drone.on(events.NewMessage(incoming=True, func=lambda e: e.is_private)) -async def clone(event): - if event.is_reply: - reply = await event.get_reply_message() - if reply.text == message: - return - try: - link = get_link(event.text) - if not link: - return - except TypeError: - return - s, r = await force_sub(event.client, fs, event.sender_id, ft) - if s == True: - await event.reply(r) - return - edit = await event.reply("Processing!") - if 't.me/+' in link: - q = await join(userbot, link) - await edit.edit(q) - return - if 't.me/' in link: - await get_msg(userbot, Bot, event.sender_id, edit.id, link, 0) - diff --git a/main/plugins/helpers.py b/main/plugins/helpers.py index c3731ca..d982bad 100644 --- a/main/plugins/helpers.py +++ b/main/plugins/helpers.py @@ -1,11 +1,9 @@ #Github.com/8769Anurag -from pyrogram.errors import FloodWait, InviteHashInvalid, InviteHashExpired, UserAlreadyParticipant -from telethon import errors, events +from pyrogram import Client +from pyrogram.errors import FloodWait, BadRequest import asyncio, subprocess, re, os, time -from pathlib import Path -from datetime import datetime as dt #Join private chat------------------------------------------------------------------------------------------------------------- @@ -13,16 +11,13 @@ async def join(client, invite_link): try: await client.join_chat(invite_link) return "Successfully joined the Channel" - except UserAlreadyParticipant: - return "User is already a participant." - except (InviteHashInvalid, InviteHashExpired): + except BadRequest: return "Could not join. Maybe your link is expired or Invalid." except FloodWait: return "Too many requests, try again later." except Exception as e: - print(e) - return "Could not join, try joining manually." - + return f"{str(e)}" + #Regex--------------------------------------------------------------------------------------------------------------- #to get the url from event @@ -40,34 +35,23 @@ def get_link(string): #Screenshot--------------------------------------------------------------------------------------------------------------- -def hhmmss(seconds): - x = time.strftime('%H:%M:%S',time.gmtime(seconds)) - return x - -async def screenshot(video, duration, sender): - if os.path.exists(f'{sender}.jpg'): +async def screenshot(video, time_stamp, sender): + if os.path.isfile(f'{sender}.jpg'): return f'{sender}.jpg' - time_stamp = hhmmss(int(duration)/2) - out = dt.now().isoformat("_", "seconds") + ".jpg" - cmd = ["ffmpeg", - "-ss", - f"{time_stamp}", - "-i", - f"{video}", - "-frames:v", - "1", - f"{out}", - "-y" - ] + out = str(video).split(".")[0] + ".jpg" + cmd = (f"ffmpeg -ss {time_stamp} -i {video} -vframes 1 {out}").split(" ") process = await asyncio.create_subprocess_exec( - *cmd, - stdout=asyncio.subprocess.PIPE, - stderr=asyncio.subprocess.PIPE - ) + *cmd, + stdout=asyncio.subprocess.PIPE, + stderr=asyncio.subprocess.PIPE) + stdout, stderr = await process.communicate() x = stderr.decode().strip() y = stdout.decode().strip() + print(x) + print(y) if os.path.isfile(out): return out else: - None + None + diff --git a/main/plugins/main.py b/main/plugins/main.py new file mode 100644 index 0000000..8479232 --- /dev/null +++ b/main/plugins/main.py @@ -0,0 +1,130 @@ +#Github.com/8769Anurag + +from main.plugins.helpers import get_link, join, screenshot +from main.plugins.display_progress import progress_for_pyrogram + +from decouple import config + +API_ID = config("API_ID", default=None, cast=int) +API_HASH = config("API_HASH", default=None) +BOT_TOKEN = config("BOT_TOKEN", default=None) +SESSION = config("SESSION", default=None) #pyro session + +from pyrogram.errors import FloodWait, BadRequest +from pyrogram import Client, filters +from ethon.pyfunc import video_metadata + +import re, time, asyncio, logging, os + +logging.basicConfig(format='[%(levelname) 5s/%(asctime)s] %(name)s: %(message)s', + level=logging.WARNING) + +Bot = Client( + "Simple-Pyrogram-Bot", + bot_token=BOT_TOKEN, + api_id=int(API_ID), + api_hash=API_HASH +) + +userbot = Client( + session_name=SESSION, + api_hash=API_HASH, + api_id=API_ID) + +def thumbnail(sender): + if os.path.exists(f'{sender}.jpg'): + return f'{sender}.jpg' + else: + return None + +async def get_msg(userbot, client, sender, msg_link, edit): + chat = "" + msg_id = int(msg_link.split("/")[-1]) + if 't.me/c/' in msg_link: + chat = int('-100' + str(msg_link.split("/")[-2])) + try: + msg = await userbot.get_messages(chat, msg_id) + file = await userbot.download_media( + msg, + progress=progress_for_pyrogram, + progress_args=( + userbot, + "**DOWNLOADING:**\n", + edit, + time.time() + ) + ) + await edit.edit('Trying to Upload.') + caption = "" + if msg.text is not None: + caption = msg.text + if str(file).split(".")[-1] == 'mkv' or 'mp4' or 'webm': + if str(file).split(".")[-1] == 'webm' or 'mkv': + path = str(file).split(".")[0] + ".mp4" + os.rename(file, path) + file = str(file).split(".")[0] + ".mp4" + data = video_metadata(file) + duration = data["duration"] + thumb_path = await screenshot(file, duration/2, sender) + await client.send_video( + chat_id=sender, + video=file, + caption=caption, + supports_streaming=True, + duration=duration, + thumb=thumb_path, + progress=progress_for_pyrogram, + progress_args=( + client, + '**UPLOADING:**\n', + edit, + time.time() + ) + ) + else: + thumb_path=thumbnail(sender) + await client.send_document( + sender, + file, + caption=caption, + thumb=thumb_path, + progress=progress_for_pyrogram, + progress_args=( + client, + '**UPLOADING:**\n', + edit, + time.time() + ) + ) + await edit.delete() + except Exception as e: + await edit.edit(f'ERROR: {str(e)}') + return + else: + chat = msg_link.split("/")[-2] + await client.copy_message(int(sender), chat, msg_id) + await edit.delete() + +@Bot.on_message(filters.private & filters.incoming) +async def clone(bot, event): + try: + link = get_link(event.text) + if not link: + return + except TypeError: + return + edit = await bot.send_message(event.chat.id, 'Trying to process.') + if 't.me/+' in link: + xy = await join(userbot, link) + await edit.edit(xy) + return + if 't.me' in link: + try: + await get_msg(userbot, bot, event.chat.id, link, edit) + except FloodWait: + return await edit.edit('Too many requests, try again later.') + except ValueError: + return await edit.edit('Send Only message link or Private channel invites.') + except Exception as e: + return await edit.edit(f'Error: `{str(e)}`') + diff --git a/main/plugins/pyroplug.py b/main/plugins/pyroplug.py deleted file mode 100644 index 9f6b060..0000000 --- a/main/plugins/pyroplug.py +++ /dev/null @@ -1,134 +0,0 @@ -# Github.com/8769Anurag - -import asyncio, time, os - -from .. import Bot, bot -from main.plugins.progress import progress_for_pyrogram -from main.plugins.helpers import screenshot - -from pyrogram import Client, filters -from pyrogram.errors import ChannelBanned, ChannelInvalid, ChannelPrivate, ChatIdInvalid, ChatInvalid -from ethon.pyfunc import video_metadata -from telethon import events - -def thumbnail(sender): - if os.path.exists(f'{sender}.jpg'): - return f'{sender}.jpg' - else: - return None - -async def check(userbot, client, link): - msg_id = int(link.split("/")[-1]) - if 't.me/c/' in link: - try: - chat = int('-100' + str(link.split("/")[-2])) - await userbot.get_messages(chat, msg_id) - return True, None - except ValueError: - return False, "**Invalid Link!**" - except Exception: - return False, "Have you joined the channel?" - else: - try: - chat = str(link.split("/")[-2]) - await client.get_messages(chat, msg_id) - return True, None - except Exception: - return False, "Maybe bot is banned from the chat, or your link is invalid!" - -async def get_msg(userbot, client, sender, edit_id, msg_link, i): - edit = "" - chat = "" - msg_id = int(msg_link.split("/")[-1]) + int(i) - if 't.me/c/' in msg_link: - chat = int('-100' + str(msg_link.split("/")[-2])) - try: - msg = await userbot.get_messages(chat, msg_id) - if msg.media: - if 'web_page' in msg.media: - edit = await client.edit_message_text(sender, edit_id, "Cloning.") - await client.send_message(sender, msg.text.markdown) - await edit.delete() - return - if not msg.media: - if msg.text: - edit = await client.edit_message_text(sender, edit_id, "Cloning.") - await client.send_message(sender, msg.text.markdown) - await edit.delete() - return - edit = await client.edit_message_text(sender, edit_id, "Trying to Download.") - file = await userbot.download_media( - msg, - progress=progress_for_pyrogram, - progress_args=( - client, - "**DOWNLOADING:**\n", - edit, - time.time() - ) - ) - await edit.edit('Preparing to Upload!') - caption = str(file) - if msg.caption is not None: - caption = msg.caption - if str(file).split(".")[-1] in ['mkv', 'mp4', 'webm']: - if str(file).split(".")[-1] in ['webm', 'mkv']: - path = str(file).split(".")[0] + ".mp4" - os.rename(file, path) - file = str(file).split(".")[0] + ".mp4" - data = video_metadata(file) - duration = data["duration"] - thumb_path = await screenshot(file, duration, sender) - await client.send_video( - chat_id=sender, - video=file, - caption=caption, - supports_streaming=True, - duration=duration, - thumb=thumb_path, - progress=progress_for_pyrogram, - progress_args=( - client, - '**UPLOADING:**\n', - edit, - time.time() - ) - ) - elif str(file).split(".")[-1] in ['jpg', 'jpeg', 'png', 'webp']: - await edit.edit("Uploading photo.") - await bot.send_file(sender, file, caption=caption) - else: - thumb_path=thumbnail(sender) - await client.send_document( - sender, - file, - caption=caption, - thumb=thumb_path, - progress=progress_for_pyrogram, - progress_args=( - client, - '**UPLOADING:**\n', - edit, - time.time() - ) - ) - await edit.delete() - except (ChannelBanned, ChannelInvalid, ChannelPrivate, ChatIdInvalid, ChatInvalid): - await client.edit_message_text(sender, edit_id, "Have you joined the channel?") - return - except Exception as e: - await client.edit_message_text(sender, edit_id, f'Failed to save: `{msg_link}`') - return - else: - edit = await client.edit_message_text(sender, edit_id, "Cloning.") - chat = msg_link.split("/")[-2] - try: - await client.copy_message(int(sender), chat, msg_id) - except Exception as e: - print(e) - return await client.edit_message_text(sender, edit_id, f'Failed to save: `{msg_link}`') - await edit.delete() - -async def get_bulk_msg(userbot, client, sender, msg_link, i): - x = await client.send_message(sender, "Processing!") - await get_msg(userbot, client, sender, x.message_id, msg_link, i) diff --git a/main/plugins/start.py b/main/plugins/start.py index 44727ca..dac7278 100644 --- a/main/plugins/start.py +++ b/main/plugins/start.py @@ -1,14 +1,33 @@ #Github.com/8769Anurag import os -from .. import bot as Drone -from telethon import events, Button +from .. import bot +from telethon import events, Button, TelegramClient -from ethon.mystarts import start_srb - -S = '/' + 's' + 't' + 'a' + 'r' + 't' +from pyrogram import idle +from main.plugins.main import Bot, userbot + +st = "Send me Link of any message to clone it here, For private channel message, send invite link first.\n\n**SUPPORT:** @movies_zilaa\n**DEV:** @sources_cods" -@Drone.on(events.callbackquery.CallbackQuery(data="set")) +@bot.on(events.NewMessage(incoming=True, pattern="/start")) +async def start(event): + await event.reply(f'{st}', + buttons=[ + [Button.inline("SET THUMB.", data="sett"), + Button.inline("REM THUMB.", data="remt")] + ]) + try: + await Bot.start() + await userbot.start() + await idle() + except Exception as e: + if 'Client is already connected' in str(e): + pass + else: + await event.client.send_message(event.chat_id, "Error while starting Client, check if your API and SESSION is right.") + return + +@bot.on(events.callbackquery.CallbackQuery(data="sett")) async def sett(event): Drone = event.client button = await event.get_message() @@ -32,7 +51,7 @@ async def sett(event): os.rename(path, f'./{event.sender_id}.jpg') await t.edit("Temporary thumbnail saved!") -@Drone.on(events.callbackquery.CallbackQuery(data="rem")) +@bot.on(events.callbackquery.CallbackQuery(data="remt")) async def remt(event): Drone = event.client await event.edit('Trying.') @@ -41,9 +60,5 @@ async def remt(event): await event.edit('Removed!') except Exception: await event.edit("No thumbnail saved.") - -@Drone.on(events.NewMessage(incoming=True, pattern=f"{S}")) -async def start(event): - text = "Send me Link of any message to clone it here, For private channel message, send invite link first.\n\n**SUPPORT:** @movies_zilaa" - await start_srb(event, text) + diff --git a/okteto-stack.yaml b/okteto-stack.yaml deleted file mode 100644 index 0ee6624..0000000 --- a/okteto-stack.yaml +++ /dev/null @@ -1,15 +0,0 @@ -services: - drone-srcb: - build: . - environment: - API_ID: $API_ID - API_HASH: $API_HASH - BOT_TOKEN: $BOT_TOKEN - SESSION: $SESSION - AUTH: $AUTH - FORCESUB: $FORCESUB - ports: - - 8080 - resources: - cpu: 1000m - memory: 3Gi diff --git a/requirements.txt b/requirements.txt index 2691b93..4062314 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,6 +1,5 @@ -#Github.com/8769Anurag - -ethon==1.3.6 -cryptg +ethon +python-decouple +pyrogram +telethon tgcrypto -pyrogram==1.4.16