diff --git a/assistant/callbackstuffs.py b/assistant/callbackstuffs.py index 0495c8246..15598fee2 100644 --- a/assistant/callbackstuffs.py +++ b/assistant/callbackstuffs.py @@ -20,8 +20,8 @@ from pyUltroid.fns.gDrive import GDriveManager except ImportError: GDriveManager = None -from telegraph import upload_file as upl from telethon import Button, events +from catbox import CatboxUploader from telethon.tl.types import MessageMediaWebPage from telethon.utils import get_peer_id @@ -34,9 +34,9 @@ # --------------------------------------------------------------------# telegraph = telegraph_client() GDrive = GDriveManager() if GDriveManager else None +uploader = CatboxUploader() # --------------------------------------------------------------------# - def text_to_url(event): """function to get media url (with|without) Webpage""" if isinstance(event.media, MessageMediaWebPage): @@ -322,9 +322,9 @@ async def update(eve): await eve.edit(get_string("clst_1")) call_back() await bash("git pull && pip3 install -r requirements.txt") + await bash("pip3 install -r requirements.txt --break-system-packages") execl(sys.executable, sys.executable, "-m", "pyUltroid") - @callback(re.compile("changes(.*)"), owner=True) async def changes(okk): match = okk.data_match.group(1).decode("utf-8") @@ -384,11 +384,14 @@ async def _(e): if "|" in ok: ok, index = ok.split("|") with open(ok, "r") as hmm: - _, key = await get_paste(hmm.read()) - link = f"https://spaceb.in/{key}" - raw = f"https://spaceb.in/api/v1/documents/{key}/raw" - if not _: + _, data = await get_paste(hmm.read()) + if not data.get("link"): return await e.answer(key[:30], alert=True) + if not key.startswith("http"): + link, raw = data["link"], data["raw"] + else: + link = key + raw = f"{key}/raw" if ok.startswith("addons"): key = "Addons" elif ok.startswith("vcbot"): @@ -830,8 +833,7 @@ async def media(event): else: media = await event.client.download_media(response, "alvpc") try: - x = upl(media) - url = f"https://graph.org/{x[0]}" + url = uploader.upload_file(media) remove(media) except BaseException as er: LOGS.exception(er) @@ -969,8 +971,7 @@ async def media(event): url = response.file.id else: try: - x = upl(media) - url = f"https://graph.org/{x[0]}" + url = uploader.upload_file(media) remove(media) except BaseException as er: LOGS.exception(er) @@ -1239,8 +1240,7 @@ async def media(event): url = text_to_url(response) else: try: - x = upl(media) - url = f"https://graph.org/{x[0]}" + url = uploader.upload_file(media) remove(media) except BaseException as er: LOGS.exception(er) diff --git a/assistant/games.py b/assistant/games.py index fef75c0cb..e2b86eacc 100644 --- a/assistant/games.py +++ b/assistant/games.py @@ -14,23 +14,28 @@ """ import asyncio -import re +import re, uuid, operator from random import choice, shuffle -from akipy.async_akipy import Akinator, akipyLOGS +from akipy.async_akipy import Akinator from telethon.errors.rpcerrorlist import BotMethodInvalidError from telethon.events import Raw from telethon.tl.types import InputMediaPoll, Poll, PollAnswer, UpdateMessagePollVote from pyUltroid._misc._decorators import ultroid_cmd +from logging import getLogger +from html import unescape +from telethon.tl.types import TextWithEntities from pyUltroid.fns.helper import inline_mention from pyUltroid.fns.tools import async_searcher +from telethon.errors import ChatSendStickersForbiddenError from . import * # Ensure this import matches your project structure games = {} aki_photo = "https://graph.org/file/3cc8825c029fd0cab9edc.jpg" +akipyLOGS = getLogger("akipy") @ultroid_cmd(pattern="akinator") async def akina(e): @@ -133,11 +138,7 @@ async def eiagx(e): # ----------------------- Main Command ------------------- # -GIMAGES = [ - "https://graph.org/file/1c51015bae5205a65fd69.jpg", - "https://imgwhale.xyz/3xyr322l64j9590", -] - +GIMAGE = "https://graph.org/file/1c51015bae5205a65fd69.jpg" @asst_cmd(pattern="startgame", owner=True) async def magic(event): @@ -147,7 +148,7 @@ async def magic(event): ] await event.reply( get_string("games_1"), - file=choice(GIMAGES), + file=GIMAGE, buttons=buttons, ) @@ -243,10 +244,10 @@ async def choose_cata(event): if TRIVIA_CHATS[chat].get("cancel") is not None: break ansi = str(uuid.uuid1()).split("-")[0].encode() - opts = [PollAnswer(unescape(q["correct_answer"]), ansi)] + opts = [PollAnswer(TextWithEntities(unescape(q["correct_answer"]), entities=[]), ansi)] [ opts.append( - PollAnswer(unescape(a), str(uuid.uuid1()).split("-")[0].encode()) + PollAnswer(TextWithEntities(unescape(a), entities=[]), str(uuid.uuid1()).split("-")[0].encode()) ) for a in q["incorrect_answers"] ] @@ -254,7 +255,10 @@ async def choose_cata(event): poll = InputMediaPoll( Poll( 0, - f"[{copper+1}]. " + unescape(q["question"]), + TextWithEntities( + f"[{copper+1}]. " + unescape(q["question"]), + entities=[] + ), answers=opts, public_voters=True, quiz=True, @@ -298,13 +302,22 @@ async def choose_cata(event): @asst.on( Raw(UpdateMessagePollVote, func=lambda x: TRIVIA_CHATS and POLLS.get(x.poll_id)) ) -async def pollish(eve): +async def pollish(eve: UpdateMessagePollVote): if POLLS.get(eve.poll_id)["chat"] not in TRIVIA_CHATS.keys(): return + if not eve.options: + # Consider as correct answer if no options selected + chat = POLLS.get(eve.poll_id)["chat"] + user = eve.peer.user_id + if not TRIVIA_CHATS.get(chat, {}).get(user): + TRIVIA_CHATS[chat][user] = 1 + else: + TRIVIA_CHATS[chat][user] += 1 + return if POLLS[eve.poll_id]["answer"] != eve.options[0]: return chat = POLLS.get(eve.poll_id)["chat"] - user = eve.user_id + user = eve.peer.user_id if not TRIVIA_CHATS.get(chat, {}).get(user): TRIVIA_CHATS[chat][user] = 1 else: diff --git a/plugins/__init__.py b/plugins/__init__.py index 173db5398..82ef3187a 100644 --- a/plugins/__init__.py +++ b/plugins/__init__.py @@ -25,6 +25,7 @@ from pyUltroid.startup._database import _BaseDatabase as Database from pyUltroid.version import __version__, ultroid_version from strings import get_help, get_string +from catbox import CatboxUploader udB: Database @@ -50,6 +51,9 @@ def inline_pic(): Telegraph = telegraph_client() +cat_uploader = CatboxUploader() + +upload_file = cat_uploader.upload_file List = [] Dict = {} @@ -84,6 +88,7 @@ def inline_pic(): "Mr.Steal-Your-Sticker is stealing this sticker... ", ] + ATRA_COL = [ "DarkCyan", "DeepSkyBlue", diff --git a/plugins/_inline.py b/plugins/_inline.py index 93cc81e4a..211e723ff 100644 --- a/plugins/_inline.py +++ b/plugins/_inline.py @@ -115,8 +115,12 @@ async def inline_handler(event): @in_pattern("pasta", owner=True) async def _(event): ok = event.text.split("-")[1] - link = f"https://spaceb.in/{ok}" - raw = f"https://spaceb.in/api/v1/documents/{ok}/raw" + if not ok.startswith("http"): + link = f"https://spaceb.in/{ok}" + raw = f"https://spaceb.in/api/v1/documents/{ok}/raw" + else: + link = ok + raw = f"{ok}/raw" result = await event.builder.article( title="Paste", text="Pasted to Spacebin 🌌", diff --git a/plugins/afk.py b/plugins/afk.py index 67f5d08ed..74e06eb77 100644 --- a/plugins/afk.py +++ b/plugins/afk.py @@ -12,7 +12,6 @@ import asyncio -from telegraph import upload_file as uf from telethon import events from pyUltroid.dB.afk_db import add_afk, del_afk, is_afk @@ -28,6 +27,7 @@ udB, ultroid_bot, ultroid_cmd, + upload_file ) old_afk_msg = [] @@ -50,8 +50,7 @@ async def set_afk(event): media_type = mediainfo(reply.media) if media_type.startswith(("pic", "gif")): file = await event.client.download_media(reply.media) - iurl = uf(file) - media = f"https://graph.org{iurl[0]}" + media = upload_file(file) else: media = reply.file.id await event.eor("`Done`", time=2) diff --git a/plugins/asstcmd.py b/plugins/asstcmd.py index b84c717bc..02a9945c1 100644 --- a/plugins/asstcmd.py +++ b/plugins/asstcmd.py @@ -13,14 +13,9 @@ from pyUltroid.dB.asstcmd_db import add_cmd, cmd_reply, list_cmds, rem_cmd from pyUltroid.fns.tools import create_tl_btn, format_btn, get_msg_button - -try: - from telegraph import upload_file as uf -except ImportError: - uf = None from telethon import events, utils -from . import asst, get_string, mediainfo, udB, ultroid_cmd +from . import asst, get_string, mediainfo, udB, ultroid_cmd, upload_file @ultroid_cmd(pattern="addcmd( (.*)|$)") @@ -36,16 +31,14 @@ async def ac(e): wut = mediainfo(wt.media) if wut.startswith(("pic", "gif")): dl = await e.client.download_media(wt.media) - variable = uf(dl) + m = upload_file(dl) os.remove(dl) - m = f"https://graph.org{variable[0]}" elif wut == "video": if wt.media.document.size > 8 * 1000 * 1000: return await e.eor(get_string("com_4"), time=5) dl = await e.client.download_media(wt.media) - variable = uf(dl) + m = upload_file(dl) os.remove(dl) - m = f"https://graph.org{variable[0]}" else: m = utils.pack_bot_file_id(wt.media) if wt.text: diff --git a/plugins/audiotools.py b/plugins/audiotools.py index 2ae4e9921..40343bbc8 100644 --- a/plugins/audiotools.py +++ b/plugins/audiotools.py @@ -26,8 +26,7 @@ mediainfo, stdr, time_formatter, - ultroid_cmd, - uploader, + ultroid_cmd ) __doc__ = get_help("help_audiotools") @@ -104,13 +103,15 @@ async def trim_aud(e): await bash(cmd) os.remove(file.name) f_time = time.time() - mmmm = await uploader(out, out, f_time, xxx, f"Uploading {out}...") + n_file, _ = await e.client.fast_uploader( + out, show_progress=True, event=e, message="Uploading...", to_delete=True + ) attributes = await set_attributes(out) caption = get_string("audiotools_7").format(ss, dd) await e.client.send_file( e.chat_id, - mmmm, + n_file, thumb=ULTConfig.thumb, caption=caption, attributes=attributes, @@ -147,13 +148,15 @@ async def ex_aud(e): f_time = time.time() try: - fo = await uploader(out_file, out_file, f_time, msg, f"Uploading {out_file}...") + n_file, _ = await e.client.fast_uploader( + out_file, show_progress=True, event=e, message="Uploading...", to_delete=True + ) except FileNotFoundError: return await eor(msg, get_string("audiotools_9")) await e.reply( get_string("audiotools_10"), - file=fo, + file=n_file, thumb=ULTConfig.thumb, attributes=attributes, ) diff --git a/plugins/bot.py b/plugins/bot.py index e10bd09e9..a4febdc90 100644 --- a/plugins/bot.py +++ b/plugins/bot.py @@ -211,6 +211,7 @@ async def restartbt(ult): if heroku_api: return await restart(ok) await bash("git pull && pip3 install -r requirements.txt") + await bash("pip3 install -r requirements.txt --break-system-packages") if len(sys.argv) > 1: os.execl(sys.executable, sys.executable, "main.py") else: @@ -324,6 +325,7 @@ async def _(e): or "soft" in e.pattern_match.group(1).strip() ): await bash("git pull -f && pip3 install -r requirements.txt") + await bash("pip3 install -r requirements.txt --break-system-packages") call_back() await xx.edit(get_string("upd_7")) os.execl(sys.executable, "python3", "-m", "pyUltroid") diff --git a/plugins/button.py b/plugins/button.py index ef61d2990..ef1fbb2a8 100644 --- a/plugins/button.py +++ b/plugins/button.py @@ -11,7 +11,7 @@ import os -from telegraph import upload_file as uf +from . import upload_file as uf from telethon.utils import pack_bot_file_id from pyUltroid.fns.tools import create_tl_btn, get_msg_button @@ -31,15 +31,13 @@ async def butt(event): wut = mediainfo(wt.media) if wut and wut.startswith(("pic", "gif")): dl = await wt.download_media() - variable = uf(dl) - media = f"https://graph.org{variable[0]}" + media = uf(dl) elif wut == "video": if wt.media.document.size > 8 * 1000 * 1000: return await event.eor(get_string("com_4"), time=5) dl = await wt.download_media() - variable = uf(dl) + media = uf(dl) os.remove(dl) - media = f"https://graph.org{variable[0]}" else: media = pack_bot_file_id(wt.media) try: diff --git a/plugins/compressor.py b/plugins/compressor.py index abd6d157e..a221d8f16 100644 --- a/plugins/compressor.py +++ b/plugins/compressor.py @@ -139,7 +139,9 @@ async def _(e): caption += f"**Compressed Size: **`{humanbytes(c_size)}`\n" caption += f"**Compression Ratio: **`{differ:.2f}%`\n" caption += f"\n**Time Taken To Compress: **`{difff}`" - mmmm = await uploader(out, out, f_time, xxx, f"Uploading {out}...") + n_file, _ = await e.client.fast_uploader( + out, show_progress=True, event=e, message="Uploading...", to_delete=True + ) if to_stream: data = await metadata(out) width = data["width"] @@ -152,7 +154,7 @@ async def _(e): ] await e.client.send_file( e.chat_id, - mmmm, + n_file, thumb=ULTConfig.thumb, caption=caption, attributes=attributes, @@ -162,7 +164,7 @@ async def _(e): else: await e.client.send_file( e.chat_id, - mmmm, + n_file, thumb=ULTConfig.thumb, caption=caption, force_document=True, diff --git a/plugins/converter.py b/plugins/converter.py index b68dd2736..201ff76b9 100644 --- a/plugins/converter.py +++ b/plugins/converter.py @@ -25,7 +25,7 @@ LOGS.info(f"{__file__}: PIL not Installed.") Image = None -from telegraph import upload_file as uf +from . import upload_file as uf from . import ( ULTConfig, @@ -53,9 +53,8 @@ async def _(e): dl = await r.download_media(thumb=-1) else: return await e.eor("`Reply to Photo or media with thumb...`") - variable = uf(dl) + nn = uf(dl) os.remove(dl) - nn = f"https://graph.org{variable[0]}" udB.set_key("CUSTOM_THUMBNAIL", str(nn)) await bash(f"wget {nn} -O resources/extras/ultroid.jpg") await e.eor(get_string("cvt_6").format(nn), link_preview=False) @@ -93,10 +92,12 @@ async def imak(event): if not os.path.exists(inp) or os.path.exists(inp) and not os.path.getsize(inp): os.rename(file, inp) k = time.time() - xxx = await uploader(inp, inp, k, xx, get_string("com_6")) + n_file, _ = await event.client.fast_uploader( + inp, show_progress=True, event=event, message="Uploading...", to_delete=True + ) await event.reply( - f"`{xxx.name}`", - file=xxx, + f"`{n_file.name}`", + file=n_file, force_document=True, thumb=ULTConfig.thumb, ) @@ -135,14 +136,18 @@ async def uconverter(event): except KeyError: return await xx.edit(get_string("sts_3").format("gif/img/sticker/webm")) file = await con.convert(b, outname="ultroid", convert_to=convert) + print(file) + if file: await event.client.send_file( event.chat_id, file, reply_to=event.reply_to_msg_id or event.id ) os.remove(file) + else: + await xx.edit("`Failed to convert`") + return await xx.delete() - @ultroid_cmd( pattern="doc( (.*)|$)", ) @@ -183,9 +188,9 @@ async def _(event): try: await xx.edit(f"```{d}```") except BaseException: - what, key = await get_paste(d) + what, data = await get_paste(d) await xx.edit( - f"**MESSAGE EXCEEDS TELEGRAM LIMITS**\n\nSo Pasted It On [SPACEBIN](https://spaceb.in/{key})" + f"**MESSAGE EXCEEDS TELEGRAM LIMITS**\n\nSo Pasted It On [SPACEBIN]({data['link']})" ) if rem: os.remove(b) diff --git a/plugins/devtools.py b/plugins/devtools.py index fb3f72b4b..40af9a798 100644 --- a/plugins/devtools.py +++ b/plugins/devtools.py @@ -33,10 +33,8 @@ from yaml import safe_load except ImportError: from pyUltroid.fns.tools import safe_load -try: - from telegraph import upload_file as uf -except ImportError: - uf = None + +from . import upload_file as uf from telethon.tl import functions fn = functions @@ -99,7 +97,7 @@ async def _(event): f"Unknown Response from Carbon: `{li}`\n\nstdout`:{stdout}`\nstderr: `{stderr}`" ) return - url = f"https://graph.org{uf(li)[-1]}" + url = uf(li) OUT = f"[\xad]({url}){OUT}" out = "**• OUTPUT:**" remove(li) @@ -121,7 +119,7 @@ async def _(event): f"Unknown Response from Carbon: `{li}`\n\nstdout`:{stdout}`\nstderr: `{stderr}`" ) return - url = f"https://graph.org{uf(li)[-1]}" + url = uf(li) OUT = f"[\xad]({url}){OUT}" out = "**• OUTPUT:**" remove(li) diff --git a/plugins/filter.py b/plugins/filter.py index 95294b01a..b33076913 100644 --- a/plugins/filter.py +++ b/plugins/filter.py @@ -12,14 +12,13 @@ import os import re -from telegraph import upload_file as uf from telethon.tl.types import User from telethon.utils import pack_bot_file_id from pyUltroid.dB.filter_db import add_filter, get_filter, list_filter, rem_filter from pyUltroid.fns.tools import create_tl_btn, format_btn, get_msg_button -from . import events, get_string, mediainfo, udB, ultroid_bot, ultroid_cmd +from . import events, get_string, mediainfo, udB, ultroid_bot, ultroid_cmd, upload_file from ._inline import something @@ -35,15 +34,14 @@ async def af(e): wut = mediainfo(wt.media) if wut.startswith(("pic", "gif")): dl = await wt.download_media() - variable = uf(dl) - m = f"https://graph.org{variable[0]}" + m = upload_file(dl) + os.remove(dl) elif wut == "video": if wt.media.document.size > 8 * 1000 * 1000: return await e.eor(get_string("com_4"), time=5) dl = await wt.download_media() - variable = uf(dl) + m = upload_file(dl) os.remove(dl) - m = f"https://graph.org{variable[0]}" else: m = pack_bot_file_id(wt.media) if wt.text: diff --git a/plugins/greetings.py b/plugins/greetings.py index 7f126e1a5..27053eff3 100644 --- a/plugins/greetings.py +++ b/plugins/greetings.py @@ -32,7 +32,7 @@ """ import os -from telegraph import upload_file as uf +from . import upload_file as uf from telethon.utils import pack_bot_file_id from pyUltroid.dB.greetings_db import ( @@ -67,16 +67,14 @@ async def setwel(event): wut = mediainfo(r.media) if wut.startswith(("pic", "gif")): dl = await r.download_media() - variable = uf(dl) + m = uf(dl) os.remove(dl) - m = f"https://graph.org{variable[0]}" elif wut == "video": if r.media.document.size > 8 * 1000 * 1000: return await eor(x, get_string("com_4"), time=5) dl = await r.download_media() - variable = uf(dl) + m = uf(dl) os.remove(dl) - m = f"https://graph.org{variable[0]}" elif wut == "web": m = None else: @@ -132,16 +130,14 @@ async def setgb(event): wut = mediainfo(r.media) if wut.startswith(("pic", "gif")): dl = await r.download_media() - variable = uf(dl) + m = uf(dl) os.remove(dl) - m = f"https://graph.org{variable[0]}" elif wut == "video": if r.media.document.size > 8 * 1000 * 1000: return await eor(x, get_string("com_4"), time=5) dl = await r.download_media() - variable = uf(dl) + m = uf(dl) os.remove(dl) - m = f"https://graph.org{variable[0]}" elif wut == "web": m = None else: diff --git a/plugins/imagetools.py b/plugins/imagetools.py index a0757bcff..22fd01182 100644 --- a/plugins/imagetools.py +++ b/plugins/imagetools.py @@ -68,7 +68,8 @@ except ImportError: Image = None LOGS.info(f"{__file__}: PIL not Installed.") -from telegraph import upload_file as upf + +from . import upload_file as upf from telethon.errors.rpcerrorlist import ( ChatSendMediaForbiddenError, MessageDeleteForbiddenError, @@ -217,8 +218,7 @@ async def ultd(event): if ultt.endswith(".tgs"): await xx.edit(get_string("sts_9")) file = await con.convert(ultt, convert_to="png", outname="ult") - got = upf(file) - lnk = f"https://graph.org{got[0]}" + lnk = upf(file) r = await async_searcher( f"https://nekobot.xyz/api/imagegen?type=blurpify&image={lnk}", re_json=True ) diff --git a/plugins/mediatools.py b/plugins/mediatools.py index fd0ab43b4..4e8667b8f 100644 --- a/plugins/mediatools.py +++ b/plugins/mediatools.py @@ -27,6 +27,7 @@ bash, downloader, get_string, + upload_file, is_url_ok, mediainfo, ultroid_cmd, @@ -87,7 +88,7 @@ async def mi(e): makehtml = "" if naam.endswith((".jpg", ".png")): if os.path.exists(naam): - med = "https://graph.org" + Telegraph.upload_file(naam)[0]["src"] + med = upload_file(naam) else: med = match makehtml += f"
" diff --git a/plugins/notes.py b/plugins/notes.py index 5553782f7..4bceefeb6 100644 --- a/plugins/notes.py +++ b/plugins/notes.py @@ -22,7 +22,7 @@ """ import os -from telegraph import upload_file as uf +from . import upload_file as uf from telethon.utils import pack_bot_file_id from pyUltroid.dB.notes_db import add_note, get_notes, list_note, rem_note @@ -46,16 +46,14 @@ async def an(e): wut = mediainfo(wt.media) if wut.startswith(("pic", "gif")): dl = await wt.download_media() - variable = uf(dl) + m = uf(dl) os.remove(dl) - m = f"https://graph.org{variable[0]}" elif wut == "video": if wt.media.document.size > 8 * 1000 * 1000: return await e.eor(get_string("com_4"), time=5) dl = await wt.download_media() - variable = uf(dl) + m = uf(dl) os.remove(dl) - m = f"https://graph.org{variable[0]}" else: m = pack_bot_file_id(wt.media) if wt.text: diff --git a/plugins/polls.py b/plugins/polls.py index 2fb71e5dc..95423a684 100644 --- a/plugins/polls.py +++ b/plugins/polls.py @@ -18,7 +18,7 @@ Get the quiz poll where answerno is the number of option which is correct """ -from telethon.tl.types import InputMediaPoll, Poll, PollAnswer +from telethon.tl.types import InputMediaPoll, Poll, PollAnswer, TextWithEntities from . import get_string, ultroid_cmd @@ -57,10 +57,10 @@ async def uri_poll(e): if len(option) <= 1: return await e.eor("`Options Should be More than 1..`", time=5) m = await e.eor(get_string("com_1")) - OUT = [PollAnswer(option[on], str(on).encode()) for on in range(len(option))] + OUT = [PollAnswer(TextWithEntities(option[on], entities=[]), str(on).encode()) for on in range(len(option))] await e.respond( file=InputMediaPoll( - Poll(20, ques, OUT, multiple_choice=mpp, public_voters=publ, quiz=quizo), + Poll(20, TextWithEntities(ques, entities=[]), OUT, multiple_choice=mpp, public_voters=publ, quiz=quizo), correct_answers=karzo, ), ) diff --git a/plugins/search.py b/plugins/search.py index b80e34f04..020e08c02 100644 --- a/plugins/search.py +++ b/plugins/search.py @@ -152,8 +152,10 @@ async def reverse(event): "User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:58.0) Gecko/20100101 Firefox/58.0", }, ) + with open("response.html", "w") as f: + f.write(response) xx = bs(response, "html.parser") - div = xx.find_all("div", {"class": "r5a77d"})[0] + div = xx.find_all("div", {"class": "kb0PBd"})[0] alls = div.find("a") link = alls["href"] text = alls.text diff --git a/plugins/snips.py b/plugins/snips.py index 6b11f27ec..a7c7aae1f 100644 --- a/plugins/snips.py +++ b/plugins/snips.py @@ -21,7 +21,7 @@ """ import os -from telegraph import upload_file as uf +from . import upload_file as uf from telethon.utils import pack_bot_file_id from pyUltroid._misc import sudoers @@ -45,16 +45,14 @@ async def an(e): wut = mediainfo(wt.media) if wut.startswith(("pic", "gif")): dl = await wt.download_media() - variable = uf(dl) + m = uf(dl) os.remove(dl) - m = f"https://graph.org{variable[0]}" elif wut == "video": if wt.media.document.size > 8 * 1000 * 1000: return await e.eor(get_string("com_4"), time=5) dl = await wt.download_media() - variable = uf(dl) + m = uf(dl) os.remove(dl) - m = f"https://graph.org{variable[0]}" else: m = pack_bot_file_id(wt.media) if wt.text: diff --git a/plugins/specialtools.py b/plugins/specialtools.py index 6971c58ff..52a448be7 100644 --- a/plugins/specialtools.py +++ b/plugins/specialtools.py @@ -36,10 +36,11 @@ from datetime import datetime as dt from random import choice -import pytz +import pytz, asyncio from bs4 import BeautifulSoup as bs from telethon.tl.types import DocumentAttributeVideo - +from requests import Session +from cloudscraper import create_scraper from pyUltroid.fns.tools import get_google_images, metadata from . import ( @@ -59,7 +60,7 @@ from .beautify import all_col File = [] - +scraper = create_scraper() @ultroid_cmd( pattern="getaudio$", @@ -250,6 +251,7 @@ async def hbd(event): reply_to=event.reply_to_msg_id, ) +session = Session() @ultroid_cmd(pattern="sticker( (.*)|$)") async def _(event): @@ -257,23 +259,61 @@ async def _(event): if not x: return await event.eor("`Give something to search`") uu = await event.eor(get_string("com_1")) - z = bs( - await async_searcher(f"https://combot.org/telegram/stickers?q={x}"), - "html.parser", - ) - - packs = z.find_all("div", "sticker-pack__header") - sticks = { - c.a["href"]: c.find("div", {"class": "sticker-pack__title"}).text for c in packs + + headers = { + 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36' } - - if not sticks: - return await uu.edit(get_string("spcltool_9")) - a = "SᴛɪᴄᴋEʀs Aᴠᴀɪʟᴀʙʟᴇ ~\n\n" - for _, value in sticks.items(): - a += f"{value}\n" - await uu.edit(a, parse_mode="html") - + + max_retries = 3 + retry_count = 0 + + while retry_count < max_retries: + try: + response = scraper.get( + f"https://combot.org/telegram/stickers?q={x}", + headers=headers + ).content + + # Check if response contains Cloudflare challenge + if "Just a moment..." in response.decode(): + retry_count += 1 + await asyncio.sleep(2) # Wait before retry + continue + + z = bs(response, "html.parser") + packs = z.find_all("a", {"class": "stickerset__title"}) + + if not packs: + return await uu.edit(get_string("spcltool_9")) + + break # Success - exit loop + + except Exception as er: + retry_count += 1 + await asyncio.sleep(2) + continue + + if retry_count >= max_retries: + return await uu.edit("`Failed to fetch stickers after multiple retries`") + try: + sticks = {} + for pack in packs: + href = pack.get("href") + title = pack.text.strip() + if href: + href = f"https://t.me/addstickers/{href.split('/')[-1]}" + sticks[href] = title + + if not sticks: + return await uu.edit(get_string("spcltool_9")) + + a = "SᴛɪᴄᴋEʀs Aᴠᴀɪʟᴀʙʟᴇ ~\n\n" + for href, title in sticks.items(): + a += f"{title}\n" + await uu.edit(a, parse_mode="html") + + except Exception as e: + await uu.edit(f"`Error: {str(e)}`\nTry again later.") @ultroid_cmd(pattern="wall( (.*)|$)") async def wall(event): diff --git a/plugins/twitter.py b/plugins/twitter.py index 81dbe534a..06613cee2 100644 --- a/plugins/twitter.py +++ b/plugins/twitter.py @@ -81,8 +81,10 @@ async def twitter_details(event): msg = await event.eor("🔍 `Getting tweet details...`") try: client = await get_client() - if "twitter.com" in match or "x.com" in match: - tweet_id = match.split("/")[-1].split("?")[0] + from urllib.parse import urlparse + parsed_url = urlparse(match) + if parsed_url.hostname in ["twitter.com", "x.com"]: + tweet_id = parsed_url.path.split("/")[-1].split("?")[0] else: tweet_id = match diff --git a/plugins/utilities.py b/plugins/utilities.py index 11d826890..f8b62f643 100644 --- a/plugins/utilities.py +++ b/plugins/utilities.py @@ -67,10 +67,7 @@ from pyUltroid.dB.gban_mute_db import is_gbanned from pyUltroid.fns.tools import get_chat_and_msgid -try: - from telegraph import upload_file as uf -except ImportError: - uf = None +from . import upload_file as uf from telethon.errors.rpcerrorlist import ChatForwardsRestrictedError, UserBotError from telethon.errors import MessageTooLongError @@ -266,18 +263,16 @@ async def _(event): return await xx.eor( "`Reply to a Message/Document or Give me Some Text !`", time=5 ) - done, key = await get_paste(message) - if not done: - return await xx.eor(key) - link = f"https://spaceb.in/{key}" - raw = f"https://spaceb.in/api/v1/documents/{key}/raw" + done, data = await get_paste(message) + if not done and data.get("error"): + return await xx.eor(data["error"]) reply_text = ( - f"• **Pasted to SpaceBin :** [Space]({link})\n• **Raw Url :** : [Raw]({raw})" + f"• **Pasted to SpaceBin :** [Space]({data['link']})\n• **Raw Url :** : [Raw]({data['raw']})" ) try: if event.client._bot: return await xx.eor(reply_text) - ok = await event.client.inline_query(asst.me.username, f"pasta-{key}") + ok = await event.client.inline_query(asst.me.username, f"pasta-{data['link']}") await ok[0].click(event.chat_id, reply_to=event.reply_to_msg_id, hide_via=True) await xx.delete() except BaseException as e: @@ -506,7 +501,7 @@ async def telegraphcmd(event): getit = file if "document" not in dar: try: - nn = f"https://graph.org{uf(getit)[0]}" + nn = uf(getit) amsg = f"Uploaded to [Telegraph]({nn}) !" except Exception as e: amsg = f"Error : {e}" diff --git a/plugins/writer.py b/plugins/writer.py index 4e9f812ff..9b9ea3d4e 100644 --- a/plugins/writer.py +++ b/plugins/writer.py @@ -74,7 +74,8 @@ async def writer(e): font = ImageFont.truetype("resources/fonts/assfont.ttf", 30) x, y = 150, 140 lines = text_set(text) - line_height = font.getsize("hg")[1] + bbox = font.getbbox("hg") + line_height = bbox[3] - bbox[1] for line in lines: draw.text((x, y), line, fill=(1, 22, 55), font=font) y = y + line_height - 5 diff --git a/plugins/ziptools.py b/plugins/ziptools.py index c7006dad7..ab2674c19 100644 --- a/plugins/ziptools.py +++ b/plugins/ziptools.py @@ -63,13 +63,15 @@ async def zipp(event): else: await bash(f"zip -r {inp} {file}") k = time.time() - xxx = await uploader(inp, inp, k, xx, get_string("com_6")) + n_file, _ = await event.client.fast_uploader( + inp, show_progress=True, event=event, message="Uploading...", to_delete=True + ) await event.client.send_file( event.chat_id, - xxx, + n_file, force_document=True, thumb=ULTConfig.thumb, - caption=f"`{xxx.name}`", + caption=f"`{n_file.name}`", reply_to=reply, ) os.remove(inp) @@ -104,13 +106,15 @@ async def unzipp(event): ok = get_all_files("unzip") for x in ok: k = time.time() - xxx = await uploader(x, x, k, xx, get_string("com_6")) + n_file, _ = await event.client.fast_uploader( + x, show_progress=True, event=event, message="Uploading...", to_delete=True + ) await event.client.send_file( event.chat_id, - xxx, + n_file, force_document=True, thumb=ULTConfig.thumb, - caption=f"`{xxx.name}`", + caption=f"`{n_file.name}`", ) await xx.delete() diff --git a/pyUltroid/fns/misc.py b/pyUltroid/fns/misc.py index 69ce9e94a..85369b1b6 100644 --- a/pyUltroid/fns/misc.py +++ b/pyUltroid/fns/misc.py @@ -13,6 +13,7 @@ from logging import WARNING from random import choice, randrange, shuffle from traceback import format_exc +from catbox import CatboxUploader from pyUltroid.exceptions import DependencyMissingError @@ -59,6 +60,7 @@ except ImportError: BeautifulSoup = None +uploader = CatboxUploader() async def randomchannel( tochat, channel, range1, range2, caption=None, client=ultroid_bot @@ -295,15 +297,7 @@ async def _format_quote(self, event, reply=None, sender=None, type_="private"): async def telegraph(file_): file = file_ + ".png" Image.open(file_).save(file, "PNG") - files = {"file": open(file, "rb").read()} - uri = ( - "https://graph.org" - + ( - await async_searcher( - "https://graph.org/upload", post=True, data=files, re_json=True - ) - )[0]["src"] - ) + uri = uploader.upload_file(file) os.remove(file) os.remove(file_) return uri diff --git a/pyUltroid/fns/tools.py b/pyUltroid/fns/tools.py index 6785fae64..3c23f2186 100644 --- a/pyUltroid/fns/tools.py +++ b/pyUltroid/fns/tools.py @@ -9,9 +9,9 @@ import math import os import random -import re +import re, subprocess import secrets -import ssl +import ssl, html from io import BytesIO from json.decoder import JSONDecodeError from traceback import format_exc @@ -118,8 +118,12 @@ async def metadata(file): raise DependencyMissingError( f"'{_}' is not installed!\nInstall it to use this command." ) + data = {} - _info = json.loads(out)["media"]["track"] + _info = json.loads(out)["media"] + if not _info: + return {} + _info = _info["track"] info = _info[0] if info.get("Format") in ["GIF", "PNG"]: return { @@ -385,95 +389,109 @@ def make_logo(imgpath, text, funt, **args): async def get_paste(data: str, extension: str = "txt"): - ssl_context = ssl.create_default_context(cafile=certifi.where()) - json = {"content": data, "extension": extension} - key = await async_searcher( - url="https://spaceb.in/api/v1/documents/", - json=json, - ssl=ssl_context, - post=True, - re_json=True, - ) try: - return True, key["payload"]["id"] - except KeyError: - if "the length must be between 2 and 400000." in key["error"]: - return await get_paste(data[-400000:], extension=extension) - return False, key["error"] - except Exception as e: - LOGS.info(e) - return None, str(e) - + url = "https://spaceb.in/api/" + res = await async_searcher(url, json={"content": data, "extension": extension}, post=True, re_json=True) + return True, { + "link": f"https://spaceb.in/{res['payload']['id']}", + "raw": f"https://spaceb.in/{res['payload']['id']}/raw" + } + except Exception: + try: + url = "https://dpaste.org/api/" + data = { + 'format': 'json', + 'content': data.encode('utf-8'), + 'lexer': extension, + 'expires': '604800', # expire in week + } + res = await async_searcher(url, data=data, post=True, re_json=True) + return True, { + "link": res["url"], + "raw": f'{res["url"]}/raw' + } + except Exception as e: + LOGS.info(e) + return None, { + "link": None, + "raw": None, + "error": str(e) + } -# -------------------------------------- # https://stackoverflow.com/a/74563494 async def get_google_images(query): - soup = BeautifulSoup( - await async_searcher( - "https://google.com/search", - params={"q": query, "tbm": "isch"}, - headers={"User-Agent": random.choice(some_random_headers)}, - ), - "lxml", - ) - google_images = [] - all_script_tags = soup.select("script") - matched_images_data = "".join( - re.findall(r"AF_initDataCallback\(([^<]+)\);", str(all_script_tags)) - ) - matched_images_data_fix = json.dumps(matched_images_data) - matched_images_data_json = json.loads(matched_images_data_fix) - matched_google_image_data = re.findall( - r"\"b-GRID_STATE0\"(.*)sideChannel:\s?{}}", matched_images_data_json - ) - matched_google_images_thumbnails = ", ".join( - re.findall( - r"\[\"(https\:\/\/encrypted-tbn0\.gstatic\.com\/images\?.*?)\",\d+,\d+\]", - str(matched_google_image_data), - ) - ).split(", ") - thumbnails = [ - bytes(bytes(thumbnail, "ascii").decode("unicode-escape"), "ascii").decode( - "unicode-escape" - ) - for thumbnail in matched_google_images_thumbnails - ] - removed_matched_google_images_thumbnails = re.sub( - r"\[\"(https\:\/\/encrypted-tbn0\.gstatic\.com\/images\?.*?)\",\d+,\d+\]", - "", - str(matched_google_image_data), - ) - matched_google_full_resolution_images = re.findall( - r"(?:'|,),\[\"(https:|http.*?)\",\d+,\d+\]", - removed_matched_google_images_thumbnails, - ) - full_res_images = [ - bytes(bytes(img, "ascii").decode("unicode-escape"), "ascii").decode( - "unicode-escape" - ) - for img in matched_google_full_resolution_images + """Get image results from Google Custom Search API. + + Args: + query (str): Search query string + + Returns: + list: List of dicts containing image info (title, link, source, thumbnail, original) + """ + LOGS.info(f"Searching Google Images for: {query}") + + # Google Custom Search API credentials + google_keys = [ + { + "key": "AIzaSyAj75v6vHWLJdJaYcj44tLz7bdsrh2g7Y0", + "cx": "712a54749d99a449e" + }, + { + "key": "AIzaSyDFQQwPLCzcJ9FDao-B7zDusBxk8GoZ0HY", + "cx": "001bbd139705f44a6" + }, + { + "key": "AIzaSyD0sRNZUa8-0kq9LAREDAFKLNO1HPmikRU", + "cx": "4717c609c54e24250" + } ] - for index, (metadata, thumbnail, original) in enumerate( - zip(soup.select(".isv-r.PNCib.MSM1fd.BUooTd"), thumbnails, full_res_images), - start=1, - ): - google_images.append( - { - "title": metadata.select_one(".VFACy.kGQAp.sMi44c.lNHeqe.WGvvNb")[ - "title" - ], - "link": metadata.select_one(".VFACy.kGQAp.sMi44c.lNHeqe.WGvvNb")[ - "href" - ], - "source": metadata.select_one(".fxgdke").text, - "thumbnail": thumbnail, - "original": original, - } + key_index = random.randint(0, len(google_keys) - 1) + GOOGLE_API_KEY = google_keys[key_index]["key"] + GOOGLE_CX = google_keys[key_index]["cx"] + try: + # Construct API URL + url = ( + "https://www.googleapis.com/customsearch/v1" + f"?q={quote(query)}" + f"&cx={GOOGLE_CX}" + f"&key={GOOGLE_API_KEY}" + "&searchType=image" + "&num=10" # Number of results ) - random.shuffle(google_images) - return google_images + + # Make API request + response = await async_searcher(url, re_json=True) + print("response") + if not response or "items" not in response: + LOGS.error("No results from Google Custom Search API") + return [] + + # Process results + google_images = [] + for item in response["items"]: + try: + google_images.append({ + "title": item.get("title", ""), + "link": item.get("contextLink", ""), # Page containing image + "source": item.get("displayLink", ""), + "thumbnail": item.get("image", {}).get("thumbnailLink", item["link"]), + "original": item["link"] # Original image URL + }) + except Exception as e: + LOGS.warning(f"Failed to process image result: {str(e)}") + continue + + # Randomize results order + random.shuffle(google_images) + + LOGS.info(f"Found {len(google_images)} images for query: {query}") + return google_images + + except Exception as e: + LOGS.exception(f"Error in get_google_images: {str(e)}") + return [] # Thanks https://t.me/ImSafone for ChatBotApi @@ -672,7 +690,7 @@ async def get_file_link(msg): async def get_stored_file(event, hash): - from .. import udB + from .. import udB, asst msg_id = get_stored_msg(hash) if not msg_id: @@ -689,37 +707,22 @@ async def get_stored_file(event, hash): await asst.send_message(event.chat_id, msg.text, file=msg.media, reply_to=event.id) -def _package_rpc(text, lang_src="auto", lang_tgt="auto"): - GOOGLE_TTS_RPC = ["MkEWBc"] - parameter = [[text.strip(), lang_src, lang_tgt, True], [1]] - escaped_parameter = json.dumps(parameter, separators=(",", ":")) - rpc = [[[random.choice(GOOGLE_TTS_RPC), escaped_parameter, None, "generic"]]] - espaced_rpc = json.dumps(rpc, separators=(",", ":")) - freq = "f.req={}&".format(quote(espaced_rpc)) - return freq - +def translate(text, lang_tgt="en", lang_src="auto", timeout=60, detect=False): + pattern = r'(?s)class="(?:t0|result-container)">(.*?)<' + escaped_text = quote(text.encode("utf8")) + url = "https://translate.google.com/m?tl=%s&sl=%s&q=%s" % ( + lang_tgt, + lang_src, + escaped_text, + ) + response = requests.get(url, timeout=timeout).content + result = response.decode("utf8") + result = re.findall(pattern, result) + if not result: + return "" + text = html.unescape(result[0]) + return (text, None) if detect else text -def translate(*args, **kwargs): - headers = { - "Referer": "https://translate.google.co.in", - "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) " - "AppleWebKit/537.36 (KHTML, like Gecko) " - "Chrome/47.0.2526.106 Safari/537.36", - "Content-Type": "application/x-www-form-urlencoded;charset=utf-8", - } - x = requests.post( - "https://translate.google.co.in/_/TranslateWebserverUi/data/batchexecute", - headers=headers, - data=_package_rpc(*args, **kwargs), - ).text - response = "" - data = json.loads(json.loads(x[4:])[0][2])[1][0][0] - subind = data[-2] - if not subind: - subind = data[-1] - for i in subind: - response += i[0] - return response def cmd_regex_replace(cmd): @@ -751,50 +754,83 @@ class TgConverter: @staticmethod async def animated_sticker(file, out_path="sticker.tgs", throw=False, remove=False): """Convert to/from animated sticker.""" - if out_path.endswith("webp"): - er, out = await bash( - f"lottie_convert.py --webp-quality 100 --webp-skip-frames 100 '{file}' '{out_path}'" - ) - else: - er, out = await bash(f"lottie_convert.py '{file}' '{out_path}'") - if er and throw: - raise LottieException(er) - if remove: - os.remove(file) - if os.path.exists(out_path): - return out_path + LOGS.info(f"Converting animated sticker: {file} -> {out_path}") + try: + if out_path.endswith("webp"): + er, out = await bash( + f"lottie_convert.py --webp-quality 100 --webp-skip-frames 100 '{file}' '{out_path}'" + ) + else: + er, out = await bash(f"lottie_convert.py '{file}' '{out_path}'") + + if er: + LOGS.error(f"Error in animated_sticker conversion: {er}") + if throw: + raise LottieException(er) + if remove and os.path.exists(file): + os.remove(file) + LOGS.info(f"Removed original file: {file}") + if os.path.exists(out_path): + LOGS.info(f"Successfully converted to {out_path}") + return out_path + LOGS.error(f"Output file not created: {out_path}") + return None + except Exception as e: + LOGS.exception(f"Unexpected error in animated_sticker: {str(e)}") + if throw: + raise @staticmethod async def animated_to_gif(file, out_path="gif.gif"): """Convert animated sticker to gif.""" - await bash( - f"lottie_convert.py '{_unquote_text(file)}' '{_unquote_text(out_path)}'" - ) - return out_path + LOGS.info(f"Converting to gif: {file} -> {out_path}") + try: + er, out = await bash( + f"lottie_convert.py '{_unquote_text(file)}' '{_unquote_text(out_path)}'" + ) + if er: + LOGS.error(f"Error in animated_to_gif conversion: {er}") + if os.path.exists(out_path): + LOGS.info("Successfully converted to gif") + return out_path + LOGS.error("Gif conversion failed - output file not created") + return None + except Exception as e: + LOGS.exception(f"Unexpected error in animated_to_gif: {str(e)}") + return None @staticmethod def resize_photo_sticker(photo): """Resize the given photo to 512x512 (for creating telegram sticker).""" - image = Image.open(photo) - if (image.width and image.height) < 512: - size1 = image.width - size2 = image.height - if image.width > image.height: - scale = 512 / size1 - size1new = 512 - size2new = size2 * scale + LOGS.info(f"Resizing photo for sticker: {photo}") + try: + image = Image.open(photo) + original_size = (image.width, image.height) + + if (image.width and image.height) < 512: + size1 = image.width + size2 = image.height + if image.width > image.height: + scale = 512 / size1 + size1new = 512 + size2new = size2 * scale + else: + scale = 512 / size2 + size1new = size1 * scale + size2new = 512 + size1new = math.floor(size1new) + size2new = math.floor(size2new) + sizenew = (size1new, size2new) + image = image.resize(sizenew) else: - scale = 512 / size2 - size1new = size1 * scale - size2new = 512 - size1new = math.floor(size1new) - size2new = math.floor(size2new) - sizenew = (size1new, size2new) - image = image.resize(sizenew) - else: - maxsize = (512, 512) - image.thumbnail(maxsize) - return image + maxsize = (512, 512) + image.thumbnail(maxsize) + + LOGS.info(f"Resized image from {original_size} to {image.size}") + return image + except Exception as e: + LOGS.exception(f"Error in resize_photo_sticker: {str(e)}") + raise @staticmethod async def ffmpeg_convert(input_, output, remove=False): @@ -803,9 +839,11 @@ async def ffmpeg_convert(input_, output, remove=False): input_, name=output[:-5], remove=remove ) if output.endswith(".gif"): - await bash(f"ffmpeg -i '{input_}' -an -sn -c:v copy '{output}.mp4' -y") + out, er = await bash(f"ffmpeg -i '{input_}' -an -sn -c:v copy '{output}.mp4' -y") + LOGS.info(f"FFmpeg output: {out}, Error: {er}") else: - await bash(f"ffmpeg -i '{input_}' '{output}' -y") + out, er = await bash(f"ffmpeg -i '{input_}' '{output}' -y") + LOGS.info(f"FFmpeg output: {out}, Error: {er}") if remove: os.remove(input_) if os.path.exists(output): @@ -813,35 +851,80 @@ async def ffmpeg_convert(input_, output, remove=False): @staticmethod async def create_webm(file, name="video", remove=False): - _ = await metadata(file) - name += ".webm" - h, w = _["height"], _["width"] - if h == w and h != 512: - h, w = 512, 512 - if h != 512 or w != 512: - if h > w: - h, w = 512, -1 - if w > h: - h, w = -1, 512 - await bash( - f'ffmpeg -i "{file}" -preset fast -an -to 00:00:03 -crf 30 -bufsize 256k -b:v {_["bitrate"]} -vf "scale={w}:{h},fps=30" -c:v libvpx-vp9 "{name}" -y' - ) - if remove: - os.remove(file) - return name + LOGS.info(f"Creating webm: {file} -> {name}.webm") + try: + _ = await metadata(file) + name += ".webm" + h, w = _["height"], _["width"] + + if h == w and h != 512: + h, w = 512, 512 + if h != 512 or w != 512: + if h > w: + h, w = 512, -1 + if w > h: + h, w = -1, 512 + + await bash( + f'ffmpeg -i "{file}" -preset fast -an -to 00:00:03 -crf 30 -bufsize 256k -b:v {_["bitrate"]} -vf "scale={w}:{h},fps=30" -c:v libvpx-vp9 "{name}" -y' + ) + + if remove and os.path.exists(file): + os.remove(file) + LOGS.info(f"Removed original file: {file}") + + if os.path.exists(name): + LOGS.info(f"Successfully created webm: {name}") + return name + + LOGS.error(f"Webm creation failed - output file not created: {name}") + return None + except Exception as e: + LOGS.exception(f"Error in create_webm: {str(e)}") + return None @staticmethod def to_image(input_, name, remove=False): + """Convert video/gif to image using first frame.""" + LOGS.info(f"Converting to image: {input_} -> {name}") try: - import cv2 - except ImportError: - raise DependencyMissingError("This function needs 'cv2' to be installed.") - img = cv2.VideoCapture(input_) - ult, roid = img.read() - cv2.imwrite(name, roid) - if remove: - os.remove(input_) - return name + if not input_: + LOGS.error("Input file is None") + return None + + if not os.path.exists(input_): + LOGS.error(f"Input file does not exist: {input_}") + return None + + try: + import cv2 + except ImportError: + raise DependencyMissingError("This function needs 'cv2' to be installed.") + + img = cv2.VideoCapture(input_) + success, frame = img.read() + + if not success: + LOGS.error(f"Failed to read frame from {input_}") + return None + + cv2.imwrite(name, frame) + img.release() + + if not os.path.exists(name): + LOGS.error(f"Failed to save image: {name}") + return None + + if remove and os.path.exists(input_): + os.remove(input_) + LOGS.info(f"Removed original file: {input_}") + + LOGS.info(f"Successfully converted to image: {name}") + return name + + except Exception as e: + LOGS.exception(f"Error in to_image conversion: {str(e)}") + return None @staticmethod async def convert( @@ -851,9 +934,21 @@ async def convert( allowed_formats=[], remove_old=True, ): + """Convert between different file formats.""" + LOGS.info(f"Converting {input_file} to {convert_to or allowed_formats}") + + if not input_file: + LOGS.error("Input file is None") + return None + + if not os.path.exists(input_file): + LOGS.error(f"Input file does not exist: {input_file}") + return None + if "." in input_file: ext = input_file.split(".")[-1].lower() else: + LOGS.error("Input file has no extension") return input_file if ( @@ -866,60 +961,90 @@ async def convert( def recycle_type(exte): return convert_to == exte or exte in allowed_formats - # Sticker to Something - if ext == "tgs": - for extn in ["webp", "json", "png", "mp4", "gif"]: - if recycle_type(extn): - name = outname + "." + extn - return await TgConverter.animated_sticker( - input_file, name, remove=remove_old + try: + # Sticker to Something + if ext == "tgs": + for extn in ["webp", "json", "png", "mp4", "gif"]: + if recycle_type(extn): + name = outname + "." + extn + result = await TgConverter.animated_sticker( + input_file, name, remove=remove_old + ) + if result: + return result + if recycle_type("webm"): + gif_file = await TgConverter.convert( + input_file, convert_to="gif", remove_old=remove_old ) - if recycle_type("webm"): - input_file = await TgConverter.convert( - input_file, convert_to="gif", remove_old=remove_old - ) - return await TgConverter.create_webm(input_file, outname, remove=True) - # Json -> Tgs - elif ext == "json": - if recycle_type("tgs"): - name = outname + ".tgs" - return await TgConverter.animated_sticker( - input_file, name, remove=remove_old - ) - # Video to Something - elif ext in ["webm", "mp4", "gif"]: - for exte in ["webm", "mp4", "gif"]: - if recycle_type(exte): - name = outname + "." + exte - return await TgConverter.ffmpeg_convert( + if gif_file: + return await TgConverter.create_webm(gif_file, outname, remove=True) + + # Json -> Tgs + elif ext == "json": + if recycle_type("tgs"): + name = outname + ".tgs" + return await TgConverter.animated_sticker( input_file, name, remove=remove_old ) - for exte in ["png", "jpg", "jpeg", "webp"]: - if recycle_type(exte): - name = outname + "." + exte - return TgConverter.to_image(input_file, name, remove=remove_old) - # Image to Something - elif ext in ["jpg", "jpeg", "png", "webp"]: - for extn in ["png", "webp", "ico"]: - if recycle_type(extn): - img = Image.open(input_file) - name = outname + "." + extn - img.save(name, extn.upper()) - if remove_old: - os.remove(input_file) - return name - for extn in ["webm", "gif", "mp4"]: - if recycle_type(extn): - name = outname + "." + extn - if extn == "webm": - input_file = await TgConverter.convert( - input_file, - convert_to="png", - remove_old=remove_old, + + # Video to Something + elif ext in ["webm", "mp4", "gif"]: + for exte in ["webm", "mp4", "gif"]: + if recycle_type(exte): + name = outname + "." + exte + result = await TgConverter.ffmpeg_convert( + input_file, name, remove=remove_old ) - return await TgConverter.ffmpeg_convert( - input_file, name, remove=True if extn == "webm" else remove_old - ) + if result: + return result + + for exte in ["png", "jpg", "jpeg", "webp"]: + if recycle_type(exte): + name = outname + "." + exte + result = TgConverter.to_image(input_file, name, remove=remove_old) + if result: + return result + + # Image to Something + elif ext in ["jpg", "jpeg", "png", "webp"]: + for extn in ["png", "webp", "ico"]: + if recycle_type(extn): + try: + img = Image.open(input_file) + name = outname + "." + extn + img.save(name, extn.upper()) + if remove_old and os.path.exists(input_file): + os.remove(input_file) + LOGS.info(f"Removed original file: {input_file}") + return name + except Exception as e: + LOGS.error(f"Failed to convert image to {extn}: {str(e)}") + continue + + for extn in ["webm", "gif", "mp4"]: + if recycle_type(extn): + name = outname + "." + extn + if extn == "webm": + png_file = await TgConverter.convert( + input_file, + convert_to="png", + remove_old=remove_old, + ) + if png_file: + return await TgConverter.ffmpeg_convert( + png_file, name, remove=True + ) + else: + return await TgConverter.ffmpeg_convert( + input_file, name, remove=remove_old + ) + + LOGS.error(f"No valid conversion found for {input_file} to {convert_to or allowed_formats}") + return None + + except Exception as e: + LOGS.exception(f"Error in convert: {str(e)}") + return None def _get_value(stri): diff --git a/pyUltroid/startup/BaseClient.py b/pyUltroid/startup/BaseClient.py index 763159ce0..603121b52 100644 --- a/pyUltroid/startup/BaseClient.py +++ b/pyUltroid/startup/BaseClient.py @@ -128,6 +128,7 @@ async def fast_uploader(self, file, **kwargs): with contextlib.suppress(FileNotFoundError): os.remove(file) return files["raw_file"], time.time() - start_time + from pyUltroid.fns.FastTelethon import upload_file from pyUltroid.fns.helper import progress diff --git a/pyUltroid/version.py b/pyUltroid/version.py index 2bd0e369e..791e5438e 100644 --- a/pyUltroid/version.py +++ b/pyUltroid/version.py @@ -1,2 +1,2 @@ -__version__ = "2025.02.19" -ultroid_version = "2.0" +__version__ = "2025.02.23" +ultroid_version = "2.1" diff --git a/requirements.txt b/requirements.txt index 30d2f6483..6231f9924 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,6 +1,11 @@ # Important Requirements here. telethon -# https://github.com/TeamUltroid/Telethon/archive/ultroid.zip https://github.com/New-dev0/Telethon-Patch/archive/main.zip python-decouple python-dotenv +telegraph +enhancer +requests +aiohttp +catbox-uploader +cloudscraper \ No newline at end of file diff --git a/resources/startup/locals.py b/resources/startup/locals.py index 94b1f68af..024cef332 100644 --- a/resources/startup/locals.py +++ b/resources/startup/locals.py @@ -76,6 +76,7 @@ def start(): print("\nCongrats. All done!\nTime to start the bot!") print("\nInstalling requirements... This might take a while...") os.system("pip3 install --no-cache-dir -r requirements.txt") + os.system("pip3 install -r requirements.txt --break-system-packages") ask = input( "Enter 'yes/y' to Install other requirements, required for local deployment." ) diff --git a/resources/startup/optional-requirements.txt b/resources/startup/optional-requirements.txt index 224c30080..2d5fe5806 100644 --- a/resources/startup/optional-requirements.txt +++ b/resources/startup/optional-requirements.txt @@ -1,7 +1,7 @@ # Required only for Local Deploys # ------------------------------------------------------ # -git+https://github.com/ufoptg/akipy.git +akipy apscheduler aiohttp bs4