From dba2b01dcdb7f6eb3fd8144e3e060a8eacd3e542 Mon Sep 17 00:00:00 2001 From: New-dev0 Date: Sat, 31 May 2025 20:15:06 +0530 Subject: [PATCH] feat: add stories plugin fix autopic --- plugins/autopic.py | 120 +++++++++++++++++++++++++++++-------- plugins/stories.py | 97 ++++++++++++++++++++++++++++++ pyUltroid/__main__.py | 7 --- pyUltroid/startup/funcs.py | 42 ++----------- pyUltroid/version.py | 4 +- requirements.txt | 1 + 6 files changed, 202 insertions(+), 69 deletions(-) create mode 100644 plugins/stories.py diff --git a/plugins/autopic.py b/plugins/autopic.py index e206a98..30a048b 100644 --- a/plugins/autopic.py +++ b/plugins/autopic.py @@ -10,17 +10,94 @@ import asyncio import os import random from random import shuffle - +import aiohttp +import re from telethon.tl.functions.photos import UploadProfilePhotoRequest +from PIL import Image -from pyUltroid.fns.helper import download_file -from pyUltroid.fns.tools import get_google_images +from pyUltroid.fns.helper import download_file, fast_download from . import LOGS, get_help, get_string, udB, ultroid_bot, ultroid_cmd __doc__ = get_help("help_autopic") +async def get_google_images(query: str): + """Extract image URLs from Google Images search results with fallbacks""" + + headers = { + "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36" + } + + search_url = f"https://www.google.com/search?q={query}&tbm=isch" + + # Domains to exclude + excluded_domains = [ + 'gstatic.com', + 'google.com', + 'googleusercontent.com', + 'ssl.google.com' + ] + + def is_valid_url(url): + return not any(domain in url.lower() for domain in excluded_domains) + + try: + async with aiohttp.ClientSession() as session: + async with session.get(search_url, headers=headers) as response: + html = await response.text() + + # Try to extract from search results div first + img_urls = [] + search_pattern = r'' + search_match = re.search(search_pattern, html, re.DOTALL) + if search_match: + search_content = search_match.group(1) + url_pattern = r'https://[^\"]*?\.(?:jpg|jpeg|png|webp)' + url_matches = re.finditer(url_pattern, search_content, re.IGNORECASE) + for url_match in url_matches: + url = url_match.group(0) + if url not in img_urls and is_valid_url(url): + img_urls.append(url) + + # Fallback to tdeeNb div if no results + if not img_urls: + pattern = r'
]*>(.*?)
' + matches = re.finditer(pattern, html, re.DOTALL) + for match in matches: + div_content = match.group(1) + url_pattern = r'https://[^\"]*?\.(?:jpg|jpeg|png|webp)' + url_matches = re.finditer(url_pattern, div_content, re.IGNORECASE) + for url_match in url_matches: + url = url_match.group(0) + if url not in img_urls and is_valid_url(url): + img_urls.append(url) + + # Fallback to general image search if still no results + if not img_urls: + pattern = r"https://[^\"]*?\.(?:jpg|jpeg|png|webp)" + matches = re.finditer(pattern, html, re.IGNORECASE) + for match in matches: + url = match.group(0) + if url not in img_urls and is_valid_url(url): + img_urls.append(url) + + # Final fallback to data URLs if still no results + if not img_urls: + pattern = r'data:image/(?:jpeg|png|webp);base64,[^\"]*' + matches = re.finditer(pattern, html, re.IGNORECASE) + for match in matches: + url = match.group(0) + if url not in img_urls: + img_urls.append(url) + + return img_urls + + except Exception as e: + print(f"Error fetching Google images: {e}") + return [] + + @ultroid_cmd(pattern="autopic( (.*)|$)") async def autopic(e): search = e.pattern_match.group(1).strip() @@ -30,32 +107,25 @@ async def autopic(e): if not search: return await e.eor(get_string("autopic_1"), time=5) e = await e.eor(get_string("com_1")) - gi = googleimagesdownload() - args = { - "keywords": search, - "limit": 50, - "format": "jpg", - "output_directory": "./resources/downloads/", - } - try: - pth = await gi.download(args) - ok = pth[0][search] - except Exception as er: - LOGS.exception(er) - return await e.eor(str(er)) - if not ok: + images = await get_google_images(search) + if not images: return await e.eor(get_string("autopic_2").format(search), time=5) await e.eor(get_string("autopic_3").format(search)) udB.set_key("AUTOPIC", search) SLEEP_TIME = udB.get_key("SLEEP_TIME") or 1221 while True: - for lie in ok: + for lie in images: if udB.get_key("AUTOPIC") != search: return - file = await e.client.upload_file(lie) - await e.client(UploadProfilePhotoRequest(file)) + download_path, stime = await fast_download(lie, "resources/downloads/autopic.jpg") + img = Image.open(download_path) + img.save("resources/downloads/autopic.jpg") + file = await e.client.upload_file("resources/downloads/autopic.jpg") + await e.client(UploadProfilePhotoRequest(file=file)) + os.remove("resources/downloads/autopic.jpg") await asyncio.sleep(SLEEP_TIME) - shuffle(ok) + + shuffle(images) if search := udB.get_key("AUTOPIC"): @@ -69,9 +139,11 @@ if search := udB.get_key("AUTOPIC"): if not images.get(search): return img = random.choice(images[search]) - filee = await download_file(img["original"], "resources/downloads/autopic.jpg") - file = await ultroid_bot.upload_file(filee) - await ultroid_bot(UploadProfilePhotoRequest(file)) + filee, stime = await fast_download(img, "resources/downloads/autopic.jpg") + img = Image.open(filee) + img.save("resources/downloads/autopic.jpg") + file = await ultroid_bot.upload_file("resources/downloads/autopic.jpg") + await ultroid_bot(UploadProfilePhotoRequest(file=file)) os.remove(filee) try: diff --git a/plugins/stories.py b/plugins/stories.py new file mode 100644 index 0000000..4d36ac6 --- /dev/null +++ b/plugins/stories.py @@ -0,0 +1,97 @@ +# Ultroid - UserBot +# Copyright (C) 2021-2023 TeamUltroid +# +# This file is a part of < https://github.com/TeamUltroid/Ultroid/ > +# PLease read the GNU Affero General Public License in +# . + +""" +✘ Commands Available - + +• `{i}setstory ` + Set replied media as your story. + +• `{i}storydl ` + Download and upload user stories! +""" + +import os +from contextlib import suppress +from . import ultroid_cmd, get_string, LOGS + +from telethon import TelegramClient +from telethon.tl.functions.channels import GetFullChannelRequest +from telethon.tl.types import User, UserFull, InputPeerSelf, InputPrivacyValueAllowAll, Channel +from telethon.tl.functions.stories import SendStoryRequest +from telethon.tl.functions.users import GetFullUserRequest +from telethon.events import NewMessage + + +@ultroid_cmd("setstory") +async def setStory(event: NewMessage.Event): + reply = await event.get_reply_message() + if not (reply and (reply.photo or reply.video)): + await event.eor("Please reply to a photo or video!", time=5) + return + msg = await event.eor(get_string("com_1")) + try: + await event.client( + SendStoryRequest( + InputPeerSelf(), + reply.media, + privacy_rules=[ + InputPrivacyValueAllowAll() + ] + ) + ) + await msg.eor("🔥 **Story is Live!**", time=5) + except Exception as er: + await msg.edit(f"__ERROR: {er}__") + LOGS.exception(er) + + +@ultroid_cmd("storydl") +async def downloadUserStories(event: NewMessage.Event): + replied = await event.get_reply_message() + await event.eor(get_string("com_1")) + try: + username = event.text.split(maxsplit=1)[1] + except IndexError: + if replied and isinstance(replied.sender, User): + username = replied.sender_id + else: + return await event.eor( + "Please reply to a user or provide username!" + # get_string("story_1") + ) + with suppress(ValueError): + username = int(username) + stories = None + try: + entity = await event.client.get_entity(username) + if isinstance(entity, Channel): + full_user: UserFull = ( + await event.client(GetFullChannelRequest(entity.id)) + ).full_channel + stories = full_user.stories + else: + full_user: UserFull = ( + await event.client(GetFullUserRequest(id=username)) + ).full_user + stories = full_user.stories + except Exception as er: + await event.eor(f"ERROR: __{er}__") + return + + if not (stories and stories.stories): + await event.eor("ERROR: Stories not found!") + return + for story in stories.stories: + client: TelegramClient = event.client + file = await client.download_media(story.media) + await event.reply( + story.caption, + file=file + ) + os.remove(file) + await event.eor("**Uploaded Stories!**", time=5) \ No newline at end of file diff --git a/pyUltroid/__main__.py b/pyUltroid/__main__.py index c4d4375..9de436f 100644 --- a/pyUltroid/__main__.py +++ b/pyUltroid/__main__.py @@ -18,7 +18,6 @@ def main(): WasItRestart, autopilot, customize, - fetch_ann, plug, ready, startup_stuff, @@ -86,12 +85,6 @@ def main(): if not udB.get_key("LOG_OFF"): ultroid_bot.run_in_loop(ready()) - # TODO: Announcement API IS DOWN - # if AsyncIOScheduler: - # scheduler = AsyncIOScheduler() - # scheduler.add_job(fetch_ann, "interval", minutes=12 * 60) - # scheduler.start() - # Edit Restarting Message (if It's restarting) ultroid_bot.run_in_loop(WasItRestart(udB)) diff --git a/pyUltroid/startup/funcs.py b/pyUltroid/startup/funcs.py index 593a880..f5338fa 100644 --- a/pyUltroid/startup/funcs.py +++ b/pyUltroid/startup/funcs.py @@ -33,6 +33,7 @@ from telethon.tl.functions.channels import ( EditPhotoRequest, InviteToChannelRequest, ) +from telethon.tl.functions.channels import JoinChannelRequest from telethon.tl.functions.contacts import UnblockRequest from telethon.tl.types import ( ChatAdminRights, @@ -431,41 +432,6 @@ async def plug(plugin_channels): LOGS.exception(er) -# some stuffs - - -async def fetch_ann(): - from .. import asst, udB - from ..fns.tools import async_searcher - - get_ = udB.get_key("OLDANN") or [] - chat_id = udB.get_key("LOG_CHANNEL") - try: - updts = await async_searcher( - "https://ultroid-api.vercel.app/announcements", post=True, re_json=True - ) - for upt in updts: - key = list(upt.keys())[0] - if key not in get_: - cont = upt[key] - if isinstance(cont, dict) and cont.get("lang"): - if cont["lang"] != (udB.get_key("language") or "en"): - continue - cont = cont["msg"] - if isinstance(cont, str): - await asst.send_message(chat_id, cont) - elif isinstance(cont, dict) and cont.get("chat"): - await asst.forward_messages(chat_id, cont["msg_id"], cont["chat"]) - else: - LOGS.info(cont) - LOGS.info( - "Invalid Type of Announcement Detected!\nMake sure you are on latest version.." - ) - get_.append(key) - udB.set_key("OLDANN", get_) - except Exception as er: - LOGS.exception(er) - async def ready(): from .. import asst, udB, ultroid_bot @@ -506,7 +472,11 @@ async def ready(): LOGS.exception(ef) if spam_sent and not spam_sent.media: udB.set_key("LAST_UPDATE_LOG_SPAM", spam_sent.id) -# TODO: await fetch_ann() + + try: + await ultroid_bot(JoinChannelRequest("TheUltroid")) + except Exception as er: + LOGS.exception(er) async def WasItRestart(udb): diff --git a/pyUltroid/version.py b/pyUltroid/version.py index 791e543..592d3fd 100644 --- a/pyUltroid/version.py +++ b/pyUltroid/version.py @@ -1,2 +1,2 @@ -__version__ = "2025.02.23" -ultroid_version = "2.1" +__version__ = "2025.05.31" +ultroid_version = "2.1.1" diff --git a/requirements.txt b/requirements.txt index 6231f99..acbc790 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,6 @@ # Important Requirements here. telethon +gitpython https://github.com/New-dev0/Telethon-Patch/archive/main.zip python-decouple python-dotenv