فهرست منبع

Switched to Pytube, Back to sync .sh & 79 line length

TheHamkerCat 4 سال پیش
والد
کامیت
63c50e834b

+ 1 - 0
requirements.txt

@@ -24,3 +24,4 @@ pyromod
 fuzzysearch
 img2pdf
 telegraph
+pytube

+ 6 - 4
wbb/__main__.py

@@ -56,7 +56,9 @@ async def start_bot():
                 hasattr(imported_module, "__HELP__")
                 and imported_module.__HELP__
             ):
-                HELPABLE[imported_module.__MODULE__.replace(' ', '_').lower()] = imported_module
+                HELPABLE[
+                    imported_module.__MODULE__.replace(" ", "_").lower()
+                ] = imported_module
     bot_modules = ""
     j = 1
     for i in ALL_MODULES:
@@ -197,7 +199,7 @@ async def start(_, message):
 async def help_command(_, message):
     if message.chat.type != "private":
         if len(message.command) >= 2:
-            name = (message.text.split(None, 1)[1]).replace(' ', '_').lower()
+            name = (message.text.split(None, 1)[1]).replace(" ", "_").lower()
             if str(name) in HELPABLE:
                 key = InlineKeyboardMarkup(
                     [
@@ -223,7 +225,7 @@ async def help_command(_, message):
             )
     else:
         if len(message.command) >= 2:
-            name = (message.text.split(None, 1)[1]).replace(' ', '_').lower()
+            name = (message.text.split(None, 1)[1]).replace(" ", "_").lower()
             if str(name) in HELPABLE:
                 text = (
                     f"Here is the help for **{HELPABLE[name].__MODULE__}**:\n"
@@ -302,7 +304,7 @@ General command are:
  - /help: Give this message
  """
     if mod_match:
-        module = (mod_match.group(1)).replace(' ', '_')
+        module = (mod_match.group(1)).replace(" ", "_")
         text = (
             "{} **{}**:\n".format(
                 "Here is the help for", HELPABLE[module].__MODULE__

+ 1 - 1
wbb/core/decorators/permissions.py

@@ -68,7 +68,7 @@ def adminsOnly(permission):
             if not message.from_user:
                 # For anonymous admins
                 #### It's a big security risk, Removing for a while
-                #if message.sender_chat:
+                # if message.sender_chat:
                 #    return await authorised(
                 #        func,
                 #        subFunc2,

+ 15 - 10
wbb/modules/admin.py

@@ -609,30 +609,35 @@ async def check_warns(_, message: Message):
 # Report
 
 
-@app.on_message((filters.command("report")
-                 | filters.command(["admins", "admin"], prefixes="@"))
-                & ~filters.edited
-                & ~filters.private)
+@app.on_message(
+    (
+        filters.command("report")
+        | filters.command(["admins", "admin"], prefixes="@")
+    )
+    & ~filters.edited
+    & ~filters.private
+)
 @capture_err
 async def report_user(_, message):
     if not message.reply_to_message:
         return await message.reply_text(
-          "Reply to a message to report that user."
+            "Reply to a message to report that user."
         )
- 
+
     if message.reply_to_message.from_user.id == message.from_user.id:
         return await message.reply_text("Why are you reporting yourself ?")
 
     list_of_admins = await list_admins(message.chat.id)
     if message.reply_to_message.from_user.id in list_of_admins:
         return await message.reply_text(
-          "Do you know that the user you are replying is an admin ?"
+            "Do you know that the user you are replying is an admin ?"
         )
- 
+
     user_mention = message.reply_to_message.from_user.mention
     text = f"Reported {user_mention} to admins!"
-    admin_data = await app.get_chat_members(chat_id=message.chat.id,
-                                            filter="administrators") # will it giv floods ?
+    admin_data = await app.get_chat_members(
+        chat_id=message.chat.id, filter="administrators"
+    )  # will it giv floods ?
     for admin in admin_data:
         if admin.user.is_bot or admin.user.is_deleted:
             # return bots or deleted admins

+ 15 - 14
wbb/modules/locks.py

@@ -117,21 +117,22 @@ async def locks_func(_, message):
 
     elif parameter == "all" and state == "unlock":
         await app.set_chat_permissions(
-         chat_id,
-         ChatPermissions(
-            can_send_messages=True,
-            can_send_media_messages=True,
-            can_send_stickers=True,
-            can_send_animations=True,
-            can_invite_users=True,
-            can_send_games=True,
-            can_use_inline_bots=True,
-            can_send_polls=True,
-            can_add_web_page_previews=True
-                        )
-                                 )
+            chat_id,
+            ChatPermissions(
+                can_send_messages=True,
+                can_send_media_messages=True,
+                can_send_stickers=True,
+                can_send_animations=True,
+                can_invite_users=True,
+                can_send_games=True,
+                can_use_inline_bots=True,
+                can_send_polls=True,
+                can_add_web_page_previews=True,
+            ),
+        )
         await message.reply(f"Unlocked Everything in {message.chat.title}")
-                  
+
+
 @app.on_message(filters.command("locks") & ~filters.private)
 @capture_err
 async def locktypes(_, message):

+ 36 - 42
wbb/modules/music.py

@@ -21,17 +21,16 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 SOFTWARE.
 """
-from __future__ import unicode_literals
 
+import datetime
 import os
 from asyncio import get_running_loop
 from functools import partial
 from io import BytesIO
-from urllib.parse import urlparse
 
-import ffmpeg
-import youtube_dl
 from pyrogram import filters
+from pytube import YouTube
+from requests import get
 
 from wbb import aiohttpsession as session
 from wbb import app, arq
@@ -48,42 +47,34 @@ __HELP__ = """
 is_downloading = False
 
 
-def get_file_extension_from_url(url):
-    url_path = urlparse(url).path
-    basename = os.path.basename(url_path)
-    return basename.split(".")[-1]
+def download_youtube_audio(arq_resp):
+    global is_downloading
+    r = arq_resp.result[0]
 
+    title = r.title
+    performer = r.channel
+
+    m, s = r.duration.split(":")
+    duration = int(
+        datetime.timedelta(minutes=int(m), seconds=int(s)).total_seconds()
+    )
+
+    if duration > 1800:
+        return
+    thumb = get(r.thumbnails[0]).content
+    with open("thumbnail.png", "wb") as f:
+        f.write(thumb)
+    thumbnail_file = "thumbnail.png"
+
+    url = f"https://youtube.com{r.url_suffix}"
+    yt = YouTube(url)
+    audio = yt.streams.filter(only_audio=True).get_audio_only()
+
+    out_file = audio.download()
+    base, ext = os.path.splitext(out_file)
+    audio_file = base + ".mp3"
+    os.rename(out_file, audio_file)
 
-def download_youtube_audio(url: str):
-    global is_downloading
-    with youtube_dl.YoutubeDL(
-        {
-            "format": "bestaudio",
-            "writethumbnail": True,
-            "quiet": True,
-        }
-    ) as ydl:
-        info_dict = ydl.extract_info(url, download=False)
-        if int(float(info_dict["duration"])) > 600:
-            is_downloading = False
-            return []
-        ydl.process_info(info_dict)
-        audio_file = ydl.prepare_filename(info_dict)
-        basename = audio_file.rsplit(".", 1)[-2]
-        if info_dict["ext"] == "webm":
-            audio_file_opus = basename + ".opus"
-            ffmpeg.input(audio_file).output(
-                audio_file_opus, codec="copy", loglevel="error"
-            ).overwrite_output().run()
-            os.remove(audio_file)
-            audio_file = audio_file_opus
-        thumbnail_url = info_dict["thumbnail"]
-        thumbnail_file = (
-            basename + "." + get_file_extension_from_url(thumbnail_url)
-        )
-        title = info_dict["title"]
-        performer = info_dict["uploader"]
-        duration = int(float(info_dict["duration"]))
     return [title, performer, duration, audio_file, thumbnail_file]
 
 
@@ -91,8 +82,9 @@ def download_youtube_audio(url: str):
 @capture_err
 async def music(_, message):
     global is_downloading
-    if len(message.command) != 2:
-        return await message.reply_text("/ytmusic needs a link as argument")
+    if len(message.command) < 2:
+        return await message.reply_text("/ytmusic needs a query as argument")
+
     url = message.text.split(None, 1)[1]
     if is_downloading:
         return await message.reply_text(
@@ -104,11 +96,13 @@ async def music(_, message):
     )
     try:
         loop = get_running_loop()
+        arq_resp = await arq.youtube(url)
         music = await loop.run_in_executor(
-            None, partial(download_youtube_audio, url)
+            None, partial(download_youtube_audio, arq_resp)
         )
+
         if not music:
-            await m.edit("Too Long, Can't Download.")
+            return await message.reply_text("[ERROR]: MUSIC TOO LONG")
         (
             title,
             performer,

+ 3 - 1
wbb/modules/pmpermit.py

@@ -90,7 +90,9 @@ async def pm_approve(_, message):
 )
 async def pm_disapprove(_, message):
     if not message.reply_to_message:
-        return await eor(message, text="Reply to a user's message to disapprove.")
+        return await eor(
+            message, text="Reply to a user's message to disapprove."
+        )
     user_id = message.reply_to_message.from_user.id
     if not await is_pmpermit_approved(user_id):
         await eor(message, text="User is already disapproved to pm")

+ 3 - 1
wbb/modules/sudoers.py

@@ -196,6 +196,7 @@ async def broadcast_message(_, message):
 
 # Update
 
+
 @app.on_message(filters.command("update") & filters.user(SUDOERS))
 async def update_restart(_, message):
     try:
@@ -206,5 +207,6 @@ async def update_restart(_, message):
     except Exception as e:
         return await message.reply_text(str(e))
     m = await message.reply_text(
-        "**Updated with default branch, restarting now.**")
+        "**Updated with default branch, restarting now.**"
+    )
     await restart(m)

+ 3 - 1
wbb/modules/telegraph.py

@@ -20,7 +20,9 @@ async def paste(_, message: Message):
         return await message.reply("**Usage:**\n /telegraph [Page name]")
 
     page_name = message.text.split(None, 1)[1]
-    page = telegraph.create_page(page_name, html_content=(reply.text.html).replace("\n", "<br>"))
+    page = telegraph.create_page(
+        page_name, html_content=(reply.text.html).replace("\n", "<br>")
+    )
     return await message.reply(
         f"**Posted:** {page['url']}",
         disable_web_page_preview=True,

+ 53 - 21
wbb/modules/userbot.py

@@ -10,7 +10,7 @@ import re
 import subprocess
 import sys
 import traceback
-from asyncio import sleep, create_subprocess_shell, subprocess
+from asyncio import sleep
 from html import escape
 from io import StringIO
 from time import time
@@ -171,38 +171,70 @@ async def shellrunner(_, message: Message):
             ReplyKeyboardMarkup,
         ):
             return await eor(message, text="INSECURE!")
-    output = ""
+
     text = message.text.split(None, 1)[1]
     if "\n" in text:
         code = text.split("\n")
-        shell = " ".join(code)
+        output = ""
+        for x in code:
+            shell = re.split(""" (?=(?:[^'"]|'[^']*'|"[^"]*")*$)""", x)
+            try:
+                process = subprocess.Popen(
+                    shell,
+                    stdout=subprocess.PIPE,
+                    stderr=subprocess.PIPE,
+                )
+            except Exception as err:
+                print(err)
+                await eor(
+                    message,
+                    text=f"**INPUT:**\n```{escape(text)}```\n\n**ERROR:**\n```{escape(err)}```",
+                )
+            output += f"**{code}**\n"
+            output += process.stdout.read()[:-1].decode("utf-8")
+            output += "\n"
     else:
-        shell = text
-    process = await create_subprocess_shell(
-              shell,
-              stdout=subprocess.PIPE,
-              stderr=subprocess.PIPE,
-             )
-    out, errorz = await process.communicate()
-    if errorz:            
-        error=f"**INPUT:**\n```{escape(text)}```\n\n**ERROR:**\n```{errorz.decode('utf-8')}```"
-        return await eor(message, text=error)
-    output += out.decode("utf-8")
-    output += "\n"
+        shell = re.split(""" (?=(?:[^'"]|'[^']*'|"[^"]*")*$)""", text)
+        for a, _ in enumerate(shell):
+            shell[a] = shell[a].replace('"', "")
+        try:
+            process = subprocess.Popen(
+                shell,
+                stdout=subprocess.PIPE,
+                stderr=subprocess.PIPE,
+            )
+        except Exception as err:
+            print(err)
+            exc_type, exc_obj, exc_tb = sys.exc_info()
+            errors = traceback.format_exception(
+                etype=exc_type,
+                value=exc_obj,
+                tb=exc_tb,
+            )
+            return await eor(
+                message,
+                text=f"**INPUT:**\n```{escape(text)}```\n\n**ERROR:**\n```{''.join(errors)}```",
+            )
+        output = process.stdout.read()[:-1].decode("utf-8")
     if str(output) == "\n":
         output = None
     if output:
         if len(output) > 4096:
             with open("output.txt", "w+") as file:
                 file.write(output)
-            await message.reply_document("output.txt",caption=f"{escape(text)}")
+            await app2.send_document(
+                message.chat.id,
+                "output.txt",
+                reply_to_message_id=message.message_id,
+                caption=escape(text),
+            )
             return os.remove("output.txt")
         await eor(
-        message,
-        text=f"**INPUT:**\n```{escape(text)}```\n\n**OUTPUT:**\n```{(output)}```",
+            message,
+            text=f"**INPUT:**\n```{escape(text)}```\n\n**OUTPUT:**\n```{escape(output)}```",
         )
     else:
-        return await eor(
-        message,
-        text=f"**INPUT:**\n```{escape(text)}```\n\n**OUTPUT: **\n`No output`",
+        await eor(
+            message,
+            text=f"**INPUT:**\n```{escape(text)}```\n\n**OUTPUT: **\n`No output`",
         )

+ 2 - 4
wbb/utils/inlinefuncs.py

@@ -602,11 +602,9 @@ async def ping_func(answers):
 
 
 async def yt_music_func(answers, url):
-    if "http" not in url:
-        url = (await arq.youtube(url)).result[0]
-        url = f"https://youtube.com{url.url_suffix}"
+    arq_resp = await arq.youtube(url)
     loop = asyncio.get_running_loop()
-    music = await loop.run_in_executor(None, download_youtube_audio, url)
+    music = await loop.run_in_executor(None, download_youtube_audio, arq_resp)
     if not music:
         msg = "**ERROR**\n__MUSIC TOO LONG__"
         answers.append(

+ 2 - 2
wbb/utils/misc.py

@@ -46,7 +46,7 @@ def paginate_modules(page_n, module_dict, prefix, chat=None):
                 EqInlineKeyboardButton(
                     x.__MODULE__,
                     callback_data="{}_module({})".format(
-                        prefix, x.__MODULE__.replace(' ', '_').lower()
+                        prefix, x.__MODULE__.replace(" ", "_").lower()
                     ),
                 )
                 for x in module_dict.values()
@@ -58,7 +58,7 @@ def paginate_modules(page_n, module_dict, prefix, chat=None):
                 EqInlineKeyboardButton(
                     x.__MODULE__,
                     callback_data="{}_module({},{})".format(
-                        prefix, chat, x.__MODULE__.replace(' ', '_').lower()
+                        prefix, chat, x.__MODULE__.replace(" ", "_").lower()
                     ),
                 )
                 for x in module_dict.values()

+ 2 - 1
wbb/utils/stickerset.py

@@ -32,7 +32,8 @@ async def get_sticker_set_by_name(
     try:
         return await client.send(
             raw.functions.messages.GetStickerSet(
-                stickerset=raw.types.InputStickerSetShortName(short_name=name), hash=0,
+                stickerset=raw.types.InputStickerSetShortName(short_name=name),
+                hash=0,
             )
         )
     except errors.exceptions.not_acceptable_406.StickersetInvalid: