From 52f7d6eb14e6e2f5ea4c0f18f1df946a88b8d1df Mon Sep 17 00:00:00 2001 From: Yasir Date: Sat, 7 Sep 2024 12:14:21 +0700 Subject: [PATCH] Update version --- Dockerfile | 38 +- README.md | 406 ++-- misskaty/__init__.py | 2 +- misskaty/helper/mediainfo_paste.py | 156 +- misskaty/plugins/chatbot_ai.py | 280 +-- misskaty/plugins/dev.py | 1316 +++++------ misskaty/plugins/paste.py | 910 ++++---- misskaty/plugins/web_scraper.py | 3246 ++++++++++++++-------------- requirements.txt | 72 +- 9 files changed, 3213 insertions(+), 3213 deletions(-) diff --git a/Dockerfile b/Dockerfile index 553ee4f0..d7a95b47 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,19 +1,19 @@ -# * @author Yasir Aris M -# * @date 2022-12-01 09:12:27 -# * @projectName MissKatyPyro -# * Copyright ©YasirPedia All rights reserved - -# Base Docker Using Ubuntu 24.04, Python 3.12 and Built In Pip -## With Built in Pip Package -FROM yasirarism/misskaty-docker:py3.12 -## Without Built in Pip Package -# FROM yasirarism/misskaty-docker:free - -# Set Hostname -ENV HOSTNAME=yasir-server -# Copy Files -COPY . . -# Instal pip package -# RUN pip3 install --no-cache-dir -r requirements.txt -# Set CMD Bot -CMD ["bash", "start.sh"] +# * @author Yasir Aris M +# * @date 2022-12-01 09:12:27 +# * @projectName MissKatyPyro +# * Copyright ©YasirPedia All rights reserved + +# Base Docker Using Ubuntu 24.04, Python 3.12 and Built In Pip +## With Built in Pip Package +FROM yasirarism/misskaty-docker:py3.12 +## Without Built in Pip Package +# FROM yasirarism/misskaty-docker:free + +# Set Hostname +ENV HOSTNAME=yasir-server +# Copy Files +COPY . . +# Instal pip package +# RUN pip3 install --no-cache-dir -r requirements.txt +# Set CMD Bot +CMD ["bash", "start.sh"] diff --git a/README.md b/README.md index 926df603..40a9446b 100644 --- a/README.md +++ b/README.md @@ -1,203 +1,203 @@ -# MissKatyPyro -```diff -- I will not give any support to your fork, so try learn by yourself!! Don't contact me because of your fault. I will stop update to this repo, and i will only give minor bugfix to this repo. -``` - - -![MIT License][license-shield] ![Repository Size][repository-size-shield] ![Issue Closed][issue-closed-shield] - - -

- -

- - - [![Readme in Indonesian][readme-ko-shield]][readme-ko-url] [![View Demo][view-demo-shield]][view-demo-url] [![Report bug][report-bug-shield]][report-bug-url] - - -# Table of Contents -- [[1] About MissKaty](#1-about-misskaty) -- [[2] Framework Tools And Server That Used To Build This Bot](#2-framework-tools-and-server-that-used-to-build-this-bot) -- [[3] Support Creator](#3-donation) -- [[4] Notes](#4-notes) -- [[5] Features](#5-features) -- [[6] Variables](#6-variables) -- [[7] Deploying Tutorial](#7-deploy-recommended-using-dockerdocker-compose) - - [Build And Run Using Legacy Method](#build-and-run-using-legacy-method) - - [Build And Run Using Docker](#build-and-run-using-docker) - - [Build And Run The Docker Image Using docker-compose](#build-and-run-the-docker-image-using-docker-compose) -- [[8] Credits](#8-thanks-to) -- [[9] Disclaimer](#8-disclaimer) - -# [1] About MissKaty -*MissKaty* is a Telegram Bot built using Python and the Pyrogram library. Many useful features for us to use. I hope that one day this project will be discontinued, someone will continue or develop it again. I gave the name MissKaty because I like cats, a cute animal that likes to be played with and friendly with humans. - -## [2] Framework Tools And Server That Used To Build This Bot - 🌱 PyroFork v2.x.x (Fork of Pyrogram with Topics, Stories Support and Some Patch)
- 🌱 Python 3.12 Support
- 🌱 MongoDB as Database
- 🌱 PyKeyboard for Building Pagination
- 🌱 VS Code
- 🌱 VPS/Server With Root and Docker Support (Recommended)
- -## [3] Donation and Support -*For Indonesian Only and some supported country:*
- 🌱 [QRIS][qris-url]
- -*For International Payment:*
- 🌱 [Paypal][paypal-url]
- -## [4] Notes -If you want help me fixing some error in my bot, you can make pull request to this repo. I'm very glad if you can help me. You can also give support to me for buying server. - -## [5] Features - -| FEATURE MY BOT |🌱| -| ------------- | ------------- | -| Basic Admin Feature |✔️| -| AFK Feature |✔️| -| Downloader FB, TikTok and YT-DLP Support |✔️| -| MultiLanguage Support (Unfinished) |⚠️| -| NightMode |✔️| -| ChatBot based on OpenAI and Google Bard |✔️| -| MissKaty Mata |✔️| -| Inline Search |✔️| -| Sticker Tools |✔️| -| PasteBin Tools |✔️| -| WebScraper (Pahe, MelongMovie, LK21, Terbit21, Kusonime, etc) |✔️| -| IMDB Search With Multi Language Per User |✔️| -| GenSS From Media and MediaInfo Generator |✔️| -| And Many More.. |✔️| - -## [6] Variables - -### Required Variables -* `BOT_TOKEN`: Create a bot using [@BotFather](https://t.me/BotFather), and get the Telegram API token. -* `API_ID`: Get this value from [telegram.org](https://my.telegram.org/apps) -* `API_HASH`: Get this value from [telegram.org](https://my.telegram.org/apps) -* `DATABASE_URI`: [mongoDB](https://www.mongodb.com) URI. Get this value from [mongoDB](https://www.mongodb.com). -* `LOG_CHANNEL` : A channel to log the activities of bot. Make sure bot is an admin in the channel. - -### Optional Variables -* `YT_COOKIES` : Get YT cookies using https://chromewebstore.google.com/detail/get-cookiestxt-locally/cclelndahbckbenkjhflpdbgdldlbecc?pli=1 and save cookies value on github gist. Copy raw url and fill in this vars. -* `USER_SESSION` : Session string for Userbot. -* `DATABASE_NAME`: Name of the database in MongoDB -* `COMMAND_HANDLER`: List of handler bot command splitted by space. Ex: `. !` > so bot will respond with `.cmd` or `!cmd` -* `SUDO`: User ID that have access to bot, split by space -* `OPENAI_API`: Create personal access token from github, and set as this env. Make sure you have access to Github Model. -* `GOOGLEAI_KEY`: Learn how to get api key from this https://ai.google.dev/tutorials/python_quickstart?hl=en. -* `CURRENCY_API`: Get API Key from https://app.exchangerate-api.com/sign-up - -## [7] Tutorial Deploy (Recommended using Docker/Docker Compose) - -#### Build And Run Using Legacy Method -- Make sure minimum python version is 3.8 and max python 3.12 to prevent some errors. Check it with this command: -``` -python3 --version -``` -- Install all dependency that needed bot to run. *(need root access, you can skip this if your server didn't have root access but some plugins will not work)* -``` -apt update -y & apt install libjpeg-dev zlib1g-dev libwebp-dev python3-pip python3-lxml git wget curl ffmpeg locales tzdata neofetch mediainfo speedtest-cli -y -``` -- Install requirements.txt, if using python => 3.11, you need use venv when install pip package.
-*Python < 3.10* -``` -pip3 install -r requirements.txt -``` -*Python => 3.11* -``` -python3 -m venv nama_venv -source nama_venv/bin/activate -pip3 install -r requirements.txt -``` -- Setting your config.env or via environment and dont forget fill all required value. -- Run Bot -``` -bash start.sh -``` - -#### Build And Run Using Docker - -- Start Docker daemon (Skip if already running): -``` -sudo dockerd -``` -- Build Docker image: -``` -sudo docker build . -t misskaty -``` -- Run the image: -``` -sudo docker run misskaty -``` -- To stop the image: -``` -sudo docker ps -sudo docker stop -``` - -#### Build And Run The Docker Image Using docker-compose - -- Install docker-compose -``` -sudo apt install docker-compose -``` -- Build and run Docker image or to view current running image: -``` -sudo docker-compose up -``` -- After editing files with nano for example (nano start.sh): -``` -sudo docker-compose up --build -``` -- To stop the running image: -``` -sudo docker ps -``` -``` -sudo docker-compose stop -``` - ----- - - -## [8] Thanks to - - Thanks To Allah Swt. - - Thanks To Dan For [Pyrogram Library](https://github.com/pyrogram/pyrogram) as founder of pyrogram. - - Thanks To Mayuri For [Pyrofork Library](https://github.com/Mayuri-Chan) as owner of pyrofork library. - - Thanks To TeamDrivecok and SecretGroup TBK in Telegram. - - Thanks To [The Hamker Cat](https://github.com/TheHamkerCat) For WilliamButcher Code. - - Thanks To [Team Yukki](https://github.com/TeamYukki) For AFK Bot Code. - - Thanks To [Wrench](https://github.com/EverythingSuckz) For Some Code. - - Thanks To [AmanoTeam](https://github.com/AmanoTeam) For MultiLanguage Template. - - And All People Who Help Me In My Life... - If your code used in this repo and want to give credit please open issue.. - -## [9] Disclaimer -[![GNU Affero General Public License 2.0](https://www.gnu.org/graphics/agplv3-155x51.png)](https://www.gnu.org/licenses/agpl-3.0.en.html#header) -Licensed under [GNU AGPL 2.0.](https://github.com/yasirarism/MissKatyPyro/blob/master/LICENSE) -WARNING: Selling The Codes To Other People For Money Is *Strictly Prohibited*. Or i will stop this project forever. - - -[license-shield]: https://img.shields.io/github/license/yasirarism/MissKatyPyro?labelColor=D8D8D8&color=04B4AE -[repository-size-shield]: https://img.shields.io/github/repo-size/yasirarism/MissKatyPyro?labelColor=D8D8D8&color=BE81F7 -[issue-closed-shield]: https://img.shields.io/github/issues-closed/yasirarism/MissKatyPyro?labelColor=D8D8D8&color=FE9A2E - - -[readme-ko-shield]: https://img.shields.io/badge/-readme%20in%20Indonesian-2E2E2E?style=for-the-badge -[view-demo-shield]: https://img.shields.io/badge/-%F0%9F%98%8E%20view%20demo-F3F781?style=for-the-badge -[view-demo-url]: https://t.me/MissKatyBot -[report-bug-shield]: https://img.shields.io/badge/-%F0%9F%90%9E%20report%20bug-F5A9A9?style=for-the-badge -[report-bug-url]: https://github.com/yasirarism/MissKatyPyro/issues -[request-feature-shield]: https://img.shields.io/badge/-%E2%9C%A8%20request%20feature-A9D0F5?style=for-the-badge -[request-feature-url]: https://github.com/yasirarism/MissKatyPyro/issues - - -[readme-ko-url]: README.id.md -[kofi-url]: https://ko-fi.com/yasirarism -[paypal-url]: https://paypal.me/yasirarism -[qris-url]: https://img.yasirweb.eu.org/file/ee74ce527fb8264b54691.jpg -[mayar]: https://yasirarism.mayar.link/payme -[sociabuzz-url]: https://sociabuzz.com/yasirarism/tribe -[saweria-url]: https://saweria.co/yasirarism -[trakteer-url]: https://trakteer.id/yasir-aris-sp7cn +# MissKatyPyro +```diff +- I will not give any support to your fork, so try learn by yourself!! Don't contact me because of your fault. I will stop update to this repo, and i will only give minor bugfix to this repo. +``` + + +![MIT License][license-shield] ![Repository Size][repository-size-shield] ![Issue Closed][issue-closed-shield] + + +

+ +

+ + + [![Readme in Indonesian][readme-ko-shield]][readme-ko-url] [![View Demo][view-demo-shield]][view-demo-url] [![Report bug][report-bug-shield]][report-bug-url] + + +# Table of Contents +- [[1] About MissKaty](#1-about-misskaty) +- [[2] Framework Tools And Server That Used To Build This Bot](#2-framework-tools-and-server-that-used-to-build-this-bot) +- [[3] Support Creator](#3-donation) +- [[4] Notes](#4-notes) +- [[5] Features](#5-features) +- [[6] Variables](#6-variables) +- [[7] Deploying Tutorial](#7-deploy-recommended-using-dockerdocker-compose) + - [Build And Run Using Legacy Method](#build-and-run-using-legacy-method) + - [Build And Run Using Docker](#build-and-run-using-docker) + - [Build And Run The Docker Image Using docker-compose](#build-and-run-the-docker-image-using-docker-compose) +- [[8] Credits](#8-thanks-to) +- [[9] Disclaimer](#8-disclaimer) + +# [1] About MissKaty +*MissKaty* is a Telegram Bot built using Python and the Pyrogram library. Many useful features for us to use. I hope that one day this project will be discontinued, someone will continue or develop it again. I gave the name MissKaty because I like cats, a cute animal that likes to be played with and friendly with humans. + +## [2] Framework Tools And Server That Used To Build This Bot + 🌱 PyroFork v2.x.x (Fork of Pyrogram with Topics, Stories Support and Some Patch)
+ 🌱 Python 3.12 Support
+ 🌱 MongoDB as Database
+ 🌱 PyKeyboard for Building Pagination
+ 🌱 VS Code
+ 🌱 VPS/Server With Root and Docker Support (Recommended)
+ +## [3] Donation and Support +*For Indonesian Only and some supported country:*
+ 🌱 [QRIS][qris-url]
+ +*For International Payment:*
+ 🌱 [Paypal][paypal-url]
+ +## [4] Notes +If you want help me fixing some error in my bot, you can make pull request to this repo. I'm very glad if you can help me. You can also give support to me for buying server. + +## [5] Features + +| FEATURE MY BOT |🌱| +| ------------- | ------------- | +| Basic Admin Feature |✔️| +| AFK Feature |✔️| +| Downloader FB, TikTok and YT-DLP Support |✔️| +| MultiLanguage Support (Unfinished) |⚠️| +| NightMode |✔️| +| ChatBot based on OpenAI and Google Bard |✔️| +| MissKaty Mata |✔️| +| Inline Search |✔️| +| Sticker Tools |✔️| +| PasteBin Tools |✔️| +| WebScraper (Pahe, MelongMovie, LK21, Terbit21, Kusonime, etc) |✔️| +| IMDB Search With Multi Language Per User |✔️| +| GenSS From Media and MediaInfo Generator |✔️| +| And Many More.. |✔️| + +## [6] Variables + +### Required Variables +* `BOT_TOKEN`: Create a bot using [@BotFather](https://t.me/BotFather), and get the Telegram API token. +* `API_ID`: Get this value from [telegram.org](https://my.telegram.org/apps) +* `API_HASH`: Get this value from [telegram.org](https://my.telegram.org/apps) +* `DATABASE_URI`: [mongoDB](https://www.mongodb.com) URI. Get this value from [mongoDB](https://www.mongodb.com). +* `LOG_CHANNEL` : A channel to log the activities of bot. Make sure bot is an admin in the channel. + +### Optional Variables +* `YT_COOKIES` : Get YT cookies using https://chromewebstore.google.com/detail/get-cookiestxt-locally/cclelndahbckbenkjhflpdbgdldlbecc?pli=1 and save cookies value on github gist. Copy raw url and fill in this vars. +* `USER_SESSION` : Session string for Userbot. +* `DATABASE_NAME`: Name of the database in MongoDB +* `COMMAND_HANDLER`: List of handler bot command splitted by space. Ex: `. !` > so bot will respond with `.cmd` or `!cmd` +* `SUDO`: User ID that have access to bot, split by space +* `OPENAI_API`: Create personal access token from github, and set as this env. Make sure you have access to Github Model. +* `GOOGLEAI_KEY`: Learn how to get api key from this https://ai.google.dev/tutorials/python_quickstart?hl=en. +* `CURRENCY_API`: Get API Key from https://app.exchangerate-api.com/sign-up + +## [7] Tutorial Deploy (Recommended using Docker/Docker Compose) + +#### Build And Run Using Legacy Method +- Make sure minimum python version is 3.8 and max python 3.12 to prevent some errors. Check it with this command: +``` +python3 --version +``` +- Install all dependency that needed bot to run. *(need root access, you can skip this if your server didn't have root access but some plugins will not work)* +``` +apt update -y & apt install libjpeg-dev zlib1g-dev libwebp-dev python3-pip python3-lxml git wget curl ffmpeg locales tzdata neofetch mediainfo speedtest-cli -y +``` +- Install requirements.txt, if using python => 3.11, you need use venv when install pip package.
+*Python < 3.10* +``` +pip3 install -r requirements.txt +``` +*Python => 3.11* +``` +python3 -m venv nama_venv +source nama_venv/bin/activate +pip3 install -r requirements.txt +``` +- Setting your config.env or via environment and dont forget fill all required value. +- Run Bot +``` +bash start.sh +``` + +#### Build And Run Using Docker + +- Start Docker daemon (Skip if already running): +``` +sudo dockerd +``` +- Build Docker image: +``` +sudo docker build . -t misskaty +``` +- Run the image: +``` +sudo docker run misskaty +``` +- To stop the image: +``` +sudo docker ps +sudo docker stop +``` + +#### Build And Run The Docker Image Using docker-compose + +- Install docker-compose +``` +sudo apt install docker-compose +``` +- Build and run Docker image or to view current running image: +``` +sudo docker-compose up +``` +- After editing files with nano for example (nano start.sh): +``` +sudo docker-compose up --build +``` +- To stop the running image: +``` +sudo docker ps +``` +``` +sudo docker-compose stop +``` + +---- + + +## [8] Thanks to + - Thanks To Allah Swt. + - Thanks To Dan For [Pyrogram Library](https://github.com/pyrogram/pyrogram) as founder of pyrogram. + - Thanks To Mayuri For [Pyrofork Library](https://github.com/Mayuri-Chan) as owner of pyrofork library. + - Thanks To TeamDrivecok and SecretGroup TBK in Telegram. + - Thanks To [The Hamker Cat](https://github.com/TheHamkerCat) For WilliamButcher Code. + - Thanks To [Team Yukki](https://github.com/TeamYukki) For AFK Bot Code. + - Thanks To [Wrench](https://github.com/EverythingSuckz) For Some Code. + - Thanks To [AmanoTeam](https://github.com/AmanoTeam) For MultiLanguage Template. + - And All People Who Help Me In My Life... + If your code used in this repo and want to give credit please open issue.. + +## [9] Disclaimer +[![GNU Affero General Public License 2.0](https://www.gnu.org/graphics/agplv3-155x51.png)](https://www.gnu.org/licenses/agpl-3.0.en.html#header) +Licensed under [GNU AGPL 2.0.](https://github.com/yasirarism/MissKatyPyro/blob/master/LICENSE) +WARNING: Selling The Codes To Other People For Money Is *Strictly Prohibited*. Or i will stop this project forever. + + +[license-shield]: https://img.shields.io/github/license/yasirarism/MissKatyPyro?labelColor=D8D8D8&color=04B4AE +[repository-size-shield]: https://img.shields.io/github/repo-size/yasirarism/MissKatyPyro?labelColor=D8D8D8&color=BE81F7 +[issue-closed-shield]: https://img.shields.io/github/issues-closed/yasirarism/MissKatyPyro?labelColor=D8D8D8&color=FE9A2E + + +[readme-ko-shield]: https://img.shields.io/badge/-readme%20in%20Indonesian-2E2E2E?style=for-the-badge +[view-demo-shield]: https://img.shields.io/badge/-%F0%9F%98%8E%20view%20demo-F3F781?style=for-the-badge +[view-demo-url]: https://t.me/MissKatyBot +[report-bug-shield]: https://img.shields.io/badge/-%F0%9F%90%9E%20report%20bug-F5A9A9?style=for-the-badge +[report-bug-url]: https://github.com/yasirarism/MissKatyPyro/issues +[request-feature-shield]: https://img.shields.io/badge/-%E2%9C%A8%20request%20feature-A9D0F5?style=for-the-badge +[request-feature-url]: https://github.com/yasirarism/MissKatyPyro/issues + + +[readme-ko-url]: README.id.md +[kofi-url]: https://ko-fi.com/yasirarism +[paypal-url]: https://paypal.me/yasirarism +[qris-url]: https://img.yasirweb.eu.org/file/ee74ce527fb8264b54691.jpg +[mayar]: https://yasirarism.mayar.link/payme +[sociabuzz-url]: https://sociabuzz.com/yasirarism/tribe +[saweria-url]: https://saweria.co/yasirarism +[trakteer-url]: https://trakteer.id/yasir-aris-sp7cn diff --git a/misskaty/__init__.py b/misskaty/__init__.py index d343eadf..24fb0feb 100644 --- a/misskaty/__init__.py +++ b/misskaty/__init__.py @@ -46,7 +46,7 @@ MOD_NOLOAD = ["subscene_dl"] HELPABLE = {} cleanmode = {} botStartTime = time.time() -misskaty_version = "v2.14" +misskaty_version = "v2.15" uvloop.install() faulthandler_enable() diff --git a/misskaty/helper/mediainfo_paste.py b/misskaty/helper/mediainfo_paste.py index 7cbfb556..2137136f 100644 --- a/misskaty/helper/mediainfo_paste.py +++ b/misskaty/helper/mediainfo_paste.py @@ -1,78 +1,78 @@ -import json -import re - -from .http import fetch - - -def html_builder(title: str, text: str) -> str: - """ - Make proper html with css from given content. - """ - - heading = "{content}" - subheading = "{content}" - infobox = "" - subtitlebox = "" - icon = "" - html_msg = f"{heading.format(content=title)}" - - for line in text.splitlines(): - if ":" not in line and bool(line): - if "Text #" in line: - if bool(re.search("Text #1$", line)): - subtitle_count = len(re.findall("Text #", text)) - html_msg += icon.format( - icon_url="https://te.legra.ph/file/9d4a676445544d0f2d6db.png" - ) - html_msg += subheading.format( - content=f"Subtitles ({subtitle_count} subtitle)" - ) - html_msg += "" - - elif "General" in line: - html_msg += icon.format( - icon_url="https://te.legra.ph/file/638fb0416f2600e7c5aa3.png" - ) - html_msg += subheading.format(content="General") - - elif "Video" in line: - html_msg += icon.format( - icon_url="https://te.legra.ph/file/fbc30d71cf71c9a54e59d.png" - ) - html_msg += subheading.format(content="Video") - - elif "Audio" in line: - html_msg += icon.format( - icon_url="https://te.legra.ph/file/a3c431be457fedbae2286.png" - ) - html_msg += subheading.format(content=f"{line.strip()}") - - elif "Menu" in line: - html_msg += "" - html_msg += icon.format( - icon_url="https://te.legra.ph/file/3023b0c2bc202ec9d6d0d.png" - ) - html_msg += subheading.format(content="Chapters") - - else: - html_msg += subheading.format(content=f"{line.strip()}") - html_msg += subtitlebox if "Text #" in line else infobox - - elif ":" in line: - if "Attachments" not in line and "ErrorDetectionType" not in line: - html_msg += f"
{line.strip()}
" - - else: - html_msg += "
" - - html_msg += "
" - return html_msg - - -async def mediainfo_paste(text: str, title: str) -> str: - html_content = html_builder(title, text) - URL = "https://yasirr.eu.org/mediainfo" - response = await fetch.post(URL, data={"content": html_content}) - return ( - f"https://yasirr.eu.org/mediainfo-{json.loads(response.content)['key']}" - ) +import json +import re + +from .http import fetch + + +def html_builder(title: str, text: str) -> str: + """ + Make proper html with css from given content. + """ + + heading = "{content}" + subheading = "{content}" + infobox = "" + subtitlebox = "" + icon = "" + html_msg = f"{heading.format(content=title)}" + + for line in text.splitlines(): + if ":" not in line and bool(line): + if "Text #" in line: + if bool(re.search("Text #1$", line)): + subtitle_count = len(re.findall("Text #", text)) + html_msg += icon.format( + icon_url="https://te.legra.ph/file/9d4a676445544d0f2d6db.png" + ) + html_msg += subheading.format( + content=f"Subtitles ({subtitle_count} subtitle)" + ) + html_msg += "" + + elif "General" in line: + html_msg += icon.format( + icon_url="https://te.legra.ph/file/638fb0416f2600e7c5aa3.png" + ) + html_msg += subheading.format(content="General") + + elif "Video" in line: + html_msg += icon.format( + icon_url="https://te.legra.ph/file/fbc30d71cf71c9a54e59d.png" + ) + html_msg += subheading.format(content="Video") + + elif "Audio" in line: + html_msg += icon.format( + icon_url="https://te.legra.ph/file/a3c431be457fedbae2286.png" + ) + html_msg += subheading.format(content=f"{line.strip()}") + + elif "Menu" in line: + html_msg += "" + html_msg += icon.format( + icon_url="https://te.legra.ph/file/3023b0c2bc202ec9d6d0d.png" + ) + html_msg += subheading.format(content="Chapters") + + else: + html_msg += subheading.format(content=f"{line.strip()}") + html_msg += subtitlebox if "Text #" in line else infobox + + elif ":" in line: + if "Attachments" not in line and "ErrorDetectionType" not in line: + html_msg += f"
{line.strip()}
" + + else: + html_msg += "
" + + html_msg += "
" + return html_msg + + +async def mediainfo_paste(text: str, title: str) -> str: + html_content = html_builder(title, text) + URL = "https://yasirr.eu.org/mediainfo" + response = await fetch.post(URL, data={"content": html_content}) + return ( + f"https://yasirr.eu.org/mediainfo-{json.loads(response.content)['key']}" + ) diff --git a/misskaty/plugins/chatbot_ai.py b/misskaty/plugins/chatbot_ai.py index 368ddd58..e68eed02 100644 --- a/misskaty/plugins/chatbot_ai.py +++ b/misskaty/plugins/chatbot_ai.py @@ -1,140 +1,140 @@ -# * @author Yasir Aris M -# * @date 2023-06-21 22:12:27 -# * @projectName MissKatyPyro -# * Copyright ©YasirPedia All rights reserved -import asyncio -import html -import privatebinapi - -from cachetools import TTLCache -from openai import APIConnectionError, APIStatusError, AsyncOpenAI, RateLimitError -from pyrogram import filters -from pyrogram.errors import MessageTooLong -from pyrogram.types import Message - -from misskaty import app -from misskaty.core import pyro_cooldown -from misskaty.helper import check_time_gap, post_to_telegraph, use_chat_lang -from misskaty.vars import COMMAND_HANDLER, GOOGLEAI_KEY, OPENAI_KEY, SUDO - -__MODULE__ = "ChatBot" -__HELP__ = """ -/ai - Generate text response from AI using Gemini AI By Google. -/ask - Generate text response from AI using OpenAI. -""" - -gptai_conversations = TTLCache(maxsize=4000, ttl=24*60*60) -gemini_conversations = TTLCache(maxsize=4000, ttl=24*60*60) - -async def get_openai_stream_response(is_stream, key, base_url, model, messages, bmsg, strings): - ai = AsyncOpenAI(api_key=key, base_url=base_url) - answer = "" - num = 0 - try: - response = await ai.chat.completions.create( - model=model, - messages=messages, - temperature=0.7, - stream=is_stream, - ) - if not is_stream: - answer += response.choices[0].message.content - if len(answer) > 4000: - answerlink = await privatebinapi.send_async("https://bin.yasirweb.eu.org", text=answer, expiration="1week", formatting="markdown") - await bmsg.edit_msg( - strings("answers_too_long").format(answerlink=answerlink.get("full_url")), - disable_web_page_preview=True, - ) - else: - await bmsg.edit_msg(f"{html.escape(answer)}\nPowered by: Gemini 1.5 Flash") - else: - async for chunk in response: - if not chunk.choices or not chunk.choices[0].delta.content: - continue - num += 1 - answer += chunk.choices[0].delta.content - if num == 30 and len(answer) < 4000: - await bmsg.edit_msg(html.escape(answer)) - await asyncio.sleep(1.5) - num = 0 - if len(answer) > 4000: - answerlink = await privatebinapi.send_async("https://bin.yasirweb.eu.org", text=answer, expiration="1week", formatting="markdown") - await bmsg.edit_msg( - strings("answers_too_long").format(answerlink=answerlink.get("full_url")), - disable_web_page_preview=True, - ) - else: - await bmsg.edit_msg(f"{html.escape(answer)}\n\nPowered by: GPT 4o") - except APIConnectionError as e: - await bmsg.edit_msg(f"The server could not be reached because {e.__cause__}") - return None - except RateLimitError as e: - if "billing details" in str(e): - return await bmsg.edit_msg( - "This openai key from this bot has expired, please give openai key donation for bot owner." - ) - await bmsg.edit_msg("You're got rate limit, please try again later.") - return None - except APIStatusError as e: - await bmsg.edit_msg( - f"Another {e.status_code} status code was received with response {e.response}" - ) - return None - except Exception as e: - await bmsg.edit_msg(f"ERROR: {e}") - return None - return answer - - -@app.on_message(filters.command("ai", COMMAND_HANDLER) & pyro_cooldown.wait(10)) -@app.on_bot_business_message( - filters.command("ai", COMMAND_HANDLER) & pyro_cooldown.wait(10) -) -@use_chat_lang() -async def gemini_chatbot(_, ctx: Message, strings): - if len(ctx.command) == 1: - return await ctx.reply_msg( - strings("no_question").format(cmd=ctx.command[0]), quote=True, del_in=5 - ) - if not GOOGLEAI_KEY: - return await ctx.reply_msg("GOOGLEAI_KEY env is missing!!!") - uid = ctx.from_user.id if ctx.from_user else ctx.sender_chat.id - msg = await ctx.reply_msg(strings("find_answers_str"), quote=True) - if uid not in gemini_conversations: - gemini_conversations[uid] = [{"role": "system", "content": "Kamu adalah AI dengan karakter mirip kucing bernama MissKaty AI yang diciptakan oleh Yasir untuk membantu manusia mencari informasi."}, {"role": "user", "content": ctx.input}] - else: - gemini_conversations[uid].append({"role": "user", "content": ctx.input}) - ai_response = await get_openai_stream_response(False, GOOGLEAI_KEY, "https://gemini.yasirapi.eu.org/v1", "gemini-1.5-flash", gemini_conversations[uid], msg, strings) - if not ai_response: - gemini_conversations[uid].pop() - if len(gemini_conversations[uid]) == 1: - gemini_conversations.pop(uid) - return - gemini_conversations[uid].append({"role": "assistant", "content": ai_response}) - -@app.on_message(filters.command("ask", COMMAND_HANDLER) & pyro_cooldown.wait(10)) -@use_chat_lang() -async def openai_chatbot(self, ctx: Message, strings): - if len(ctx.command) == 1: - return await ctx.reply_msg( - strings("no_question").format(cmd=ctx.command[0]), quote=True, del_in=5 - ) - if not OPENAI_KEY: - return await ctx.reply_msg("OPENAI_KEY env is missing!!!") - uid = ctx.from_user.id if ctx.from_user else ctx.sender_chat.id - is_in_gap, _ = await check_time_gap(uid) - if is_in_gap and (uid not in SUDO): - return await ctx.reply_msg(strings("dont_spam"), del_in=5) - pertanyaan = ctx.input - msg = await ctx.reply_msg(strings("find_answers_str"), quote=True) - if uid not in gptai_conversations: - gptai_conversations[uid] = [{"role": "system", "content": "Kamu adalah AI dengan karakter mirip kucing bernama MissKaty AI yang diciptakan oleh Yasir untuk membantu manusia mencari informasi."}, {"role": "user", "content": pertanyaan}] - else: - gptai_conversations[uid].append({"role": "user", "content": pertanyaan}) - ai_response = await get_openai_stream_response(True, OPENAI_KEY, "https://models.inference.ai.azure.com" if uid in SUDO else "https://duckai.yasirapi.eu.org/v1", "gpt-4o" if uid in SUDO else "gpt-4o-mini", gptai_conversations[uid], msg, strings) - if not ai_response: - gptai_conversations[uid].pop() - if len(gptai_conversations[uid]) == 1: - gptai_conversations.pop(uid) - return - gptai_conversations[uid].append({"role": "assistant", "content": ai_response}) +# * @author Yasir Aris M +# * @date 2023-06-21 22:12:27 +# * @projectName MissKatyPyro +# * Copyright ©YasirPedia All rights reserved +import asyncio +import html +import privatebinapi + +from cachetools import TTLCache +from openai import APIConnectionError, APIStatusError, AsyncOpenAI, RateLimitError +from pyrogram import filters +from pyrogram.errors import MessageTooLong +from pyrogram.types import Message + +from misskaty import app +from misskaty.core import pyro_cooldown +from misskaty.helper import check_time_gap, post_to_telegraph, use_chat_lang +from misskaty.vars import COMMAND_HANDLER, GOOGLEAI_KEY, OPENAI_KEY, SUDO + +__MODULE__ = "ChatBot" +__HELP__ = """ +/ai - Generate text response from AI using Gemini AI By Google. +/ask - Generate text response from AI using OpenAI. +""" + +gptai_conversations = TTLCache(maxsize=4000, ttl=24*60*60) +gemini_conversations = TTLCache(maxsize=4000, ttl=24*60*60) + +async def get_openai_stream_response(is_stream, key, base_url, model, messages, bmsg, strings): + ai = AsyncOpenAI(api_key=key, base_url=base_url) + answer = "" + num = 0 + try: + response = await ai.chat.completions.create( + model=model, + messages=messages, + temperature=0.7, + stream=is_stream, + ) + if not is_stream: + answer += response.choices[0].message.content + if len(answer) > 4000: + answerlink = await privatebinapi.send_async("https://bin.yasirweb.eu.org", text=answer, expiration="1week", formatting="markdown") + await bmsg.edit_msg( + strings("answers_too_long").format(answerlink=answerlink.get("full_url")), + disable_web_page_preview=True, + ) + else: + await bmsg.edit_msg(f"{html.escape(answer)}\nPowered by: Gemini 1.5 Flash") + else: + async for chunk in response: + if not chunk.choices or not chunk.choices[0].delta.content: + continue + num += 1 + answer += chunk.choices[0].delta.content + if num == 30 and len(answer) < 4000: + await bmsg.edit_msg(html.escape(answer)) + await asyncio.sleep(1.5) + num = 0 + if len(answer) > 4000: + answerlink = await privatebinapi.send_async("https://bin.yasirweb.eu.org", text=answer, expiration="1week", formatting="markdown") + await bmsg.edit_msg( + strings("answers_too_long").format(answerlink=answerlink.get("full_url")), + disable_web_page_preview=True, + ) + else: + await bmsg.edit_msg(f"{html.escape(answer)}\n\nPowered by: GPT 4o") + except APIConnectionError as e: + await bmsg.edit_msg(f"The server could not be reached because {e.__cause__}") + return None + except RateLimitError as e: + if "billing details" in str(e): + return await bmsg.edit_msg( + "This openai key from this bot has expired, please give openai key donation for bot owner." + ) + await bmsg.edit_msg("You're got rate limit, please try again later.") + return None + except APIStatusError as e: + await bmsg.edit_msg( + f"Another {e.status_code} status code was received with response {e.response}" + ) + return None + except Exception as e: + await bmsg.edit_msg(f"ERROR: {e}") + return None + return answer + + +@app.on_message(filters.command("ai", COMMAND_HANDLER) & pyro_cooldown.wait(10)) +@app.on_bot_business_message( + filters.command("ai", COMMAND_HANDLER) & pyro_cooldown.wait(10) +) +@use_chat_lang() +async def gemini_chatbot(_, ctx: Message, strings): + if len(ctx.command) == 1: + return await ctx.reply_msg( + strings("no_question").format(cmd=ctx.command[0]), quote=True, del_in=5 + ) + if not GOOGLEAI_KEY: + return await ctx.reply_msg("GOOGLEAI_KEY env is missing!!!") + uid = ctx.from_user.id if ctx.from_user else ctx.sender_chat.id + msg = await ctx.reply_msg(strings("find_answers_str"), quote=True) + if uid not in gemini_conversations: + gemini_conversations[uid] = [{"role": "system", "content": "Kamu adalah AI dengan karakter mirip kucing bernama MissKaty AI yang diciptakan oleh Yasir untuk membantu manusia mencari informasi."}, {"role": "user", "content": ctx.input}] + else: + gemini_conversations[uid].append({"role": "user", "content": ctx.input}) + ai_response = await get_openai_stream_response(False, GOOGLEAI_KEY, "https://gemini.yasirapi.eu.org/v1", "gemini-1.5-flash", gemini_conversations[uid], msg, strings) + if not ai_response: + gemini_conversations[uid].pop() + if len(gemini_conversations[uid]) == 1: + gemini_conversations.pop(uid) + return + gemini_conversations[uid].append({"role": "assistant", "content": ai_response}) + +@app.on_message(filters.command("ask", COMMAND_HANDLER) & pyro_cooldown.wait(10)) +@use_chat_lang() +async def openai_chatbot(self, ctx: Message, strings): + if len(ctx.command) == 1: + return await ctx.reply_msg( + strings("no_question").format(cmd=ctx.command[0]), quote=True, del_in=5 + ) + if not OPENAI_KEY: + return await ctx.reply_msg("OPENAI_KEY env is missing!!!") + uid = ctx.from_user.id if ctx.from_user else ctx.sender_chat.id + is_in_gap, _ = await check_time_gap(uid) + if is_in_gap and (uid not in SUDO): + return await ctx.reply_msg(strings("dont_spam"), del_in=5) + pertanyaan = ctx.input + msg = await ctx.reply_msg(strings("find_answers_str"), quote=True) + if uid not in gptai_conversations: + gptai_conversations[uid] = [{"role": "system", "content": "Kamu adalah AI dengan karakter mirip kucing bernama MissKaty AI yang diciptakan oleh Yasir untuk membantu manusia mencari informasi."}, {"role": "user", "content": pertanyaan}] + else: + gptai_conversations[uid].append({"role": "user", "content": pertanyaan}) + ai_response = await get_openai_stream_response(True, OPENAI_KEY, "https://models.inference.ai.azure.com" if uid in SUDO else "https://duckai.yasirapi.eu.org/v1", "gpt-4o" if uid in SUDO else "gpt-4o-mini", gptai_conversations[uid], msg, strings) + if not ai_response: + gptai_conversations[uid].pop() + if len(gptai_conversations[uid]) == 1: + gptai_conversations.pop(uid) + return + gptai_conversations[uid].append({"role": "assistant", "content": ai_response}) diff --git a/misskaty/plugins/dev.py b/misskaty/plugins/dev.py index d797a088..88bf9edf 100644 --- a/misskaty/plugins/dev.py +++ b/misskaty/plugins/dev.py @@ -1,658 +1,658 @@ -import asyncio -import contextlib -import html -import io -import json -import os -import pickle -import platform -import privatebinapi -import re -import sys -import traceback -from datetime import datetime -from inspect import getfullargspec -from logging import getLogger -from shutil import disk_usage -from time import time -from typing import Any, Optional, Tuple - -import aiohttp -import cloudscraper -import requests -from apscheduler.schedulers.asyncio import AsyncIOScheduler -from bs4 import BeautifulSoup -from PIL import Image, ImageDraw, ImageFont -from psutil import Process, boot_time, cpu_count, cpu_percent -from psutil import disk_usage as disk_usage_percent -from psutil import net_io_counters, virtual_memory -from pyrogram import Client -from pyrogram import __version__ as pyrover -from pyrogram import enums, filters -from pyrogram.errors import ( - ChatSendPhotosForbidden, - ChatSendPlainForbidden, - FloodWait, - MessageTooLong, - PeerIdInvalid, -) -from pyrogram.raw.types import UpdateBotStopped -from pyrogram.types import ( - InlineKeyboardButton, - InlineKeyboardMarkup, - InputMediaPhoto, - LabeledPrice, - Message, - PreCheckoutQuery, -) - -from database.gban_db import add_gban_user, is_gbanned_user, remove_gban_user -from database.users_chats_db import db -from misskaty import BOT_NAME, app, botStartTime, misskaty_version, user -from misskaty.core.decorator import new_task -from misskaty.helper.eval_helper import format_exception, meval -from misskaty.helper.functions import extract_user, extract_user_and_reason -from misskaty.helper.http import fetch -from misskaty.helper.human_read import get_readable_file_size, get_readable_time -from misskaty.helper.localization import use_chat_lang -from misskaty.vars import AUTO_RESTART, COMMAND_HANDLER, LOG_CHANNEL, SUDO - -__MODULE__ = "DevCommand" -__HELP__ = """ -**For Owner Bot Only.** -/run [args] - Run eval CMD -/logs [int] - Check logs bot -/shell [args] - Run Exec/Terminal CMD -/download [link/reply_to_telegram_file] - Download file from Telegram -/disablechat [chat id] - Remove blacklist group -/enablechat [chat id] - Add Blacklist group -/banuser [chat id] - Ban user and block user so cannot use bot -/unbanuser [chat id] - Unban user and make their can use bot again -/gban - To Ban A User Globally. -/ungban - To remove ban user globbaly. -/restart - update and restart bot. - -**For Public Use** -/stats - Check statistic bot -/json - Send structure message Telegram in JSON using Pyrogram Style. -""" - -var = {} -teskode = {} -LOGGER = getLogger("MissKaty") - - -async def edit_or_reply(self, msg, **kwargs): - func = msg.edit if not self.me.is_bot else msg.reply - spec = getfullargspec(func.__wrapped__).args - await func(**{k: v for k, v in kwargs.items() if k in spec}) - - -@app.on_message(filters.command(["privacy"], COMMAND_HANDLER)) -@use_chat_lang() -async def privacy_policy(self: Client, ctx: Message, strings): - await ctx.reply_msg(strings("privacy_policy").format(botname=self.me.first_name), message_effect_id=5104841245755180586 if ctx.chat.type.value == "private" else None) - - -@app.on_message(filters.command(["stars"], COMMAND_HANDLER)) -async def star_donation(self: Client, ctx: Message): - amount = ctx.command[1] if len(ctx.command) == 2 and ctx.command[1].isdigit() else 5 - await self.send_invoice( - ctx.chat.id, - title="MissKaty Donate", - description="You can give me donation via star", - currency="XTR", - prices=[LabeledPrice(label="Donation", amount=amount)], - message_thread_id=ctx.message_thread_id, - payload="stars", - ) - - -@app.on_pre_checkout_query() -async def pre_checkout_query_handler(_: Client, query: PreCheckoutQuery): - await query.answer(success=True) - - -@app.on_message(filters.private, group=3) -async def successful_payment_handler(_: Client, message: Message): - if message.successful_payment: - await message.reply( - f"Thanks for support for {message.successful_payment.total_amount} {message.successful_payment.currency}! Your transaction ID is : {message.successful_payment.telegram_payment_charge_id}" - ) - - -@app.on_message(filters.command(["refund_star"], COMMAND_HANDLER)) -async def refund_star_payment(client: Client, message: Message): - if len(message.command) == 1: - return await message.reply_msg( - "Please input telegram_payment_charge_id after command." - ) - trx_id = message.command[1] - try: - await client.refund_star_payment(message.from_user.id, trx_id) - await message.reply_msg( - f"Great {message.from_user.mention}, your stars has been refunded to your balance." - ) - except Exception as e: - await message.reply_msg(e) - - -@app.on_message(filters.command(["logs"], COMMAND_HANDLER) & filters.user(SUDO)) -@use_chat_lang() -async def log_file(_, ctx: Message, strings): - """Send log file""" - msg = await ctx.reply_msg("Reading bot logs ...", quote=True) - if len(ctx.command) == 1: - try: - with open("MissKatyLogs.txt", "r") as file: - content = file.read() - pastelog = await privatebinapi.send_async("https://bin.yasirweb.eu.org", text=content, expiration="1week", formatting="syntaxhighlighting") - await msg.edit_msg( - f"Here the Logs\nlog size: {get_readable_file_size(os.path.getsize('MissKatyLogs.txt'))}" - ) - except Exception: - await ctx.reply_document( - "MissKatyLogs.txt", - caption="Log Bot MissKatyPyro", - reply_markup=InlineKeyboardMarkup( - [ - [ - InlineKeyboardButton( - strings("cl_btn"), - f"close#{ctx.from_user.id}", - ) - ] - ] - ), - ) - await msg.delete_msg() - elif len(ctx.command) == 2: - val = ctx.text.split() - tail = await shell_exec(f"tail -n {val[1]} -v MissKatyLogs.txt") - try: - await msg.edit_msg(f"
{html.escape(tail[0])}
") - except MessageTooLong: - with io.BytesIO(str.encode(tail[0])) as s: - s.name = "MissKatyLog-Tail.txt" - await ctx.reply_document(s) - await msg.delete() - else: - await msg.edit_msg("Unsupported parameter") - - -@app.on_message(filters.command(["donate"], COMMAND_HANDLER)) -async def donate(self: Client, ctx: Message): - try: - await self.send_photo( - ctx.chat.id, - "https://img.yasirweb.eu.org/file/ee74ce527fb8264b54691.jpg", - caption="Hi, If you find this bot useful, you can make a donation to the account below. Because this bot server uses VPS and is not free. Thank You..\n\nIndonesian Payment:\nQRIS: https://img.yasirweb.eu.org/file/ee74ce527fb8264b54691.jpg (Yasir Store)\nBank Jago: 109641845083 (Yasir Aris M)\n\nFor international people can use PayPal to support me or via GitHub Sponsor:\nhttps://paypal.me/yasirarism\nhttps://github.com/sponsors/yasirarism\n\nSource: @BeriKopi", - reply_to_message_id=ctx.id, - message_effect_id=5159385139981059251 - if ctx.chat.type.value == "private" - else None, - ) - except (ChatSendPlainForbidden, ChatSendPhotosForbidden): - await self.send_message( - LOG_CHANNEL, - f"❗️ WARNING\nI'm leaving from {ctx.chat.id} since i didn't have sufficient admin permissions.", - ) - await ctx.chat.leave() - - -@app.on_message( - filters.command(["balas"], COMMAND_HANDLER) & filters.user(SUDO) & filters.reply -) -async def balas(_, ctx: Message) -> "str": - pesan = ctx.input - await ctx.delete_msg() - await ctx.reply_msg(pesan, reply_to_message_id=ctx.reply_to_message.id) - - -@app.on_message(filters.command(["stats"], COMMAND_HANDLER)) -@new_task -async def server_stats(_, ctx: Message) -> "Message": - """ - Give system stats of the server. - """ - total, used, free = disk_usage(".") - process = Process(os.getpid()) - - botuptime = get_readable_time(time() - botStartTime) - osuptime = get_readable_time(time() - boot_time()) - currentTime = get_readable_time(time() - botStartTime) - botusage = f"{round(process.memory_info()[0]/1024 ** 2)} MB" - - upload = get_readable_file_size(net_io_counters().bytes_sent) - download = get_readable_file_size(net_io_counters().bytes_recv) - - cpu_percentage = cpu_percent() - cpu_counts = cpu_count() - - ram_percentage = virtual_memory().percent - ram_total = get_readable_file_size(virtual_memory().total) - ram_used = get_readable_file_size(virtual_memory().used) - - disk_percenatge = disk_usage_percent("/").percent - disk_total = get_readable_file_size(total) - disk_used = get_readable_file_size(used) - disk_free = get_readable_file_size(free) - - neofetch = (await shell_exec("neofetch --stdout"))[0] - - caption = f"{BOT_NAME} {misskaty_version} is Up and Running successfully.\n\n{neofetch}\n\n**OS Uptime:** {osuptime}\nBot Uptime: {currentTime}\n**Bot Usage:** {botusage}\n\n**Total Space:** {disk_total}\n**Free Space:** {disk_free}\n\n**Download:** {download}\n**Upload:** {upload}\n\nPyroFork Version: {pyrover}\nPython Version: {sys.version_info[0]}.{sys.version_info[1]}.{sys.version_info[2]} {sys.version_info[3].title()}" - - if "oracle" in platform.uname().release: - return await ctx.reply_msg(caption, quote=True) - - start = datetime.now() - msg = await ctx.reply_photo( - photo="https://te.legra.ph/file/30a82c22854971d0232c7.jpg", - caption=caption, - quote=True, - ) - end = datetime.now() - - image = Image.open("assets/statsbg.jpg").convert("RGB") - IronFont = ImageFont.truetype("assets/IronFont.otf", 42) - draw = ImageDraw.Draw(image) - - def draw_progressbar(coordinate, progress): - progress = 110 + (progress * 10.8) - draw.ellipse((105, coordinate - 25, 127, coordinate), fill="#FFFFFF") - draw.rectangle((120, coordinate - 25, progress, coordinate), fill="#FFFFFF") - draw.ellipse( - (progress - 7, coordinate - 25, progress + 15, coordinate), fill="#FFFFFF" - ) - - draw_progressbar(243, int(cpu_percentage)) - draw.text( - (225, 153), - f"( {cpu_counts} core, {cpu_percentage}% )", - (255, 255, 255), - font=IronFont, - ) - - draw_progressbar(395, int(disk_percenatge)) - draw.text( - (335, 302), - f"( {disk_used} / {disk_total}, {disk_percenatge}% )", - (255, 255, 255), - font=IronFont, - ) - - draw_progressbar(533, int(ram_percentage)) - draw.text( - (225, 445), - f"( {ram_used} / {ram_total} , {ram_percentage}% )", - (255, 255, 255), - font=IronFont, - ) - - draw.text((335, 600), f"{botuptime}", (255, 255, 255), font=IronFont) - draw.text( - (857, 607), - f"{(end-start).microseconds/1000} ms", - (255, 255, 255), - font=IronFont, - ) - - image.save("stats.png") - await msg.edit_media(media=InputMediaPhoto("stats.png", caption=caption)) - os.remove("stats.png") - - -# Gban -@app.on_message(filters.command("gban", COMMAND_HANDLER) & filters.user(SUDO)) -async def ban_globally(self: Client, ctx: Message): - user_id, reason = await extract_user_and_reason(ctx) - if not user_id: - return await ctx.reply_text("I can't find that user.") - if not reason: - return await ctx.reply("No reason provided.") - - try: - getuser = await app.get_users(user_id) - user_mention = getuser.mention - user_id = user.id - except PeerIdInvalid: - user_mention = int(user_id) - user_id = int(user_id) - - from_user = ctx.from_user - - if user_id in [from_user.id, self.me.id] or user_id in SUDO: - return await ctx.reply_text("I can't ban that user.") - served_chats = await db.get_all_chats() - m = await ctx.reply_text( - f"**Banning {user_mention} Globally! This may take several times.**" - ) - await add_gban_user(user_id) - number_of_chats = 0 - async for served_chat in served_chats: - try: - await app.ban_chat_member(served_chat["id"], user_id) - number_of_chats += 1 - await asyncio.sleep(1) - except FloodWait as e: - await asyncio.sleep(int(e.value)) - except Exception: - pass - with contextlib.suppress(Exception): - await app.send_message( - user_id, - f"Hello, You have been globally banned by {from_user.mention}, You can appeal for this ban by talking to him.", - ) - await m.edit(f"Banned {user_mention} Globally!") - ban_text = f""" -__**New Global Ban**__ -**Origin:** {ctx.chat.title} [`{ctx.chat.id}`] -**Admin:** {from_user.mention} -**Banned User:** {user_mention} -**Banned User ID:** `{user_id}` -**Reason:** __{reason}__ -**Chats:** `{number_of_chats}`""" - try: - m2 = await app.send_message( - LOG_CHANNEL, - text=ban_text, - disable_web_page_preview=True, - ) - await m.edit( - f"Banned {user_mention} Globally!\nAction Log: {m2.link}", - disable_web_page_preview=True, - ) - except Exception: - await ctx.reply_text( - "User Gbanned, But This Gban Action Wasn't Logged, Add Me In LOG_CHANNEL" - ) - - -# Ungban -@app.on_message(filters.command("ungban", COMMAND_HANDLER) & filters.user(SUDO)) -async def unban_globally(_, ctx: Message): - user_id = await extract_user(ctx) - if not user_id: - return await ctx.reply_text("I can't find that user.") - try: - getuser = await app.get_users(user_id) - user_mention = getuser.mention - user_id = user.id - except PeerIdInvalid: - user_mention = int(user_id) - user_id = int(user_id) - - is_gbanned = await is_gbanned_user(user_id) - if not is_gbanned: - await ctx.reply_text("I don't remember Gbanning him.") - else: - await remove_gban_user(user_id) - await ctx.reply_text(f"Lifted {user_mention}'s Global Ban.'") - - -@app.on_message( - filters.command(["shell", "sh", "term"], COMMAND_HANDLER) & filters.user(SUDO) -) -@app.on_edited_message( - filters.command(["shell", "sh", "term"], COMMAND_HANDLER) - & filters.user(SUDO) - & ~filters.react -) -@user.on_message(filters.command(["shell", "sh", "term"], ".") & filters.me) -@use_chat_lang() -async def shell_cmd(self: Client, ctx: Message, strings): - if len(ctx.command) == 1: - return await edit_or_reply(self, ctx, text=strings("no_cmd")) - msg = ( - await ctx.edit_msg(strings("run_exec")) - if not self.me.is_bot - else await ctx.reply_msg(strings("run_exec")) - ) - shell = (await shell_exec(ctx.input))[0] - if len(shell) > 3000: - with io.BytesIO(str.encode(shell)) as doc: - doc.name = "shell_output.txt" - await ctx.reply_document( - document=doc, - caption=f"{ctx.input[: 4096 // 4 - 1]}", - file_name=doc.name, - reply_markup=InlineKeyboardMarkup( - [ - [ - InlineKeyboardButton( - text=strings("cl_btn"), - callback_data=f"close#{ctx.from_user.id if ctx.from_user else self.me.id}", - ) - ] - ] - ), - ) - await msg.delete_msg() - elif len(shell) != 0: - await edit_or_reply( - self, - ctx, - text=html.escape(shell), - parse_mode=enums.ParseMode.HTML, - reply_markup=InlineKeyboardMarkup( - [ - [ - InlineKeyboardButton( - text=strings("cl_btn"), - callback_data=f"close#{ctx.from_user.id if ctx.from_user else self.me.id}", - ) - ] - ] - ), - ) - if self.me.is_bot: - await msg.delete_msg() - else: - await ctx.reply_msg(strings("no_reply"), del_in=5) - - -@app.on_message( - ( - filters.command(["ev", "run", "myeval"], COMMAND_HANDLER) - | filters.regex(r"app.run\(\)$") - ) - & filters.user(SUDO) -) -@app.on_edited_message( - ( - filters.command(["ev", "run", "meval"], COMMAND_HANDLER) - | filters.regex(r"app.run\(\)$") - ) - & filters.user(SUDO) - & ~filters.react -) -@user.on_message(filters.command(["ev", "run", "meval"], ".") & filters.me) -@use_chat_lang() -async def cmd_eval(self: Client, ctx: Message, strings) -> Optional[str]: - if (ctx.command and len(ctx.command) == 1) or ctx.text == "app.run()": - return await edit_or_reply(self, ctx, text=strings("no_eval")) - status_message = ( - await ctx.edit_msg(strings("run_eval")) - if not self.me.is_bot - else await ctx.reply_msg(strings("run_eval"), quote=True) - ) - code = ( - ctx.text.split(maxsplit=1)[1] - if ctx.command - else ctx.text.split("\napp.run()")[0] - ) - out_buf = io.StringIO() - out = "" - humantime = get_readable_time - - async def _eval() -> Tuple[str, Optional[str]]: - # Message sending helper for convenience - async def send(*args: Any, **kwargs: Any) -> Message: - return await ctx.reply_msg(*args, **kwargs) - - # Print wrapper to capture output - # We don't override sys.stdout to avoid interfering with other output - def _print(*args: Any, **kwargs: Any) -> None: - if "file" not in kwargs: - kwargs["file"] = out_buf - return print(*args, **kwargs) - - def _help(*args: Any, **kwargs: Any) -> None: - with contextlib.redirect_stdout(out_buf): - help(*args, **kwargs) - - eval_vars = { - "self": self, - "humantime": humantime, - "ctx": ctx, - "var": var, - "teskode": teskode, - "re": re, - "os": os, - "asyncio": asyncio, - "cloudscraper": cloudscraper, - "json": json, - "aiohttp": aiohttp, - "print": _print, - "send": send, - "stdout": out_buf, - "traceback": traceback, - "fetch": fetch, - "r": ctx.reply_to_message, - "requests": requests, - "soup": BeautifulSoup, - "h": _help, - } - eval_vars.update(var) - eval_vars.update(teskode) - try: - return "", await meval(code, globals(), **eval_vars) - except Exception as e: # skipcq: PYL-W0703 - # Find first traceback frame involving the snippet - first_snip_idx = -1 - tb = traceback.extract_tb(e.__traceback__) - for i, frame in enumerate(tb): - if frame.filename == "" or frame.filename.endswith("ast.py"): - first_snip_idx = i - break - # Re-raise exception if it wasn't caused by the snippet - # Return formatted stripped traceback - stripped_tb = tb[first_snip_idx:] - formatted_tb = format_exception(e, tb=stripped_tb) - return "⚠️ Error while executing snippet\n\n", formatted_tb - - before = time() - prefix, result = await _eval() - after = time() - # Always write result if no output has been collected thus far - if not out_buf.getvalue() or result is not None: - print(result, file=out_buf) - el_us = after - before - try: - el_str = get_readable_time(el_us) - except: - el_str = "1s" - if not el_str or el_str is None: - el_str = "0.1s" - - out = out_buf.getvalue() - # Strip only ONE final newline to compensate for our message formatting - if out.endswith("\n"): - out = out[:-1] - final_output = f"{prefix}INPUT:\n
{html.escape(code)}
\nOUTPUT:\n
{html.escape(out)}
\nExecuted Time: {el_str}" - if len(final_output) > 4096: - with io.BytesIO(str.encode(out)) as out_file: - out_file.name = "MissKatyEval.txt" - await ctx.reply_document( - document=out_file, - caption=f"{code[: 4096 // 4 - 1]}", - disable_notification=True, - thumb="assets/thumb.jpg", - reply_markup=InlineKeyboardMarkup( - [ - [ - InlineKeyboardButton( - text=strings("cl_btn"), - callback_data=f"close#{ctx.from_user.id if ctx.from_user else self.me.id}", - ) - ] - ] - ), - ) - await status_message.delete_msg() - else: - await edit_or_reply( - self, - ctx, - text=final_output, - parse_mode=enums.ParseMode.HTML, - reply_markup=InlineKeyboardMarkup( - [ - [ - InlineKeyboardButton( - text=strings("cl_btn"), - callback_data=f"close#{ctx.from_user.id if ctx.from_user else self.me.id}", - ) - ] - ] - ), - ) - if self.me.is_bot: - await status_message.delete_msg() - - -# Update and restart bot -@app.on_message(filters.command(["restart"], COMMAND_HANDLER) & filters.user(SUDO)) -@use_chat_lang() -async def update_restart(_, ctx: Message, strings): - msg = await ctx.reply_msg(strings("up_and_rest")) - await shell_exec("python3 update.py") - with open("restart.pickle", "wb") as status: - pickle.dump([ctx.chat.id, msg.id], status) - os.execvp(sys.executable, [sys.executable, "-m", "misskaty"]) - - -@app.on_raw_update(group=-99) -async def updtebot(client, update, users, _): - if isinstance(update, UpdateBotStopped): - niuser = users[update.user_id] - if update.stopped and await db.is_user_exist(niuser.id): - await db.delete_user(niuser.id) - await client.send_msg( - LOG_CHANNEL, - f"{niuser.first_name} ({niuser.id}) " - f"{'BLOCKED' if update.stopped else 'UNBLOCKED'} the bot at " - f"{datetime.fromtimestamp(update.date)}", - ) - - -async def aexec(code, c, m): - exec( - "async def __aexec(c, m): " - + "\n p = print" - + "\n replied = m.reply_to_message" - + "".join(f"\n {l_}" for l_ in code.split("\n")) - ) - return await locals()["__aexec"](c, m) - - -async def shell_exec(code, treat=True): - process = await asyncio.create_subprocess_shell( - code, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.STDOUT - ) - - stdout = (await process.communicate())[0] - if treat: - stdout = stdout.decode().strip() - return stdout, process - - -async def auto_restart(): - await shell_exec("python3 update.py") - os.execvp(sys.executable, [sys.executable, "-m", "misskaty"]) - - -if AUTO_RESTART: - scheduler = AsyncIOScheduler(timezone="Asia/Jakarta") - scheduler.add_job(auto_restart, trigger="interval", days=3) - scheduler.start() +import asyncio +import contextlib +import html +import io +import json +import os +import pickle +import platform +import privatebinapi +import re +import sys +import traceback +from datetime import datetime +from inspect import getfullargspec +from logging import getLogger +from shutil import disk_usage +from time import time +from typing import Any, Optional, Tuple + +import aiohttp +import cloudscraper +import requests +from apscheduler.schedulers.asyncio import AsyncIOScheduler +from bs4 import BeautifulSoup +from PIL import Image, ImageDraw, ImageFont +from psutil import Process, boot_time, cpu_count, cpu_percent +from psutil import disk_usage as disk_usage_percent +from psutil import net_io_counters, virtual_memory +from pyrogram import Client +from pyrogram import __version__ as pyrover +from pyrogram import enums, filters +from pyrogram.errors import ( + ChatSendPhotosForbidden, + ChatSendPlainForbidden, + FloodWait, + MessageTooLong, + PeerIdInvalid, +) +from pyrogram.raw.types import UpdateBotStopped +from pyrogram.types import ( + InlineKeyboardButton, + InlineKeyboardMarkup, + InputMediaPhoto, + LabeledPrice, + Message, + PreCheckoutQuery, +) + +from database.gban_db import add_gban_user, is_gbanned_user, remove_gban_user +from database.users_chats_db import db +from misskaty import BOT_NAME, app, botStartTime, misskaty_version, user +from misskaty.core.decorator import new_task +from misskaty.helper.eval_helper import format_exception, meval +from misskaty.helper.functions import extract_user, extract_user_and_reason +from misskaty.helper.http import fetch +from misskaty.helper.human_read import get_readable_file_size, get_readable_time +from misskaty.helper.localization import use_chat_lang +from misskaty.vars import AUTO_RESTART, COMMAND_HANDLER, LOG_CHANNEL, SUDO + +__MODULE__ = "DevCommand" +__HELP__ = """ +**For Owner Bot Only.** +/run [args] - Run eval CMD +/logs [int] - Check logs bot +/shell [args] - Run Exec/Terminal CMD +/download [link/reply_to_telegram_file] - Download file from Telegram +/disablechat [chat id] - Remove blacklist group +/enablechat [chat id] - Add Blacklist group +/banuser [chat id] - Ban user and block user so cannot use bot +/unbanuser [chat id] - Unban user and make their can use bot again +/gban - To Ban A User Globally. +/ungban - To remove ban user globbaly. +/restart - update and restart bot. + +**For Public Use** +/stats - Check statistic bot +/json - Send structure message Telegram in JSON using Pyrogram Style. +""" + +var = {} +teskode = {} +LOGGER = getLogger("MissKaty") + + +async def edit_or_reply(self, msg, **kwargs): + func = msg.edit if not self.me.is_bot else msg.reply + spec = getfullargspec(func.__wrapped__).args + await func(**{k: v for k, v in kwargs.items() if k in spec}) + + +@app.on_message(filters.command(["privacy"], COMMAND_HANDLER)) +@use_chat_lang() +async def privacy_policy(self: Client, ctx: Message, strings): + await ctx.reply_msg(strings("privacy_policy").format(botname=self.me.first_name), message_effect_id=5104841245755180586 if ctx.chat.type.value == "private" else None) + + +@app.on_message(filters.command(["stars"], COMMAND_HANDLER)) +async def star_donation(self: Client, ctx: Message): + amount = ctx.command[1] if len(ctx.command) == 2 and ctx.command[1].isdigit() else 5 + await self.send_invoice( + ctx.chat.id, + title="MissKaty Donate", + description="You can give me donation via star", + currency="XTR", + prices=[LabeledPrice(label="Donation", amount=amount)], + message_thread_id=ctx.message_thread_id, + payload="stars", + ) + + +@app.on_pre_checkout_query() +async def pre_checkout_query_handler(_: Client, query: PreCheckoutQuery): + await query.answer(success=True) + + +@app.on_message(filters.private, group=3) +async def successful_payment_handler(_: Client, message: Message): + if message.successful_payment: + await message.reply( + f"Thanks for support for {message.successful_payment.total_amount} {message.successful_payment.currency}! Your transaction ID is : {message.successful_payment.telegram_payment_charge_id}" + ) + + +@app.on_message(filters.command(["refund_star"], COMMAND_HANDLER)) +async def refund_star_payment(client: Client, message: Message): + if len(message.command) == 1: + return await message.reply_msg( + "Please input telegram_payment_charge_id after command." + ) + trx_id = message.command[1] + try: + await client.refund_star_payment(message.from_user.id, trx_id) + await message.reply_msg( + f"Great {message.from_user.mention}, your stars has been refunded to your balance." + ) + except Exception as e: + await message.reply_msg(e) + + +@app.on_message(filters.command(["logs"], COMMAND_HANDLER) & filters.user(SUDO)) +@use_chat_lang() +async def log_file(_, ctx: Message, strings): + """Send log file""" + msg = await ctx.reply_msg("Reading bot logs ...", quote=True) + if len(ctx.command) == 1: + try: + with open("MissKatyLogs.txt", "r") as file: + content = file.read() + pastelog = await privatebinapi.send_async("https://bin.yasirweb.eu.org", text=content, expiration="1week", formatting="syntaxhighlighting") + await msg.edit_msg( + f"Here the Logs\nlog size: {get_readable_file_size(os.path.getsize('MissKatyLogs.txt'))}" + ) + except Exception: + await ctx.reply_document( + "MissKatyLogs.txt", + caption="Log Bot MissKatyPyro", + reply_markup=InlineKeyboardMarkup( + [ + [ + InlineKeyboardButton( + strings("cl_btn"), + f"close#{ctx.from_user.id}", + ) + ] + ] + ), + ) + await msg.delete_msg() + elif len(ctx.command) == 2: + val = ctx.text.split() + tail = await shell_exec(f"tail -n {val[1]} -v MissKatyLogs.txt") + try: + await msg.edit_msg(f"
{html.escape(tail[0])}
") + except MessageTooLong: + with io.BytesIO(str.encode(tail[0])) as s: + s.name = "MissKatyLog-Tail.txt" + await ctx.reply_document(s) + await msg.delete() + else: + await msg.edit_msg("Unsupported parameter") + + +@app.on_message(filters.command(["donate"], COMMAND_HANDLER)) +async def donate(self: Client, ctx: Message): + try: + await self.send_photo( + ctx.chat.id, + "https://img.yasirweb.eu.org/file/ee74ce527fb8264b54691.jpg", + caption="Hi, If you find this bot useful, you can make a donation to the account below. Because this bot server uses VPS and is not free. Thank You..\n\nIndonesian Payment:\nQRIS: https://img.yasirweb.eu.org/file/ee74ce527fb8264b54691.jpg (Yasir Store)\nBank Jago: 109641845083 (Yasir Aris M)\n\nFor international people can use PayPal to support me or via GitHub Sponsor:\nhttps://paypal.me/yasirarism\nhttps://github.com/sponsors/yasirarism\n\nSource: @BeriKopi", + reply_to_message_id=ctx.id, + message_effect_id=5159385139981059251 + if ctx.chat.type.value == "private" + else None, + ) + except (ChatSendPlainForbidden, ChatSendPhotosForbidden): + await self.send_message( + LOG_CHANNEL, + f"❗️ WARNING\nI'm leaving from {ctx.chat.id} since i didn't have sufficient admin permissions.", + ) + await ctx.chat.leave() + + +@app.on_message( + filters.command(["balas"], COMMAND_HANDLER) & filters.user(SUDO) & filters.reply +) +async def balas(_, ctx: Message) -> "str": + pesan = ctx.input + await ctx.delete_msg() + await ctx.reply_msg(pesan, reply_to_message_id=ctx.reply_to_message.id) + + +@app.on_message(filters.command(["stats"], COMMAND_HANDLER)) +@new_task +async def server_stats(_, ctx: Message) -> "Message": + """ + Give system stats of the server. + """ + total, used, free = disk_usage(".") + process = Process(os.getpid()) + + botuptime = get_readable_time(time() - botStartTime) + osuptime = get_readable_time(time() - boot_time()) + currentTime = get_readable_time(time() - botStartTime) + botusage = f"{round(process.memory_info()[0]/1024 ** 2)} MB" + + upload = get_readable_file_size(net_io_counters().bytes_sent) + download = get_readable_file_size(net_io_counters().bytes_recv) + + cpu_percentage = cpu_percent() + cpu_counts = cpu_count() + + ram_percentage = virtual_memory().percent + ram_total = get_readable_file_size(virtual_memory().total) + ram_used = get_readable_file_size(virtual_memory().used) + + disk_percenatge = disk_usage_percent("/").percent + disk_total = get_readable_file_size(total) + disk_used = get_readable_file_size(used) + disk_free = get_readable_file_size(free) + + neofetch = (await shell_exec("neofetch --stdout"))[0] + + caption = f"{BOT_NAME} {misskaty_version} is Up and Running successfully.\n\n{neofetch}\n\n**OS Uptime:** {osuptime}\nBot Uptime: {currentTime}\n**Bot Usage:** {botusage}\n\n**Total Space:** {disk_total}\n**Free Space:** {disk_free}\n\n**Download:** {download}\n**Upload:** {upload}\n\nPyroFork Version: {pyrover}\nPython Version: {sys.version_info[0]}.{sys.version_info[1]}.{sys.version_info[2]} {sys.version_info[3].title()}" + + if "oracle" in platform.uname().release: + return await ctx.reply_msg(caption, quote=True) + + start = datetime.now() + msg = await ctx.reply_photo( + photo="https://te.legra.ph/file/30a82c22854971d0232c7.jpg", + caption=caption, + quote=True, + ) + end = datetime.now() + + image = Image.open("assets/statsbg.jpg").convert("RGB") + IronFont = ImageFont.truetype("assets/IronFont.otf", 42) + draw = ImageDraw.Draw(image) + + def draw_progressbar(coordinate, progress): + progress = 110 + (progress * 10.8) + draw.ellipse((105, coordinate - 25, 127, coordinate), fill="#FFFFFF") + draw.rectangle((120, coordinate - 25, progress, coordinate), fill="#FFFFFF") + draw.ellipse( + (progress - 7, coordinate - 25, progress + 15, coordinate), fill="#FFFFFF" + ) + + draw_progressbar(243, int(cpu_percentage)) + draw.text( + (225, 153), + f"( {cpu_counts} core, {cpu_percentage}% )", + (255, 255, 255), + font=IronFont, + ) + + draw_progressbar(395, int(disk_percenatge)) + draw.text( + (335, 302), + f"( {disk_used} / {disk_total}, {disk_percenatge}% )", + (255, 255, 255), + font=IronFont, + ) + + draw_progressbar(533, int(ram_percentage)) + draw.text( + (225, 445), + f"( {ram_used} / {ram_total} , {ram_percentage}% )", + (255, 255, 255), + font=IronFont, + ) + + draw.text((335, 600), f"{botuptime}", (255, 255, 255), font=IronFont) + draw.text( + (857, 607), + f"{(end-start).microseconds/1000} ms", + (255, 255, 255), + font=IronFont, + ) + + image.save("stats.png") + await msg.edit_media(media=InputMediaPhoto("stats.png", caption=caption)) + os.remove("stats.png") + + +# Gban +@app.on_message(filters.command("gban", COMMAND_HANDLER) & filters.user(SUDO)) +async def ban_globally(self: Client, ctx: Message): + user_id, reason = await extract_user_and_reason(ctx) + if not user_id: + return await ctx.reply_text("I can't find that user.") + if not reason: + return await ctx.reply("No reason provided.") + + try: + getuser = await app.get_users(user_id) + user_mention = getuser.mention + user_id = user.id + except PeerIdInvalid: + user_mention = int(user_id) + user_id = int(user_id) + + from_user = ctx.from_user + + if user_id in [from_user.id, self.me.id] or user_id in SUDO: + return await ctx.reply_text("I can't ban that user.") + served_chats = await db.get_all_chats() + m = await ctx.reply_text( + f"**Banning {user_mention} Globally! This may take several times.**" + ) + await add_gban_user(user_id) + number_of_chats = 0 + async for served_chat in served_chats: + try: + await app.ban_chat_member(served_chat["id"], user_id) + number_of_chats += 1 + await asyncio.sleep(1) + except FloodWait as e: + await asyncio.sleep(int(e.value)) + except Exception: + pass + with contextlib.suppress(Exception): + await app.send_message( + user_id, + f"Hello, You have been globally banned by {from_user.mention}, You can appeal for this ban by talking to him.", + ) + await m.edit(f"Banned {user_mention} Globally!") + ban_text = f""" +__**New Global Ban**__ +**Origin:** {ctx.chat.title} [`{ctx.chat.id}`] +**Admin:** {from_user.mention} +**Banned User:** {user_mention} +**Banned User ID:** `{user_id}` +**Reason:** __{reason}__ +**Chats:** `{number_of_chats}`""" + try: + m2 = await app.send_message( + LOG_CHANNEL, + text=ban_text, + disable_web_page_preview=True, + ) + await m.edit( + f"Banned {user_mention} Globally!\nAction Log: {m2.link}", + disable_web_page_preview=True, + ) + except Exception: + await ctx.reply_text( + "User Gbanned, But This Gban Action Wasn't Logged, Add Me In LOG_CHANNEL" + ) + + +# Ungban +@app.on_message(filters.command("ungban", COMMAND_HANDLER) & filters.user(SUDO)) +async def unban_globally(_, ctx: Message): + user_id = await extract_user(ctx) + if not user_id: + return await ctx.reply_text("I can't find that user.") + try: + getuser = await app.get_users(user_id) + user_mention = getuser.mention + user_id = user.id + except PeerIdInvalid: + user_mention = int(user_id) + user_id = int(user_id) + + is_gbanned = await is_gbanned_user(user_id) + if not is_gbanned: + await ctx.reply_text("I don't remember Gbanning him.") + else: + await remove_gban_user(user_id) + await ctx.reply_text(f"Lifted {user_mention}'s Global Ban.'") + + +@app.on_message( + filters.command(["shell", "sh", "term"], COMMAND_HANDLER) & filters.user(SUDO) +) +@app.on_edited_message( + filters.command(["shell", "sh", "term"], COMMAND_HANDLER) + & filters.user(SUDO) + & ~filters.react +) +@user.on_message(filters.command(["shell", "sh", "term"], ".") & filters.me) +@use_chat_lang() +async def shell_cmd(self: Client, ctx: Message, strings): + if len(ctx.command) == 1: + return await edit_or_reply(self, ctx, text=strings("no_cmd")) + msg = ( + await ctx.edit_msg(strings("run_exec")) + if not self.me.is_bot + else await ctx.reply_msg(strings("run_exec")) + ) + shell = (await shell_exec(ctx.input))[0] + if len(shell) > 3000: + with io.BytesIO(str.encode(shell)) as doc: + doc.name = "shell_output.txt" + await ctx.reply_document( + document=doc, + caption=f"{ctx.input[: 4096 // 4 - 1]}", + file_name=doc.name, + reply_markup=InlineKeyboardMarkup( + [ + [ + InlineKeyboardButton( + text=strings("cl_btn"), + callback_data=f"close#{ctx.from_user.id if ctx.from_user else self.me.id}", + ) + ] + ] + ), + ) + await msg.delete_msg() + elif len(shell) != 0: + await edit_or_reply( + self, + ctx, + text=html.escape(shell), + parse_mode=enums.ParseMode.HTML, + reply_markup=InlineKeyboardMarkup( + [ + [ + InlineKeyboardButton( + text=strings("cl_btn"), + callback_data=f"close#{ctx.from_user.id if ctx.from_user else self.me.id}", + ) + ] + ] + ), + ) + if self.me.is_bot: + await msg.delete_msg() + else: + await ctx.reply_msg(strings("no_reply"), del_in=5) + + +@app.on_message( + ( + filters.command(["ev", "run", "myeval"], COMMAND_HANDLER) + | filters.regex(r"app.run\(\)$") + ) + & filters.user(SUDO) +) +@app.on_edited_message( + ( + filters.command(["ev", "run", "meval"], COMMAND_HANDLER) + | filters.regex(r"app.run\(\)$") + ) + & filters.user(SUDO) + & ~filters.react +) +@user.on_message(filters.command(["ev", "run", "meval"], ".") & filters.me) +@use_chat_lang() +async def cmd_eval(self: Client, ctx: Message, strings) -> Optional[str]: + if (ctx.command and len(ctx.command) == 1) or ctx.text == "app.run()": + return await edit_or_reply(self, ctx, text=strings("no_eval")) + status_message = ( + await ctx.edit_msg(strings("run_eval")) + if not self.me.is_bot + else await ctx.reply_msg(strings("run_eval"), quote=True) + ) + code = ( + ctx.text.split(maxsplit=1)[1] + if ctx.command + else ctx.text.split("\napp.run()")[0] + ) + out_buf = io.StringIO() + out = "" + humantime = get_readable_time + + async def _eval() -> Tuple[str, Optional[str]]: + # Message sending helper for convenience + async def send(*args: Any, **kwargs: Any) -> Message: + return await ctx.reply_msg(*args, **kwargs) + + # Print wrapper to capture output + # We don't override sys.stdout to avoid interfering with other output + def _print(*args: Any, **kwargs: Any) -> None: + if "file" not in kwargs: + kwargs["file"] = out_buf + return print(*args, **kwargs) + + def _help(*args: Any, **kwargs: Any) -> None: + with contextlib.redirect_stdout(out_buf): + help(*args, **kwargs) + + eval_vars = { + "self": self, + "humantime": humantime, + "ctx": ctx, + "var": var, + "teskode": teskode, + "re": re, + "os": os, + "asyncio": asyncio, + "cloudscraper": cloudscraper, + "json": json, + "aiohttp": aiohttp, + "print": _print, + "send": send, + "stdout": out_buf, + "traceback": traceback, + "fetch": fetch, + "r": ctx.reply_to_message, + "requests": requests, + "soup": BeautifulSoup, + "h": _help, + } + eval_vars.update(var) + eval_vars.update(teskode) + try: + return "", await meval(code, globals(), **eval_vars) + except Exception as e: # skipcq: PYL-W0703 + # Find first traceback frame involving the snippet + first_snip_idx = -1 + tb = traceback.extract_tb(e.__traceback__) + for i, frame in enumerate(tb): + if frame.filename == "" or frame.filename.endswith("ast.py"): + first_snip_idx = i + break + # Re-raise exception if it wasn't caused by the snippet + # Return formatted stripped traceback + stripped_tb = tb[first_snip_idx:] + formatted_tb = format_exception(e, tb=stripped_tb) + return "⚠️ Error while executing snippet\n\n", formatted_tb + + before = time() + prefix, result = await _eval() + after = time() + # Always write result if no output has been collected thus far + if not out_buf.getvalue() or result is not None: + print(result, file=out_buf) + el_us = after - before + try: + el_str = get_readable_time(el_us) + except: + el_str = "1s" + if not el_str or el_str is None: + el_str = "0.1s" + + out = out_buf.getvalue() + # Strip only ONE final newline to compensate for our message formatting + if out.endswith("\n"): + out = out[:-1] + final_output = f"{prefix}INPUT:\n
{html.escape(code)}
\nOUTPUT:\n
{html.escape(out)}
\nExecuted Time: {el_str}" + if len(final_output) > 4096: + with io.BytesIO(str.encode(out)) as out_file: + out_file.name = "MissKatyEval.txt" + await ctx.reply_document( + document=out_file, + caption=f"{code[: 4096 // 4 - 1]}", + disable_notification=True, + thumb="assets/thumb.jpg", + reply_markup=InlineKeyboardMarkup( + [ + [ + InlineKeyboardButton( + text=strings("cl_btn"), + callback_data=f"close#{ctx.from_user.id if ctx.from_user else self.me.id}", + ) + ] + ] + ), + ) + await status_message.delete_msg() + else: + await edit_or_reply( + self, + ctx, + text=final_output, + parse_mode=enums.ParseMode.HTML, + reply_markup=InlineKeyboardMarkup( + [ + [ + InlineKeyboardButton( + text=strings("cl_btn"), + callback_data=f"close#{ctx.from_user.id if ctx.from_user else self.me.id}", + ) + ] + ] + ), + ) + if self.me.is_bot: + await status_message.delete_msg() + + +# Update and restart bot +@app.on_message(filters.command(["restart"], COMMAND_HANDLER) & filters.user(SUDO)) +@use_chat_lang() +async def update_restart(_, ctx: Message, strings): + msg = await ctx.reply_msg(strings("up_and_rest")) + await shell_exec("python3 update.py") + with open("restart.pickle", "wb") as status: + pickle.dump([ctx.chat.id, msg.id], status) + os.execvp(sys.executable, [sys.executable, "-m", "misskaty"]) + + +@app.on_raw_update(group=-99) +async def updtebot(client, update, users, _): + if isinstance(update, UpdateBotStopped): + niuser = users[update.user_id] + if update.stopped and await db.is_user_exist(niuser.id): + await db.delete_user(niuser.id) + await client.send_msg( + LOG_CHANNEL, + f"{niuser.first_name} ({niuser.id}) " + f"{'BLOCKED' if update.stopped else 'UNBLOCKED'} the bot at " + f"{datetime.fromtimestamp(update.date)}", + ) + + +async def aexec(code, c, m): + exec( + "async def __aexec(c, m): " + + "\n p = print" + + "\n replied = m.reply_to_message" + + "".join(f"\n {l_}" for l_ in code.split("\n")) + ) + return await locals()["__aexec"](c, m) + + +async def shell_exec(code, treat=True): + process = await asyncio.create_subprocess_shell( + code, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.STDOUT + ) + + stdout = (await process.communicate())[0] + if treat: + stdout = stdout.decode().strip() + return stdout, process + + +async def auto_restart(): + await shell_exec("python3 update.py") + os.execvp(sys.executable, [sys.executable, "-m", "misskaty"]) + + +if AUTO_RESTART: + scheduler = AsyncIOScheduler(timezone="Asia/Jakarta") + scheduler.add_job(auto_restart, trigger="interval", days=3) + scheduler.start() diff --git a/misskaty/plugins/paste.py b/misskaty/plugins/paste.py index 492c040e..7ac1c8b0 100644 --- a/misskaty/plugins/paste.py +++ b/misskaty/plugins/paste.py @@ -1,455 +1,455 @@ -""" -* @author Yasir Aris M -* @created 2022-12-01 09:12:27 -* @projectName MissKatyPyro -* Copyright @YasirPedia All rights reserved -""" -import privatebinapi -from json import loads as json_loads -from os import remove -from re import compile as compiles - -from pyrogram import filters -from pyrogram.types import InlineKeyboardButton, InlineKeyboardMarkup - -from misskaty import app -from misskaty.helper import fetch, post_to_telegraph, rentry -from misskaty.vars import COMMAND_HANDLER - -__MODULE__ = "Paste" -__HELP__ = """ -/paste [Text/Reply To Message] - Post text to My Pastebin. -/sbin [Text/Reply To Message] - Post text to Spacebin. -/neko [Text/Reply To Message] - Post text to Nekobin. -/tgraph [Text/Reply To Message] - Post text to Telegraph. -/imgbb [Images] - Upload image to ImgBB. -/rentry [Text/Reply To Message] - Post text to Rentry using markdown style. -""" - - -# Size Checker for Limit -def humanbytes(size: int): - """Convert Bytes To Bytes So That Human Can Read It""" - if not isinstance(size, int): - try: - pass - except ValueError: - size = None - if not size: - return "0 B" - size = int(size) - power = 2**10 - raised_to_pow = 0 - dict_power_n = { - 0: "", - 1: "K", - 2: "M", - 3: "G", - 4: "T", - 5: "P", - 6: "E", - 7: "Z", - 8: "Y", - } - while size > power: - size /= power - raised_to_pow += 1 - try: - real_size = f"{str(round(size, 2))} {dict_power_n[raised_to_pow]}B" - except KeyError: - real_size = "Can't Define Real Size !" - return real_size - - -# Pattern if extension supported, PR if want to add more -pattern = compiles(r"^text/|json$|yaml$|xml$|toml$|x-sh$|x-shellscript$|x-subrip$") - - -@app.on_message(filters.command(["tgraph"], COMMAND_HANDLER)) -async def telegraph_paste(_, message): - reply = message.reply_to_message - if not reply and len(message.command) < 2: - return await message.reply_msg( - f"**Reply To A Message With /{message.command[0]} or with command**", - del_in=6, - ) - - if message.from_user: - if message.from_user.username: - uname = f"@{message.from_user.username} [{message.from_user.id}]" - else: - uname = f"[{message.from_user.first_name}](tg://user?id={message.from_user.id}) [{message.from_user.id}]" - else: - uname = message.sender_chat.title - msg = await message.reply_msg("`Pasting to Telegraph...`") - data = "" - limit = 1024 * 1024 - if reply and not (reply.text or reply.document): - return await msg.edit_msg("**Telegraph upload has been disabled by Durov, use ImgBB command instead.**") - if reply and reply.document: - if reply.document.file_size > limit: - return await msg.edit_msg( - f"**You can only paste files smaller than {humanbytes(limit)}.**" - ) - if not pattern.search(reply.document.mime_type): - return await msg.edit_msg("**Only text files can be pasted.**") - file = await reply.download() - title = ( - message.text.split(None, 1)[1] - if len(message.command) > 1 - else "MissKaty Paste" - ) - try: - with open(file, "r") as text: - data = text.read() - remove(file) - except UnicodeDecodeError: - try: - remove(file) - except: - pass - return await msg.edit_msg("`File Not Supported !`") - elif reply and (reply.text or reply.caption): - title = ( - message.text.split(None, 1)[1] - if len(message.command) > 1 - else "MissKaty Paste" - ) - data = reply.text.html.replace("\n", "
") or reply.caption.html.replace( - "\n", "
" - ) - elif not reply and len(message.command) >= 2: - title = "MissKaty Paste" - data = message.text.split(None, 1)[1] - - try: - url = await post_to_telegraph(False, title, data) - except Exception as e: - return await msg.edit_msg(f"ERROR: {e}") - - if not url: - return await msg.edit_msg("Text Too Short Or File Problems") - button = [ - [InlineKeyboardButton("Open Link", url=url)], - [ - InlineKeyboardButton( - "Share Link", url=f"https://telegram.me/share/url?url={url}" - ) - ], - ] - - pasted = f"**Successfully pasted your data to Telegraph.\n\nPaste by {uname}**" - await msg.edit_msg(pasted, reply_markup=InlineKeyboardMarkup(button)) - - -@app.on_message(filters.command(["paste"], COMMAND_HANDLER)) -async def wastepaste(_, message): - reply = message.reply_to_message - target = str(message.command[0]).split("@", maxsplit=1)[0] - if not reply and len(message.command) < 2: - return await message.reply_msg( - f"**Reply To A Message With /{target} or with command**", del_in=6 - ) - - msg = await message.reply_msg("`Pasting to YasirBin...`") - data = "" - limit = 1024 * 1024 - if reply and reply.document: - if reply.document.file_size > limit: - return await msg.edit_msg( - f"**You can only paste files smaller than {humanbytes(limit)}.**" - ) - if not pattern.search(reply.document.mime_type): - return await msg.edit_msg("**Only text files can be pasted.**") - file = await reply.download() - try: - with open(file, "r") as text: - data = text.read() - remove(file) - except UnicodeDecodeError: - try: - remove(file) - except: - pass - return await msg.edit_msg("`File Not Supported !`") - elif reply and (reply.text or reply.caption): - data = reply.text or reply.caption - elif not reply and len(message.command) >= 2: - data = message.text.split(None, 1)[1] - - if message.from_user: - if message.from_user.username: - uname = f"@{message.from_user.username} [{message.from_user.id}]" - else: - uname = f"[{message.from_user.first_name}](tg://user?id={message.from_user.id}) [{message.from_user.id}]" - else: - uname = message.sender_chat.title - - try: - url = await privatebinapi.send_async("https://bin.yasirweb.eu.org", text=data, expiration="1week", formatting="markdown") - except Exception as e: - return await msg.edit_msg(f"ERROR: {e}") - - if not url: - return await msg.edit_msg("Text Too Short Or File Problems") - button = [ - [InlineKeyboardButton("Open Link", url=url["full_url"])], - [ - InlineKeyboardButton( - "Share Link", url=f"https://telegram.me/share/url?url={url['full_url']}" - ) - ], - ] - - pasted = f"**Successfully pasted your data to YasirBin.\n\nPaste by {uname}**" - await msg.edit_msg(pasted, reply_markup=InlineKeyboardMarkup(button)) - - -# Nekobin Paste -@app.on_message(filters.command(["neko"], COMMAND_HANDLER)) -async def nekopaste(_, message): - reply = message.reply_to_message - target = str(message.command[0]).split("@", maxsplit=1)[0] - if not reply and len(message.command) < 2: - return await message.reply_msg( - f"**Reply To A Message With /{target} or with command**", del_in=6 - ) - - msg = await message.reply_msg("`Pasting to Nekobin...`") - data = "" - limit = 1024 * 1024 - if reply and reply.document: - if reply.document.file_size > limit: - return await message.edit_msg( - f"**You can only paste files smaller than {humanbytes(limit)}.**" - ) - if not pattern.search(reply.document.mime_type): - return await message.edit_msg("**Only text files can be pasted.**") - file = await reply.download() - try: - with open(file, "r") as text: - data = text.read() - remove(file) - except UnicodeDecodeError: - try: - remove(file) - except: - pass - return await message.edit_msg("`File Not Supported !`") - elif reply and (reply.text or reply.caption): - data = reply.text.html or reply.caption.html - elif not reply and len(message.command) >= 2: - data = message.text.split(None, 1)[1] - - if message.from_user: - if message.from_user.username: - uname = f"@{message.from_user.username}" - else: - uname = ( - f"[{message.from_user.first_name}](tg://user?id={message.from_user.id})" - ) - else: - uname = message.sender_chat.title - - try: - x = ( - await fetch.post( - "https://bin.mayuri.my.id/api/documents", json={"content": data} - ) - ).json() - url = f"https://bin.mayuri.my.id/{x['result']['key']}" - except Exception as e: - return await msg.edit_msg(f"ERROR: {e}") - - if not url: - return await msg.edit_msg("Text Too Short Or File Problems") - button = [ - [InlineKeyboardButton("Open Link", url=url)], - [ - InlineKeyboardButton( - "Share Link", url=f"https://telegram.me/share/url?url={url}" - ) - ], - ] - - pasted = f"**Successfully pasted your data to Nekobin.\n\nPaste by {uname}**" - await msg.edit_msg(pasted, reply_markup=InlineKeyboardMarkup(button)) - - -# Paste as spacebin -@app.on_message(filters.command(["sbin"], COMMAND_HANDLER)) -async def spacebinn(_, message): - reply = message.reply_to_message - target = str(message.command[0]).split("@", maxsplit=1)[0] - if not reply and len(message.command) < 2: - return await message.reply_msg( - f"**Reply To A Message With /{target} or with command**", del_in=6 - ) - - msg = await message.reply_msg("`Pasting to Spacebin...`") - data = "" - limit = 1024 * 1024 - if reply and reply.document: - if reply.document.file_size > limit: - return await msg.edit_msg( - f"**You can only paste files smaller than {humanbytes(limit)}.**" - ) - if not pattern.search(reply.document.mime_type): - return await msg.edit_msg("**Only text files can be pasted.**") - file = await reply.download() - try: - with open(file, "r") as text: - data = text.read() - remove(file) - except UnicodeDecodeError: - try: - remove(file) - except: - pass - return await msg.edit_msg("`File Not Supported !`") - elif reply and (reply.text or reply.caption): - data = reply.text.html or reply.caption.html - elif not reply and len(message.command) >= 2: - data = message.text.split(None, 1)[1] - - if message.from_user: - if message.from_user.username: - uname = f"@{message.from_user.username}" - else: - uname = ( - f"[{message.from_user.first_name}](tg://user?id={message.from_user.id})" - ) - else: - uname = message.sender_chat.title - - try: - siteurl = "https://spaceb.in/api/" - response = await fetch.post(siteurl, json={"content": data, "extension": "txt"}) - response = response.json() - url = "https://spaceb.in/" + response["payload"]["id"] - except Exception as e: - return await msg.edit_msg(f"ERROR: {e}") - - if not url: - return await msg.edit_msg("Text Too Short Or File Problems") - button = [ - [InlineKeyboardButton("Open Link", url=url)], - [ - InlineKeyboardButton( - "Share Link", url=f"https://telegram.me/share/url?url={url}" - ) - ], - ] - - pasted = f"**Successfully pasted your data to Spacebin.\n\nPaste by {uname}**" - await msg.edit_msg(pasted, reply_markup=InlineKeyboardMarkup(button)) - - -# Rentry paste -@app.on_message(filters.command(["rentry"], COMMAND_HANDLER)) -async def rentrypaste(_, message): - reply = message.reply_to_message - target = str(message.command[0]).split("@", maxsplit=1)[0] - if not reply and len(message.command) < 2: - return await message.reply_msg( - f"**Reply To A Message With /{target} or with command**", del_in=6 - ) - - msg = await message.reply_msg("`Pasting to Rentry...`") - data = "" - limit = 1024 * 1024 - if reply and reply.document: - if reply.document.file_size > limit: - return await msg.edit_msg( - f"**You can only paste files smaller than {humanbytes(limit)}.**" - ) - if not pattern.search(reply.document.mime_type): - return await msg.edit_msg("**Only text files can be pasted.**") - file = await reply.download() - try: - with open(file, "r") as text: - data = text.read() - remove(file) - except UnicodeDecodeError: - try: - remove(file) - except: - pass - return await msg.edit_msg("`File Not Supported !`") - elif reply and (reply.text or reply.caption): - data = reply.text.markdown or reply.caption.markdown - elif not reply and len(message.command) >= 2: - data = message.text.split(None, 1)[1] - - if message.from_user: - if message.from_user.username: - uname = f"@{message.from_user.username}" - else: - uname = ( - f"[{message.from_user.first_name}](tg://user?id={message.from_user.id})" - ) - else: - uname = message.sender_chat.title - - try: - url = await rentry(data) - except Exception as e: - return await msg.edit(f"`{e}`") - - if not url: - return await msg.edit_msg("Text Too Short Or File Problems") - button = [ - [InlineKeyboardButton("Open Link", url=url)], - [ - InlineKeyboardButton( - "Share Link", url=f"https://telegram.me/share/url?url={url}" - ) - ], - ] - - pasted = f"**Successfully pasted your data to Rentry.\n\nPaste by {uname}**" - await msg.edit_msg(pasted, reply_markup=InlineKeyboardMarkup(button)) - - -# ImgBB Upload -@app.on_message(filters.command(["imgbb"], COMMAND_HANDLER)) -async def imgbb_upload(_, message): - reply = message.reply_to_message - if not reply and len(message.command) == 1: - return await message.edit_msg( - f"**Reply to a photo with /{message.command[0]} command to upload image on ImgBB.**", del_in=6 - ) - if not (reply.photo or (reply.document and reply.document.mime_type.startswith("image"))): - return await message.reply_msg("This command only support upload photo") - msg = await message.reply_msg("`Uploading image to ImgBB...`") - if message.from_user: - if message.from_user.username: - uname = f"@{message.from_user.username}" - else: - uname = ( - f"[{message.from_user.first_name}](tg://user?id={message.from_user.id})" - ) - else: - uname = message.sender_chat.title - - try: - path = await reply.download() - data = {"type": "file", "action": "upload"} - files = {"source": (path, open(path, "rb"), "images/jpeg")} - headers = {"origin": "https://imgbb.com", "referer": "https://imgbb.com/upload", "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36 Edg/107.0.1418.42"} - res = await fetch.post("https://imgbb.com/json", files=files, data=data, headers=headers) - remove(path) - url = f"https://ibb.co.com/{res.json()['image']['id_encoded']}" - button = [ - [InlineKeyboardButton("Open Link", url=url)], - [ - InlineKeyboardButton( - "Share Link", url=f"https://telegram.me/share/url?url={url}" - ) - ], - ] - - pasted = f"**Successfully pasted your images to ImgBB.\n\nPaste by {uname}**" - await msg.edit_msg(pasted, reply_markup=InlineKeyboardMarkup(button)) - except Exception as e: - await msg.edit_msg(f"ERROR: {e}") +""" +* @author Yasir Aris M +* @created 2022-12-01 09:12:27 +* @projectName MissKatyPyro +* Copyright @YasirPedia All rights reserved +""" +import privatebinapi +from json import loads as json_loads +from os import remove +from re import compile as compiles + +from pyrogram import filters +from pyrogram.types import InlineKeyboardButton, InlineKeyboardMarkup + +from misskaty import app +from misskaty.helper import fetch, post_to_telegraph, rentry +from misskaty.vars import COMMAND_HANDLER + +__MODULE__ = "Paste" +__HELP__ = """ +/paste [Text/Reply To Message] - Post text to My Pastebin. +/sbin [Text/Reply To Message] - Post text to Spacebin. +/neko [Text/Reply To Message] - Post text to Nekobin. +/tgraph [Text/Reply To Message] - Post text to Telegraph. +/imgbb [Images] - Upload image to ImgBB. +/rentry [Text/Reply To Message] - Post text to Rentry using markdown style. +""" + + +# Size Checker for Limit +def humanbytes(size: int): + """Convert Bytes To Bytes So That Human Can Read It""" + if not isinstance(size, int): + try: + pass + except ValueError: + size = None + if not size: + return "0 B" + size = int(size) + power = 2**10 + raised_to_pow = 0 + dict_power_n = { + 0: "", + 1: "K", + 2: "M", + 3: "G", + 4: "T", + 5: "P", + 6: "E", + 7: "Z", + 8: "Y", + } + while size > power: + size /= power + raised_to_pow += 1 + try: + real_size = f"{str(round(size, 2))} {dict_power_n[raised_to_pow]}B" + except KeyError: + real_size = "Can't Define Real Size !" + return real_size + + +# Pattern if extension supported, PR if want to add more +pattern = compiles(r"^text/|json$|yaml$|xml$|toml$|x-sh$|x-shellscript$|x-subrip$") + + +@app.on_message(filters.command(["tgraph"], COMMAND_HANDLER)) +async def telegraph_paste(_, message): + reply = message.reply_to_message + if not reply and len(message.command) < 2: + return await message.reply_msg( + f"**Reply To A Message With /{message.command[0]} or with command**", + del_in=6, + ) + + if message.from_user: + if message.from_user.username: + uname = f"@{message.from_user.username} [{message.from_user.id}]" + else: + uname = f"[{message.from_user.first_name}](tg://user?id={message.from_user.id}) [{message.from_user.id}]" + else: + uname = message.sender_chat.title + msg = await message.reply_msg("`Pasting to Telegraph...`") + data = "" + limit = 1024 * 1024 + if reply and not (reply.text or reply.document): + return await msg.edit_msg("**Telegraph upload has been disabled by Durov, use ImgBB command instead.**") + if reply and reply.document: + if reply.document.file_size > limit: + return await msg.edit_msg( + f"**You can only paste files smaller than {humanbytes(limit)}.**" + ) + if not pattern.search(reply.document.mime_type): + return await msg.edit_msg("**Only text files can be pasted.**") + file = await reply.download() + title = ( + message.text.split(None, 1)[1] + if len(message.command) > 1 + else "MissKaty Paste" + ) + try: + with open(file, "r") as text: + data = text.read() + remove(file) + except UnicodeDecodeError: + try: + remove(file) + except: + pass + return await msg.edit_msg("`File Not Supported !`") + elif reply and (reply.text or reply.caption): + title = ( + message.text.split(None, 1)[1] + if len(message.command) > 1 + else "MissKaty Paste" + ) + data = reply.text.html.replace("\n", "
") or reply.caption.html.replace( + "\n", "
" + ) + elif not reply and len(message.command) >= 2: + title = "MissKaty Paste" + data = message.text.split(None, 1)[1] + + try: + url = await post_to_telegraph(False, title, data) + except Exception as e: + return await msg.edit_msg(f"ERROR: {e}") + + if not url: + return await msg.edit_msg("Text Too Short Or File Problems") + button = [ + [InlineKeyboardButton("Open Link", url=url)], + [ + InlineKeyboardButton( + "Share Link", url=f"https://telegram.me/share/url?url={url}" + ) + ], + ] + + pasted = f"**Successfully pasted your data to Telegraph.\n\nPaste by {uname}**" + await msg.edit_msg(pasted, reply_markup=InlineKeyboardMarkup(button)) + + +@app.on_message(filters.command(["paste"], COMMAND_HANDLER)) +async def wastepaste(_, message): + reply = message.reply_to_message + target = str(message.command[0]).split("@", maxsplit=1)[0] + if not reply and len(message.command) < 2: + return await message.reply_msg( + f"**Reply To A Message With /{target} or with command**", del_in=6 + ) + + msg = await message.reply_msg("`Pasting to YasirBin...`") + data = "" + limit = 1024 * 1024 + if reply and reply.document: + if reply.document.file_size > limit: + return await msg.edit_msg( + f"**You can only paste files smaller than {humanbytes(limit)}.**" + ) + if not pattern.search(reply.document.mime_type): + return await msg.edit_msg("**Only text files can be pasted.**") + file = await reply.download() + try: + with open(file, "r") as text: + data = text.read() + remove(file) + except UnicodeDecodeError: + try: + remove(file) + except: + pass + return await msg.edit_msg("`File Not Supported !`") + elif reply and (reply.text or reply.caption): + data = reply.text or reply.caption + elif not reply and len(message.command) >= 2: + data = message.text.split(None, 1)[1] + + if message.from_user: + if message.from_user.username: + uname = f"@{message.from_user.username} [{message.from_user.id}]" + else: + uname = f"[{message.from_user.first_name}](tg://user?id={message.from_user.id}) [{message.from_user.id}]" + else: + uname = message.sender_chat.title + + try: + url = await privatebinapi.send_async("https://bin.yasirweb.eu.org", text=data, expiration="1week", formatting="markdown") + except Exception as e: + return await msg.edit_msg(f"ERROR: {e}") + + if not url: + return await msg.edit_msg("Text Too Short Or File Problems") + button = [ + [InlineKeyboardButton("Open Link", url=url["full_url"])], + [ + InlineKeyboardButton( + "Share Link", url=f"https://telegram.me/share/url?url={url['full_url']}" + ) + ], + ] + + pasted = f"**Successfully pasted your data to YasirBin.\n\nPaste by {uname}**" + await msg.edit_msg(pasted, reply_markup=InlineKeyboardMarkup(button)) + + +# Nekobin Paste +@app.on_message(filters.command(["neko"], COMMAND_HANDLER)) +async def nekopaste(_, message): + reply = message.reply_to_message + target = str(message.command[0]).split("@", maxsplit=1)[0] + if not reply and len(message.command) < 2: + return await message.reply_msg( + f"**Reply To A Message With /{target} or with command**", del_in=6 + ) + + msg = await message.reply_msg("`Pasting to Nekobin...`") + data = "" + limit = 1024 * 1024 + if reply and reply.document: + if reply.document.file_size > limit: + return await message.edit_msg( + f"**You can only paste files smaller than {humanbytes(limit)}.**" + ) + if not pattern.search(reply.document.mime_type): + return await message.edit_msg("**Only text files can be pasted.**") + file = await reply.download() + try: + with open(file, "r") as text: + data = text.read() + remove(file) + except UnicodeDecodeError: + try: + remove(file) + except: + pass + return await message.edit_msg("`File Not Supported !`") + elif reply and (reply.text or reply.caption): + data = reply.text.html or reply.caption.html + elif not reply and len(message.command) >= 2: + data = message.text.split(None, 1)[1] + + if message.from_user: + if message.from_user.username: + uname = f"@{message.from_user.username}" + else: + uname = ( + f"[{message.from_user.first_name}](tg://user?id={message.from_user.id})" + ) + else: + uname = message.sender_chat.title + + try: + x = ( + await fetch.post( + "https://bin.mayuri.my.id/api/documents", json={"content": data} + ) + ).json() + url = f"https://bin.mayuri.my.id/{x['result']['key']}" + except Exception as e: + return await msg.edit_msg(f"ERROR: {e}") + + if not url: + return await msg.edit_msg("Text Too Short Or File Problems") + button = [ + [InlineKeyboardButton("Open Link", url=url)], + [ + InlineKeyboardButton( + "Share Link", url=f"https://telegram.me/share/url?url={url}" + ) + ], + ] + + pasted = f"**Successfully pasted your data to Nekobin.\n\nPaste by {uname}**" + await msg.edit_msg(pasted, reply_markup=InlineKeyboardMarkup(button)) + + +# Paste as spacebin +@app.on_message(filters.command(["sbin"], COMMAND_HANDLER)) +async def spacebinn(_, message): + reply = message.reply_to_message + target = str(message.command[0]).split("@", maxsplit=1)[0] + if not reply and len(message.command) < 2: + return await message.reply_msg( + f"**Reply To A Message With /{target} or with command**", del_in=6 + ) + + msg = await message.reply_msg("`Pasting to Spacebin...`") + data = "" + limit = 1024 * 1024 + if reply and reply.document: + if reply.document.file_size > limit: + return await msg.edit_msg( + f"**You can only paste files smaller than {humanbytes(limit)}.**" + ) + if not pattern.search(reply.document.mime_type): + return await msg.edit_msg("**Only text files can be pasted.**") + file = await reply.download() + try: + with open(file, "r") as text: + data = text.read() + remove(file) + except UnicodeDecodeError: + try: + remove(file) + except: + pass + return await msg.edit_msg("`File Not Supported !`") + elif reply and (reply.text or reply.caption): + data = reply.text.html or reply.caption.html + elif not reply and len(message.command) >= 2: + data = message.text.split(None, 1)[1] + + if message.from_user: + if message.from_user.username: + uname = f"@{message.from_user.username}" + else: + uname = ( + f"[{message.from_user.first_name}](tg://user?id={message.from_user.id})" + ) + else: + uname = message.sender_chat.title + + try: + siteurl = "https://spaceb.in/api/" + response = await fetch.post(siteurl, json={"content": data, "extension": "txt"}) + response = response.json() + url = "https://spaceb.in/" + response["payload"]["id"] + except Exception as e: + return await msg.edit_msg(f"ERROR: {e}") + + if not url: + return await msg.edit_msg("Text Too Short Or File Problems") + button = [ + [InlineKeyboardButton("Open Link", url=url)], + [ + InlineKeyboardButton( + "Share Link", url=f"https://telegram.me/share/url?url={url}" + ) + ], + ] + + pasted = f"**Successfully pasted your data to Spacebin.\n\nPaste by {uname}**" + await msg.edit_msg(pasted, reply_markup=InlineKeyboardMarkup(button)) + + +# Rentry paste +@app.on_message(filters.command(["rentry"], COMMAND_HANDLER)) +async def rentrypaste(_, message): + reply = message.reply_to_message + target = str(message.command[0]).split("@", maxsplit=1)[0] + if not reply and len(message.command) < 2: + return await message.reply_msg( + f"**Reply To A Message With /{target} or with command**", del_in=6 + ) + + msg = await message.reply_msg("`Pasting to Rentry...`") + data = "" + limit = 1024 * 1024 + if reply and reply.document: + if reply.document.file_size > limit: + return await msg.edit_msg( + f"**You can only paste files smaller than {humanbytes(limit)}.**" + ) + if not pattern.search(reply.document.mime_type): + return await msg.edit_msg("**Only text files can be pasted.**") + file = await reply.download() + try: + with open(file, "r") as text: + data = text.read() + remove(file) + except UnicodeDecodeError: + try: + remove(file) + except: + pass + return await msg.edit_msg("`File Not Supported !`") + elif reply and (reply.text or reply.caption): + data = reply.text.markdown or reply.caption.markdown + elif not reply and len(message.command) >= 2: + data = message.text.split(None, 1)[1] + + if message.from_user: + if message.from_user.username: + uname = f"@{message.from_user.username}" + else: + uname = ( + f"[{message.from_user.first_name}](tg://user?id={message.from_user.id})" + ) + else: + uname = message.sender_chat.title + + try: + url = await rentry(data) + except Exception as e: + return await msg.edit(f"`{e}`") + + if not url: + return await msg.edit_msg("Text Too Short Or File Problems") + button = [ + [InlineKeyboardButton("Open Link", url=url)], + [ + InlineKeyboardButton( + "Share Link", url=f"https://telegram.me/share/url?url={url}" + ) + ], + ] + + pasted = f"**Successfully pasted your data to Rentry.\n\nPaste by {uname}**" + await msg.edit_msg(pasted, reply_markup=InlineKeyboardMarkup(button)) + + +# ImgBB Upload +@app.on_message(filters.command(["imgbb"], COMMAND_HANDLER)) +async def imgbb_upload(_, message): + reply = message.reply_to_message + if not reply and len(message.command) == 1: + return await message.edit_msg( + f"**Reply to a photo with /{message.command[0]} command to upload image on ImgBB.**", del_in=6 + ) + if not (reply.photo or (reply.document and reply.document.mime_type.startswith("image"))): + return await message.reply_msg("This command only support upload photo") + msg = await message.reply_msg("`Uploading image to ImgBB...`") + if message.from_user: + if message.from_user.username: + uname = f"@{message.from_user.username}" + else: + uname = ( + f"[{message.from_user.first_name}](tg://user?id={message.from_user.id})" + ) + else: + uname = message.sender_chat.title + + try: + path = await reply.download() + data = {"type": "file", "action": "upload"} + files = {"source": (path, open(path, "rb"), "images/jpeg")} + headers = {"origin": "https://imgbb.com", "referer": "https://imgbb.com/upload", "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36 Edg/107.0.1418.42"} + res = await fetch.post("https://imgbb.com/json", files=files, data=data, headers=headers) + remove(path) + url = f"https://ibb.co.com/{res.json()['image']['id_encoded']}" + button = [ + [InlineKeyboardButton("Open Link", url=url)], + [ + InlineKeyboardButton( + "Share Link", url=f"https://telegram.me/share/url?url={url}" + ) + ], + ] + + pasted = f"**Successfully pasted your images to ImgBB.\n\nPaste by {uname}**" + await msg.edit_msg(pasted, reply_markup=InlineKeyboardMarkup(button)) + except Exception as e: + await msg.edit_msg(f"ERROR: {e}") diff --git a/misskaty/plugins/web_scraper.py b/misskaty/plugins/web_scraper.py index 0838d51c..d55893f1 100644 --- a/misskaty/plugins/web_scraper.py +++ b/misskaty/plugins/web_scraper.py @@ -1,1623 +1,1623 @@ -""" -* @author yasir -* @created 2022-12-01 09:12:27 -* @projectName MissKatyPyro -* Copyright @YasirPedia All rights reserved -""" - -import contextlib -import logging -import re -import sys -import traceback - -import cloudscraper -import httpx -from bs4 import BeautifulSoup -from cachetools import TTLCache -from pykeyboard import InlineButton, InlineKeyboard -from pyrogram.errors import QueryIdInvalid -from pyrogram.types import Message - -from database import dbname -from misskaty import app -from misskaty.helper import Cache, Kusonime, fetch, post_to_telegraph, use_chat_lang - -__MODULE__ = "WebScraper" -__HELP__ = """ -/melongmovie [query ] - Scrape website data from MelongMovie Web. -/lk21 [query ] - Scrape website data from LayarKaca21. -/pahe [query ] - Scrape website data from Pahe.li. -/terbit21 [query ] - Scrape website data from Terbit21. -/savefilm21 [query ] - Scrape website data from Savefilm21. -/movieku [query ] - Scrape website data from Movieku.cc -/kusonime [query ] - Scrape website data from Kusonime -/lendrive [query ] - Scrape website data from Lendrive -/klikxxi [query ] - Scrape website data from Klikxxi aka GoMov. -/samehadaku [query ] - Scrape website data from Samehadaku. -/nodrakor [query ] - Scrape website data from NoDrakor -""" - -LOGGER = logging.getLogger("MissKaty") -SCRAP_DICT = Cache(filename="scraper_cache.db", path="cache", in_memory=False) -data_kuso = Cache(filename="kuso_cache.db", path="cache", in_memory=False) -savedict = TTLCache(maxsize=1000, ttl=3600) -webdb = dbname["web"] - -web = { - "yasirapi": "https://yasirapi.eu.org", - "yasirapi_v2": "https://v2.yasirapi.eu.org", - "pahe": "pahe.ink", - "savefilm21": "https://sf1.savefilm21.digital", - "melongmovie": "https://melongmovie.site", - "terbit21": "https://terbit21.gold", - "lk21": "https://tv1.lk21official.pro", - "gomov": "https://klikxxi.com", - "movieku": "https://movieku.cloud", - "kusonime": "https://kusonime.com", - "lendrive": "https://lendrive.web.id", - "samehadaku": "https://samehadaku.help", - "oplovers": "https://oploverz.red", - "nodrakor": "https://no-drakor.xyz", -} - - -def split_arr(arr, size: 5): - arrs = [] - while len(arr) > size: - pice = arr[:size] - arrs.append(pice) - arr = arr[size:] - arrs.append(arr) - return arrs - - -# Terbit21 GetData -async def getDataTerbit21(msg, kueri, CurrentPage, strings): - if not SCRAP_DICT.get(msg.id): - with contextlib.redirect_stdout(sys.stderr): - try: - if kueri: - terbitjson = await fetch.get( - f"{web['yasirapi']}/terbit21?q={kueri}" - ) - else: - terbitjson = await fetch.get(f"{web['yasirapi']}/terbit21") - terbitjson.raise_for_status() - except httpx.HTTPError as exc: - await msg.edit_msg( - f"ERROR: Failed to fetch data from {exc.request.url} - {exc}" - ) - return None, None - res = terbitjson.json() - if not res.get("result"): - await msg.edit_msg(strings("no_result"), del_in=5) - return None, None - SCRAP_DICT.add(msg.id, [split_arr(res["result"], 6), kueri], timeout=1800) - index = int(CurrentPage - 1) - PageLen = len(SCRAP_DICT[msg.id][0]) - if kueri: - TerbitRes = strings("header_with_query").format(web="Terbit21", kueri=kueri) - else: - TerbitRes = strings("header_no_query").format(web="Terbit21", cmd="terbit21") - for c, i in enumerate(SCRAP_DICT[msg.id][0][index], start=1): - TerbitRes += f"{index*6+c}. {i['judul']}\n{strings('cat_text')}: {i['kategori']}\n" - TerbitRes += ( - "\n" - if re.search(r"Complete|Ongoing", i["kategori"]) - else f"{strings('dl_text')}\n\n" - ) - return TerbitRes, PageLen - - -# LK21 GetData -async def getDatalk21(msg, kueri, CurrentPage, strings): - if not SCRAP_DICT.get(msg.id): - with contextlib.redirect_stdout(sys.stderr): - try: - if kueri: - lk21json = await fetch.get(f"{web['yasirapi_v2']}/lk21?q={kueri}") - else: - lk21json = await fetch.get(f"{web['yasirapi_v2']}/lk21") - lk21json.raise_for_status() - except httpx.HTTPError as exc: - await msg.edit_msg( - f"ERROR: Failed to fetch data from {exc.request.url} - {exc}" - ) - return None, None - res = lk21json.json() - if not res.get("result"): - await msg.edit_msg(strings("no_result"), del_in=5) - return None, None - SCRAP_DICT.add(msg.id, [split_arr(res["result"], 6), kueri], timeout=1800) - index = int(CurrentPage - 1) - PageLen = len(SCRAP_DICT[msg.id][0]) - if kueri: - lkResult = strings("header_with_query").format(web="Layarkaca21", kueri=kueri) - else: - lkResult = strings("header_no_query").format(web="Layarkaca21", cmd="lk21") - for c, i in enumerate(SCRAP_DICT[msg.id][0][index], start=1): - lkResult += f"{index*6+c}. {i['judul']}\n{strings('cat_text')}: {i['kategori']}\n" - lkResult += ( - "\n" - if re.search(r"Complete|Ongoing", i["kategori"]) - else f"{strings('dl_text')}\n\n" - ) - return lkResult, PageLen - - -# Pahe GetData -async def getDataPahe(msg, kueri, CurrentPage, strings): - if not SCRAP_DICT.get(msg.id): - with contextlib.redirect_stdout(sys.stderr): - try: - if kueri: - pahejson = await fetch.get( - f"{web['yasirapi']}/pahe?q={kueri}&domain={web['pahe']}" - ) - else: - pahejson = await fetch.get( - f"{web['yasirapi']}/pahe?domain={web['pahe']}" - ) - pahejson.raise_for_status() - except httpx.HTTPError as exc: - await msg.edit_msg( - f"ERROR: Failed to fetch data from {exc.request.url} - {exc}" - ) - return None, None - res = pahejson.json() - if not res.get("result"): - await msg.edit_msg(strings("no_result"), del_in=5) - return None, None - SCRAP_DICT.add(msg.id, [split_arr(res["result"], 6), kueri], timeout=1800) - index = int(CurrentPage - 1) - PageLen = len(SCRAP_DICT[msg.id][0]) - paheResult = ( - strings("header_with_query").format(web="Pahe", kueri=kueri) - if kueri - else strings("header_no_query").format(web="Pahe", cmd="pahe") - ) - for c, i in enumerate(SCRAP_DICT[msg.id][0][index], start=1): - paheResult += f"{index*6+c}. {i['judul']}\n\n" - return paheResult, PageLen - - -# Kusonime GetData -async def getDataKuso(msg, kueri, CurrentPage, user, strings): - if not SCRAP_DICT.get(msg.id): - kusodata = [] - with contextlib.redirect_stdout(sys.stderr): - try: - data = await fetch.get( - f"{web['kusonime']}/?s={kueri}", follow_redirects=True - ) - data.raise_for_status() - except httpx.HTTPError as exc: - await msg.edit_msg( - f"ERROR: Failed to fetch data from {exc.request.url} - {exc}", - disable_web_page_preview=True, - ) - return None, 0, None, None - res = BeautifulSoup(data, "lxml").find_all("h2", {"class": "episodeye"}) - for i in res: - ress = i.find_all("a")[0] - title = ress.text - link = ress["href"] - kusodata.append({"title": title, "link": link}) - if not kusodata: - await msg.edit_msg(strings("no_result"), del_in=5) - return None, 0, None, None - SCRAP_DICT.add(msg.id, [split_arr(kusodata, 10), kueri], timeout=1800) - index = int(CurrentPage - 1) - PageLen = len(SCRAP_DICT[msg.id][0]) - extractbtn1 = [] - extractbtn2 = [] - - kusoResult = ( - strings("header_no_query").format(web="Kusonime", cmd="kusonime") - if kueri == "" - else strings("header_with_query").format(web="Kusonime", kueri=kueri) - ) - for c, i in enumerate(SCRAP_DICT[msg.id][0][index], start=1): - kusoResult += f"{index*6+c}. {i['title']}\n{i['link']}\n\n" - if c < 6: - extractbtn1.append( - InlineButton( - index * 6 + c, f"kusoextract#{CurrentPage}#{c}#{user}#{msg.id}" - ) - ) - else: - extractbtn2.append( - InlineButton( - index * 6 + c, f"kusoextract#{CurrentPage}#{c}#{user}#{msg.id}" - ) - ) - return kusoResult, PageLen, extractbtn1, extractbtn2 - - -# Movieku GetData -async def getDataMovieku(msg, kueri, CurrentPage, strings): - if not SCRAP_DICT.get(msg.id): - moviekudata = [] - with contextlib.redirect_stdout(sys.stderr): - try: - data = await fetch.get( - f"{web['movieku']}/?s={kueri}", follow_redirects=True - ) - data.raise_for_status() - except httpx.HTTPError as exc: - await msg.edit_msg( - f"ERROR: Failed to fetch data from {exc.request.url} - {exc}" - ) - return None, None - r = BeautifulSoup(data, "lxml") - res = r.find_all(class_="bx") - for i in res: - judul = i.find_all("a")[0]["title"] - link = i.find_all("a")[0]["href"] - typ = i.find(class_="overlay").text - typee = typ.strip() if typ.strip() != "" else "~" - moviekudata.append({"judul": judul, "link": link, "type": typee}) - if not moviekudata: - await msg.edit_msg(strings("no_result"), del_in=5) - return None, None - SCRAP_DICT.add(msg.id, [split_arr(moviekudata, 6), kueri], timeout=1800) - index = int(CurrentPage - 1) - PageLen = len(SCRAP_DICT[msg.id][0]) - - moviekuResult = ( - strings("header_no_query").format(web="Movieku", cmd="movieku") - if kueri == "" - else strings("header_with_query").format(web="Movieku", kueri=kueri) - ) - for c, i in enumerate(SCRAP_DICT[msg.id][0][index], start=1): - moviekuResult += f"{index*6+c}. {i['judul']}\n{strings('quality')}/Status: {i['type']}\nExtract: /movieku_scrap {i['link']}\n\n" - return moviekuResult, PageLen - - -# NoDrakor GetData -async def getDataNodrakor(msg, kueri, CurrentPage, user, strings): - if not SCRAP_DICT.get(msg.id): - nodrakordata = [] - with contextlib.redirect_stdout(sys.stderr): - try: - data = await fetch.get( - f"{web['nodrakor']}/?s={kueri}", - follow_redirects=True, - ) - data.raise_for_status() - except httpx.HTTPError as exc: - await msg.edit_msg( - f"HTTP Exception for {exc.request.url} - {exc}", - disable_web_page_preview=True, - ) - return None, 0, None - text = BeautifulSoup(data, "lxml") - entry = text.find_all(class_="entry-header") - if entry[0].text.strip() == "Nothing Found": - if not kueri: - await msg.edit_msg(strings("no_result"), del_in=5) - else: - await msg.edit_msg( - strings("no_result_w_query").format(kueri=kueri), del_in=5 - ) - return None, 0, None - for i in entry: - genre = i.find(class_="gmr-movie-on") - genre = f"{genre.text}" if genre else "N/A" - judul = i.find(class_="entry-title").find("a").text - link = i.find(class_="entry-title").find("a").get("href") - nodrakordata.append({"judul": judul, "link": link, "genre": genre}) - SCRAP_DICT.add(msg.id, [split_arr(nodrakordata, 6), kueri], timeout=1800) - index = int(CurrentPage - 1) - PageLen = len(SCRAP_DICT[msg.id][0]) - extractbtn = [] - nodrakorResult = ( - strings("header_no_query").format(web="NoDrakor", cmd="nodrakor") - if kueri == "" - else strings("header_with_query").format(web="NoDrakor", kueri=kueri) - ) - for c, i in enumerate(SCRAP_DICT[msg.id][0][index], start=1): - nodrakorResult += f"{index*6+c}. {i['judul']}\nGenre: {i['genre']}\n\n" - extractbtn.append( - InlineButton( - index * 6 + c, f"nodrakorextract#{CurrentPage}#{c}#{user}#{msg.id}" - ) - ) - return nodrakorResult, PageLen, extractbtn - - -# Savefilm21 GetData -async def getDataSavefilm21(msg, kueri, CurrentPage, user, strings): - if not SCRAP_DICT.get(msg.id): - sfdata = [] - with contextlib.redirect_stdout(sys.stderr): - try: - data = await fetch.get( - f"{web['savefilm21']}/?s={kueri}", - follow_redirects=True, - ) - data.raise_for_status() - except httpx.HTTPError as exc: - await msg.edit_msg( - f"HTTP Exception for {exc.request.url} - {exc}", - disable_web_page_preview=True, - ) - return None, 0, None - text = BeautifulSoup(data, "lxml") - entry = text.find_all(class_="entry-header") - if "Tidak Ditemukan" in entry[0].text: - if not kueri: - await msg.edit_msg(strings("no_result"), del_in=5) - else: - await msg.edit_msg( - strings("no_result_w_query").format(kueri=kueri), del_in=5 - ) - return None, 0, None - for i in entry: - genre = i.find(class_="gmr-movie-on").text - genre = f"{genre}" if genre != "" else "N/A" - judul = i.find(class_="entry-title").find("a").text - link = i.find(class_="entry-title").find("a").get("href") - sfdata.append({"judul": judul, "link": link, "genre": genre}) - SCRAP_DICT.add(msg.id, [split_arr(sfdata, 6), kueri], timeout=1800) - index = int(CurrentPage - 1) - PageLen = len(SCRAP_DICT[msg.id][0]) - extractbtn = [] - sfResult = ( - strings("header_no_query").format(web="Savefilm21", cmd="savefilm21") - if kueri == "" - else strings("header_with_query").format(web="Savefilm21", kueri=kueri) - ) - for c, i in enumerate(SCRAP_DICT[msg.id][0][index], start=1): - sfResult += f"{index*6+c}. {i['judul']}\nGenre: {i['genre']}\n\n" - extractbtn.append( - InlineButton( - index * 6 + c, f"sf21extract#{CurrentPage}#{c}#{user}#{msg.id}" - ) - ) - return sfResult, PageLen, extractbtn - - -# Lendrive GetData -async def getDataLendrive(msg, kueri, CurrentPage, user, strings): - if not SCRAP_DICT.get(msg.id): - with contextlib.redirect_stdout(sys.stderr): - try: - if kueri: - data = await fetch.get( - f"{web['lendrive']}/?s={kueri}", - follow_redirects=True, - ) - else: - data = await fetch.get(web["lendrive"], follow_redirects=True) - data.raise_for_status() - except httpx.HTTPError as exc: - await msg.edit_msg( - f"ERROR: Failed to fetch data from {exc.request.url} - {exc}", - disable_web_page_preview=True, - ) - return None, 0, None - res = BeautifulSoup(data, "lxml") - lenddata = [] - for o in res.find_all(class_="bsx"): - title = o.find("a")["title"] - link = o.find("a")["href"] - status = ( - o.find(class_="epx").text - if o.find(class_="epx") - else "Not Provided by BOT" - ) - kualitas = ( - o.find(class_="typez TV").text - if o.find(class_="typez TV") - else o.find(class_="typez BD") - ) - lenddata.append( - { - "judul": title, - "link": link, - "quality": kualitas or "N/A", - "status": status, - } - ) - if not lenddata: - await msg.edit_msg(strings("no_result"), del_in=5) - return None, 0, None - savedict[msg.id] = [split_arr(lenddata, 6), kueri] - index = int(CurrentPage - 1) - PageLen = len(savedict[msg.id][0]) - extractbtn = [] - - lenddataResult = ( - strings("header_no_query").format(web="Lendrive", cmd="lendrive") - if kueri == "" - else strings("header_with_query").format(web="Lendrive", kueri=kueri) - ) - for c, i in enumerate(savedict[msg.id][0][index], start=1): - lenddataResult += f"{index*6+c}. {i['judul']}\n{strings('quality')}: {i['quality']}\nStatus: {i['status']}\n\n" - extractbtn.append( - InlineButton( - index * 6 + c, f"lendriveextract#{CurrentPage}#{c}#{user}#{msg.id}" - ) - ) - return lenddataResult, PageLen, extractbtn - - -# MelongMovie GetData -async def getDataMelong(msg, kueri, CurrentPage, user, strings): - if not SCRAP_DICT.get(msg.id): - with contextlib.redirect_stdout(sys.stderr): - try: - data = await fetch.get( - f"{web['melongmovie']}/?s={kueri}", - follow_redirects=True, - ) - data.raise_for_status() - except httpx.HTTPError as exc: - await msg.edit_msg( - f"HTTP Exception for {exc.request.url} - {exc}", - disable_web_page_preview=True, - ) - return None, 0, None - bs4 = BeautifulSoup(data, "lxml") - melongdata = [] - for res in bs4.select(".box"): - dd = res.select("a") - url = dd[0]["href"] - title = dd[0]["title"] - try: - quality = dd[0].find(class_="quality").text - except: - quality = "N/A" - melongdata.append({"judul": title, "link": url, "quality": quality}) - if not melongdata: - await msg.edit_msg(strings("no_result"), del_in=5) - return None, 0, None - SCRAP_DICT.add(msg.id, [split_arr(melongdata, 6), kueri], timeout=1800) - index = int(CurrentPage - 1) - PageLen = len(SCRAP_DICT[msg.id][0]) - extractbtn = [] - - melongResult = ( - strings("header_no_query").format(web="Melongmovie", cmd="melongmovie") - if kueri == "" - else strings("header_with_query").format(web="Melongmovie", kueri=kueri) - ) - for c, i in enumerate(SCRAP_DICT[msg.id][0][index], start=1): - melongResult += f"{index*6+c}. {i['judul']}\n{strings('quality')}: {i['quality']}\n\n" - extractbtn.append( - InlineButton( - index * 6 + c, f"melongextract#{CurrentPage}#{c}#{user}#{msg.id}" - ) - ) - return melongResult, PageLen, extractbtn - - -# GoMov GetData -async def getDataGomov(msg, kueri, CurrentPage, user, strings): - if not SCRAP_DICT.get(msg.id): - with contextlib.redirect_stdout(sys.stderr): - try: - gomovv = await fetch.get( - f"{web['gomov']}/?s={kueri}", follow_redirects=True - ) - gomovv.raise_for_status() - except httpx.HTTPError as exc: - await msg.edit_msg( - f"ERROR: Failed to fetch data from {exc.request.url} - {exc}", - disable_web_page_preview=True, - ) - return None, 0, None - text = BeautifulSoup(gomovv, "lxml") - entry = text.find_all(class_="entry-header") - if entry[0].text.strip() == "Nothing Found": - if not kueri: - await msg.edit_msg(strings("no_result"), del_in=5) - else: - await msg.edit_msg( - strings("no_result_w_query").format(kueri=kueri), del_in=5 - ) - return None, 0, None - else: - data = [] - for i in entry: - genre = i.find(class_="gmr-movie-on") - genre = f"{genre.text}" if genre else "N/A" - judul = i.find(class_="entry-title").find("a").text - link = i.find(class_="entry-title").find("a").get("href") - data.append({"judul": judul, "link": link, "genre": genre}) - SCRAP_DICT.add(msg.id, [split_arr(data, 6), kueri], timeout=1800) - index = int(CurrentPage - 1) - PageLen = len(SCRAP_DICT[msg.id][0]) - extractbtn = [] - - gomovResult = ( - strings("header_with_query").format(web="GoMov", kueri=kueri) - if kueri - else strings("header_no_query").format(web="GoMov", cmd="gomov") - ) - for c, i in enumerate(SCRAP_DICT[msg.id][0][index], start=1): - gomovResult += f"{index*6+c}. {i['judul']}\nGenre: {i['genre']}\n\n" - if not re.search(r"Series", i["genre"]): - extractbtn.append( - InlineButton( - index * 6 + c, f"gomovextract#{CurrentPage}#{c}#{user}#{msg.id}" - ) - ) - gomovResult += strings("unsupport_dl_btn") - return gomovResult, PageLen, extractbtn - - -# getData samehada -async def getSame(msg, query, current_page, strings): - if not SCRAP_DICT.get(msg.id): - cfse = cloudscraper.create_scraper() - if query: - data = cfse.get(f"{web['samehadaku']}/?s={query}") - else: - data = cfse.get(web["samehadaku"]) - if data.status_code != 200: - await msg.edit_msg(strings("err_getweb").format(err=data.status_code)) - return None, None - res = BeautifulSoup(data.text, "lxml").find_all(class_="animposx") - sdata = [] - for i in res: - url = i.find("a")["href"] - title = i.find("a")["title"] - sta = ( - i.find(class_="type TV").text if i.find(class_="type TV") else "Ongoing" - ) - rate = i.find(class_="score") - sdata.append({"url": url, "title": title, "sta": sta, "rate": rate}) - if not sdata: - await msg.edit_msg(strings("no_result"), del_in=5) - return None, None - savedict[msg.id] = [split_arr(sdata, 10), query] - index = int(current_page - 1) - PageLen = len(savedict[msg.id][0]) - sameresult = "".join( - f"{index * 6 + c}. {i['title']}\nStatus: {i['sta']}\nRating: {i['rate']}\n\n" - for c, i in enumerate(savedict[msg.id][0][index], start=1) - ) - return sameresult, PageLen - - -# SameHada CMD -@app.on_cmd("samehadaku", no_channel=True) -@use_chat_lang() -async def same_search(_, msg, strings): - query = msg.text.split(maxsplit=1)[1] if len(msg.command) > 1 else None - bmsg = await msg.reply_msg(strings("get_data"), quote=True) - sameres, PageLen = await getSame(bmsg, query, 1, strings) - if not sameres: - return - keyboard = InlineKeyboard() - keyboard.paginate( - PageLen, 1, "page_same#{number}" + f"#{bmsg.id}#{msg.from_user.id}" - ) - keyboard.row(InlineButton(strings("cl_btn"), f"close#{msg.from_user.id}")) - await bmsg.edit_msg(sameres, disable_web_page_preview=True, reply_markup=keyboard) - - -# Terbit21 CMD -@app.on_cmd("terbit21", no_channel=True) -@use_chat_lang() -async def terbit21_s(_, message, strings): - kueri = " ".join(message.command[1:]) - if not kueri: - kueri = None - pesan = await message.reply_msg(strings("get_data"), quote=True) - CurrentPage = 1 - terbitres, PageLen = await getDataTerbit21(pesan, kueri, CurrentPage, strings) - if not terbitres: - return - keyboard = InlineKeyboard() - keyboard.paginate( - PageLen, - CurrentPage, - "page_terbit21#{number}" + f"#{pesan.id}#{message.from_user.id}", - ) - keyboard.row(InlineButton(strings("cl_btn"), f"close#{message.from_user.id}")) - await pesan.edit_msg( - terbitres, disable_web_page_preview=True, reply_markup=keyboard - ) - - -# LK21 CMD -@app.on_cmd("lk21", no_channel=True) -@use_chat_lang() -async def lk21_s(_, message, strings): - kueri = " ".join(message.command[1:]) - if not kueri: - kueri = None - pesan = await message.reply_msg(strings("get_data"), quote=True) - CurrentPage = 1 - lkres, PageLen = await getDatalk21(pesan, kueri, CurrentPage, strings) - if not lkres: - return - keyboard = InlineKeyboard() - keyboard.paginate( - PageLen, - CurrentPage, - "page_lk21#{number}" + f"#{pesan.id}#{message.from_user.id}", - ) - keyboard.row(InlineButton(strings("cl_btn"), f"close#{message.from_user.id}")) - await pesan.edit_msg(lkres, disable_web_page_preview=True, reply_markup=keyboard) - - -# Pahe CMD -@app.on_cmd("pahe", no_channel=True) -@use_chat_lang() -async def pahe_s(_, message, strings): - kueri = " ".join(message.command[1:]) - if not kueri: - kueri = "" - pesan = await message.reply_msg(strings("get_data"), quote=True) - CurrentPage = 1 - paheres, PageLen = await getDataPahe(pesan, kueri, CurrentPage, strings) - if not paheres: - return - keyboard = InlineKeyboard() - keyboard.paginate( - PageLen, - CurrentPage, - "page_pahe#{number}" + f"#{pesan.id}#{message.from_user.id}", - ) - keyboard.row(InlineButton(strings("cl_btn"), f"close#{message.from_user.id}")) - await pesan.edit_msg(paheres, disable_web_page_preview=True, reply_markup=keyboard) - - -# Gomov CMD -@app.on_cmd(["gomov", "klikxxi"], no_channel=True) -@use_chat_lang() -async def gomov_s(self, message, strings): - kueri = " ".join(message.command[1:]) - if not kueri: - kueri = "" - pesan = await message.reply_msg(strings("get_data"), quote=True) - CurrentPage = 1 - gomovres, PageLen, btn = await getDataGomov( - pesan, kueri, CurrentPage, message.from_user.id, strings - ) - if not gomovres: - return - keyboard = InlineKeyboard() - keyboard.paginate( - PageLen, - CurrentPage, - "page_gomov#{number}" + f"#{pesan.id}#{message.from_user.id}", - ) - keyboard.row(InlineButton(strings("ex_data"), user_id=self.me.id)) - keyboard.row(*btn) - keyboard.row(InlineButton(strings("cl_btn"), f"close#{message.from_user.id}")) - await pesan.edit_msg(gomovres, disable_web_page_preview=True, reply_markup=keyboard) - - -# MelongMovie CMD -@app.on_cmd("melongmovie", no_channel=True) -@use_chat_lang() -async def melong_s(self, message, strings): - kueri = " ".join(message.command[1:]) - if not kueri: - kueri = "" - pesan = await message.reply_msg(strings("get_data"), quote=True) - CurrentPage = 1 - melongres, PageLen, btn = await getDataMelong( - pesan, kueri, CurrentPage, message.from_user.id, strings - ) - if not melongres: - return - keyboard = InlineKeyboard() - keyboard.paginate( - PageLen, - CurrentPage, - "page_melong#{number}" + f"#{pesan.id}#{message.from_user.id}", - ) - keyboard.row(InlineButton(strings("ex_data"), user_id=self.me.id)) - keyboard.row(*btn) - keyboard.row(InlineButton(strings("cl_btn"), f"close#{message.from_user.id}")) - try: - await pesan.edit_msg( - melongres, disable_web_page_preview=True, reply_markup=keyboard - ) - except Exception as err: - await pesan.edit_msg( - f"ERROR: {err}", disable_web_page_preview=True, reply_markup=keyboard - ) - - -# Savefilm21 CMD -@app.on_cmd("savefilm21", no_channel=True) -@use_chat_lang() -async def savefilm_s(self, message, strings): - kueri = " ".join(message.command[1:]) - if not kueri: - kueri = "" - pesan = await message.reply_msg(strings("get_data"), quote=True) - CurrentPage = 1 - savefilmres, PageLen, btn = await getDataSavefilm21( - pesan, kueri, CurrentPage, message.from_user.id, strings - ) - if not savefilmres: - return - keyboard = InlineKeyboard() - keyboard.paginate( - PageLen, - CurrentPage, - "page_sf21#{number}" + f"#{pesan.id}#{message.from_user.id}", - ) - keyboard.row(InlineButton(strings("ex_data"), user_id=self.me.id)) - keyboard.row(*btn) - keyboard.row(InlineButton(strings("cl_btn"), f"close#{message.from_user.id}")) - await pesan.edit_msg( - savefilmres, disable_web_page_preview=True, reply_markup=keyboard - ) - - -# NoDrakor CMD -@app.on_cmd("nodrakor", no_channel=True) -@use_chat_lang() -async def nodrakor_s(self, message, strings): - kueri = " ".join(message.command[1:]) - if not kueri: - kueri = "" - pesan = await message.reply_msg(strings("get_data"), quote=True) - CurrentPage = 1 - nodrakorres, PageLen, btn = await getDataNodrakor( - pesan, kueri, CurrentPage, message.from_user.id, strings - ) - if not nodrakorres: - return - keyboard = InlineKeyboard() - keyboard.paginate( - PageLen, - CurrentPage, - "page_nodrakor#{number}" + f"#{pesan.id}#{message.from_user.id}", - ) - keyboard.row(InlineButton(strings("ex_data"), user_id=self.me.id)) - keyboard.row(*btn) - keyboard.row(InlineButton(strings("cl_btn"), f"close#{message.from_user.id}")) - await pesan.edit_msg( - nodrakorres, disable_web_page_preview=True, reply_markup=keyboard - ) - - -# Kusonime CMD -@app.on_cmd("kusonime", no_channel=True) -@use_chat_lang() -async def kusonime_s(self, message, strings): - kueri = " ".join(message.command[1:]) - if not kueri: - kueri = "" - pesan = await message.reply_msg(strings("get_data"), quote=True) - CurrentPage = 1 - kusores, PageLen, btn1, btn2 = await getDataKuso( - pesan, kueri, CurrentPage, message.from_user.id, strings - ) - if not kusores: - return - keyboard = InlineKeyboard() - keyboard.paginate( - PageLen, - CurrentPage, - "page_kuso#{number}" + f"#{pesan.id}#{message.from_user.id}", - ) - keyboard.row(InlineButton(strings("ex_data"), user_id=self.me.id)) - keyboard.row(*btn1) - if btn2: - keyboard.row(*btn2) - keyboard.row(InlineButton(strings("cl_btn"), f"close#{message.from_user.id}")) - await pesan.edit_msg(kusores, disable_web_page_preview=True, reply_markup=keyboard) - - -# Lendrive CMD -@app.on_cmd("lendrive", no_channel=True) -@use_chat_lang() -async def lendrive_s(self, ctx: Message, strings): - kueri = ctx.input - if not kueri: - kueri = "" - pesan = await ctx.reply_msg(strings("get_data"), quote=True) - CurrentPage = 1 - lendres, PageLen, btn = await getDataLendrive( - pesan, kueri, CurrentPage, ctx.from_user.id, strings - ) - if not lendres: - return - keyboard = InlineKeyboard() - keyboard.paginate( - PageLen, - CurrentPage, - "page_lendrive#{number}" + f"#{pesan.id}#{ctx.from_user.id}", - ) - keyboard.row(InlineButton(strings("ex_data"), user_id=self.me.id)) - keyboard.row(*btn) - keyboard.row(InlineButton(strings("cl_btn"), f"close#{ctx.from_user.id}")) - await pesan.edit_msg(lendres, disable_web_page_preview=True, reply_markup=keyboard) - - -# Movieku CMD -@app.on_cmd("movieku", no_channel=True) -@use_chat_lang() -async def movieku_s(self, ctx: Message, strings): - kueri = ctx.input - if not kueri: - kueri = "" - pesan = await ctx.reply_msg(strings("get_data"), quote=True) - CurrentPage = 1 - moviekures, PageLen = await getDataMovieku(pesan, kueri, CurrentPage, strings) - if not moviekures: - return - keyboard = InlineKeyboard() - keyboard.paginate( - PageLen, - CurrentPage, - "page_movieku#{number}" + f"#{pesan.id}#{ctx.from_user.id}", - ) - keyboard.row(InlineButton(strings("cl_btn"), f"close#{ctx.from_user.id}")) - await pesan.edit_msg( - moviekures, disable_web_page_preview=True, reply_markup=keyboard - ) - - -# Savefillm21 Page Callback -@app.on_cb("page_sf21#") -@use_chat_lang() -async def sf21page_callback(self, callback_query, strings): - try: - if callback_query.from_user.id != int(callback_query.data.split("#")[3]): - return await callback_query.answer(strings("unauth"), True) - message_id = int(callback_query.data.split("#")[2]) - CurrentPage = int(callback_query.data.split("#")[1]) - kueri = SCRAP_DICT[message_id][1] - except (IndexError, ValueError): # Gatau napa err ini - return - except KeyError: - return await callback_query.message.edit_msg(strings("invalid_cb")) - except QueryIdInvalid: - return - - try: - savefilmres, PageLen, btn = await getDataSavefilm21( - callback_query.message, - kueri, - CurrentPage, - callback_query.from_user.id, - strings, - ) - except TypeError: - return - - keyboard = InlineKeyboard() - keyboard.paginate( - PageLen, - CurrentPage, - "page_sf21#{number}" + f"#{message_id}#{callback_query.from_user.id}", - ) - keyboard.row(InlineButton(strings("ex_data"), user_id=self.me.id)) - keyboard.row(*btn) - keyboard.row( - InlineButton(strings("cl_btn"), f"close#{callback_query.from_user.id}") - ) - await callback_query.message.edit_msg( - savefilmres, disable_web_page_preview=True, reply_markup=keyboard - ) - - -# NoDrakor Page Callback -@app.on_cb("page_nodrakor#") -@use_chat_lang() -async def nodrakorpage_cb(self, callback_query, strings): - try: - if callback_query.from_user.id != int(callback_query.data.split("#")[3]): - return await callback_query.answer(strings("unauth"), True) - message_id = int(callback_query.data.split("#")[2]) - CurrentPage = int(callback_query.data.split("#")[1]) - kueri = SCRAP_DICT[message_id][1] - except (IndexError, ValueError): - return - except KeyError: - return await callback_query.message.edit_msg(strings("invalid_cb")) - except QueryIdInvalid: - return - - try: - nodrakorres, PageLen, btn = await getDataNodrakor( - callback_query.message, - kueri, - CurrentPage, - callback_query.from_user.id, - strings, - ) - except TypeError: - return - - keyboard = InlineKeyboard() - keyboard.paginate( - PageLen, - CurrentPage, - "page_nodrakor#{number}" + f"#{message_id}#{callback_query.from_user.id}", - ) - keyboard.row(InlineButton(strings("ex_data"), user_id=self.me.id)) - keyboard.row(*btn) - keyboard.row( - InlineButton(strings("cl_btn"), f"close#{callback_query.from_user.id}") - ) - await callback_query.message.edit_msg( - nodrakorres, disable_web_page_preview=True, reply_markup=keyboard - ) - - -# Kuso Page Callback -@app.on_cb("page_kuso#") -@use_chat_lang() -async def kusopage_callback(self, callback_query, strings): - try: - if callback_query.from_user.id != int(callback_query.data.split("#")[3]): - return await callback_query.answer(strings("unauth"), True) - message_id = int(callback_query.data.split("#")[2]) - CurrentPage = int(callback_query.data.split("#")[1]) - kueri = SCRAP_DICT[message_id][1] - except QueryIdInvalid: - return - except KeyError: - return await callback_query.message.edit_msg(strings("invalid_cb")) - - try: - kusores, PageLen, btn1, btn2 = await getDataKuso( - callback_query.message, - kueri, - CurrentPage, - callback_query.from_user.id, - strings, - ) - except TypeError: - return - - keyboard = InlineKeyboard() - keyboard.paginate( - PageLen, - CurrentPage, - "page_kuso#{number}" + f"#{message_id}#{callback_query.from_user.id}", - ) - keyboard.row(InlineButton(strings("ex_data"), user_id=self.me.id)) - keyboard.row(*btn1) - if btn2: - keyboard.row(*btn2) - keyboard.row( - InlineButton(strings("cl_btn"), f"close#{callback_query.from_user.id}") - ) - await callback_query.message.edit_msg( - kusores, disable_web_page_preview=True, reply_markup=keyboard - ) - - -# Lendrive Page Callback -@app.on_cb("page_lendrive#") -@use_chat_lang() -async def lendrivepage_callback(self, callback_query, strings): - try: - if callback_query.from_user.id != int(callback_query.data.split("#")[3]): - return await callback_query.answer(strings("unauth"), True) - message_id = int(callback_query.data.split("#")[2]) - CurrentPage = int(callback_query.data.split("#")[1]) - kueri = savedict[message_id][1] - except QueryIdInvalid: - return - except KeyError: - return await callback_query.message.edit_msg(strings("invalid_cb")) - - try: - lendres, PageLen, btn = await getDataLendrive( - callback_query.message, - kueri, - CurrentPage, - callback_query.from_user.id, - strings, - ) - except TypeError: - return - - keyboard = InlineKeyboard() - keyboard.paginate( - PageLen, - CurrentPage, - "page_lendrive#{number}" + f"#{message_id}#{callback_query.from_user.id}", - ) - keyboard.row(InlineButton(strings("ex_data"), user_id=self.me.id)) - keyboard.row(*btn) - keyboard.row( - InlineButton(strings("cl_btn"), f"close#{callback_query.from_user.id}") - ) - await callback_query.message.edit_msg( - lendres, disable_web_page_preview=True, reply_markup=keyboard - ) - - -# Movieku Page Callback -@app.on_cb("page_movieku#") -@use_chat_lang() -async def moviekupage_callback(_, callback_query, strings): - try: - if callback_query.from_user.id != int(callback_query.data.split("#")[3]): - return await callback_query.answer(strings("unauth"), True) - message_id = int(callback_query.data.split("#")[2]) - CurrentPage = int(callback_query.data.split("#")[1]) - kueri = SCRAP_DICT[message_id][1] - except QueryIdInvalid: - return - except KeyError: - return await callback_query.message.edit_msg(strings("invalid_cb"), True) - - try: - moviekures, PageLen = await getDataMovieku( - callback_query.message, kueri, CurrentPage, strings - ) - except TypeError: - return - - keyboard = InlineKeyboard() - keyboard.paginate( - PageLen, - CurrentPage, - "page_movieku#{number}" + f"#{message_id}#{callback_query.from_user.id}", - ) - keyboard.row( - InlineButton(strings("cl_btn"), f"close#{callback_query.from_user.id}") - ) - await callback_query.message.edit_msg( - moviekures, disable_web_page_preview=True, reply_markup=keyboard - ) - - -# Samehada Page Callback -@app.on_cb("page_same#") -@use_chat_lang() -async def samepg(_, query, strings): - try: - _, current_page, _id, user_id = query.data.split("#") - if int(user_id) != query.from_user.id: - return await query.answer(strings("unauth"), True) - lquery = savedict[int(_id)][1] - except QueryIdInvalid: - return - except KeyError: - return await query.message.edit_msg(strings("invalid_cb")) - try: - sameres, PageLen = await getSame( - query.message, lquery, int(current_page), strings - ) - except TypeError: - return - keyboard = InlineKeyboard() - keyboard.paginate( - PageLen, - int(current_page), - "page_same#{number}" + f"#{_id}#{query.from_user.id}", - ) - keyboard.row(InlineButton(strings("cl_btn"), f"close#{query.from_user.id}")) - await query.message.edit_msg( - sameres, disable_web_page_preview=True, reply_markup=keyboard - ) - - -# Terbit21 Page Callback -@app.on_cb("page_terbit21#") -@use_chat_lang() -async def terbit21page_callback(_, callback_query, strings): - try: - if callback_query.from_user.id != int(callback_query.data.split("#")[3]): - return await callback_query.answer(strings("unauth"), True) - message_id = int(callback_query.data.split("#")[2]) - CurrentPage = int(callback_query.data.split("#")[1]) - kueri = SCRAP_DICT[message_id][1] - except QueryIdInvalid: - return - except KeyError: - return await callback_query.message.edit_msg(strings("invalid_cb")) - - try: - terbitres, PageLen = await getDataTerbit21( - callback_query.message, kueri, CurrentPage, strings - ) - except TypeError: - return - - keyboard = InlineKeyboard() - keyboard.paginate( - PageLen, - CurrentPage, - "page_terbit21#{number}" + f"#{message_id}#{callback_query.from_user.id}", - ) - keyboard.row( - InlineButton(strings("cl_btn"), f"close#{callback_query.from_user.id}") - ) - await callback_query.message.edit_msg( - terbitres, disable_web_page_preview=True, reply_markup=keyboard - ) - - -# Page Callback Melong -@app.on_cb("page_melong#") -@use_chat_lang() -async def melongpage_callback(self, callback_query, strings): - try: - if callback_query.from_user.id != int(callback_query.data.split("#")[3]): - return await callback_query.answer(strings("unauth"), True) - message_id = int(callback_query.data.split("#")[2]) - CurrentPage = int(callback_query.data.split("#")[1]) - kueri = SCRAP_DICT[message_id][1] - except QueryIdInvalid: - return - except KeyError: - return await callback_query.message.edit_msg(strings("invalid_cb")) - - try: - terbitres, PageLen, btn = await getDataMelong( - callback_query.message, - kueri, - CurrentPage, - callback_query.from_user.id, - strings, - ) - except TypeError: - return - - keyboard = InlineKeyboard() - keyboard.paginate( - PageLen, - CurrentPage, - "page_melong#{number}" + f"#{message_id}#{callback_query.from_user.id}", - ) - keyboard.row(InlineButton(strings("ex_data"), user_id=self.me.id)) - keyboard.row(*btn) - keyboard.row( - InlineButton(strings("cl_btn"), f"close#{callback_query.from_user.id}") - ) - await callback_query.message.edit_msg( - terbitres, disable_web_page_preview=True, reply_markup=keyboard - ) - - -# Lk21 Page Callback -@app.on_cb("page_lk21#") -@use_chat_lang() -async def lk21page_callback(_, callback_query, strings): - try: - if callback_query.from_user.id != int(callback_query.data.split("#")[3]): - return await callback_query.answer(strings("unauth"), True) - message_id = int(callback_query.data.split("#")[2]) - CurrentPage = int(callback_query.data.split("#")[1]) - kueri = SCRAP_DICT[message_id][1] - except QueryIdInvalid: - return - except KeyError: - return await callback_query.message.edit_msg(strings("invalid_cb")) - - try: - lkres, PageLen = await getDatalk21( - callback_query.message, kueri, CurrentPage, strings - ) - except TypeError: - return - - keyboard = InlineKeyboard() - keyboard.paginate( - PageLen, - CurrentPage, - "page_lk21#{number}" + f"#{message_id}#{callback_query.from_user.id}", - ) - keyboard.row( - InlineButton(strings("cl_btn"), f"close#{callback_query.from_user.id}") - ) - await callback_query.message.edit_msg( - lkres, disable_web_page_preview=True, reply_markup=keyboard - ) - - -# Pahe Page Callback -@app.on_cb("page_pahe#") -@use_chat_lang() -async def pahepage_callback(_, callback_query, strings): - try: - if callback_query.from_user.id != int(callback_query.data.split("#")[3]): - return await callback_query.answer(strings("unauth"), True) - message_id = int(callback_query.data.split("#")[2]) - CurrentPage = int(callback_query.data.split("#")[1]) - kueri = SCRAP_DICT[message_id][1] - except QueryIdInvalid: - return - except KeyError: - return await callback_query.message.edit_msg(strings("invalid_cb")) - - try: - lkres, PageLen = await getDataPahe( - callback_query.message, kueri, CurrentPage, strings - ) - except TypeError: - return - - keyboard = InlineKeyboard() - keyboard.paginate( - PageLen, - CurrentPage, - "page_pahe#{number}" + f"#{message_id}#{callback_query.from_user.id}", - ) - keyboard.row( - InlineButton(strings("cl_btn"), f"close#{callback_query.from_user.id}") - ) - await callback_query.message.edit_msg( - lkres, disable_web_page_preview=True, reply_markup=keyboard - ) - - -# Gomov Page Callback -@app.on_cb("page_gomov#") -@use_chat_lang() -async def gomovpage_callback(self, callback_query, strings): - try: - if callback_query.from_user.id != int(callback_query.data.split("#")[3]): - return await callback_query.answer(strings("unauth"), True) - message_id = int(callback_query.data.split("#")[2]) - CurrentPage = int(callback_query.data.split("#")[1]) - kueri = SCRAP_DICT[message_id][1] - except QueryIdInvalid: - return - except KeyError: - return await callback_query.message.edit_msg(strings("invalid_cb")) - - try: - gomovres, PageLen, btn = await getDataGomov( - callback_query.message, - kueri, - CurrentPage, - callback_query.from_user.id, - strings, - ) - except TypeError: - return - - keyboard = InlineKeyboard() - keyboard.paginate( - PageLen, - CurrentPage, - "page_gomov#{number}" + f"#{message_id}#{callback_query.from_user.id}", - ) - keyboard.row(InlineButton(strings("ex_data"), user_id=self.me.id)) - keyboard.row(*btn) - keyboard.row( - InlineButton(strings("cl_btn"), f"close#{callback_query.from_user.id}") - ) - await callback_query.message.edit_msg( - gomovres, disable_web_page_preview=True, reply_markup=keyboard - ) - - -### Scrape DDL Link From Web ### -# Kusonime DDL -@app.on_cb("kusoextract#") -@use_chat_lang() -async def kusonime_scrap(client, callback_query, strings): - try: - if callback_query.from_user.id != int(callback_query.data.split("#")[3]): - return await callback_query.answer(strings("unauth"), True) - idlink = int(callback_query.data.split("#")[2]) - message_id = int(callback_query.data.split("#")[4]) - CurrentPage = int(callback_query.data.split("#")[1]) - link = SCRAP_DICT[message_id][0][CurrentPage - 1][idlink - 1].get("link") - except QueryIdInvalid: - return - except KeyError: - return await callback_query.message.edit_msg(strings("invalid_cb")) - - kuso = Kusonime() - keyboard = InlineKeyboard() - keyboard.row( - InlineButton( - strings("back_btn"), - f"page_kuso#{CurrentPage}#{message_id}#{callback_query.from_user.id}", - ), - InlineButton(strings("cl_btn"), f"close#{callback_query.from_user.id}"), - ) - try: - if init_url := data_kuso.get(link, False): - await callback_query.message.edit_msg( - init_url.get("ph_url"), reply_markup=keyboard - ) - tgh = await kuso.telegraph(link, client.me.username) - data_kuso[link] = {"ph_url": tgh} - return await callback_query.message.edit_msg(tgh, reply_markup=keyboard) - except Exception as e: - LOGGER.error(f"clases: {e.__class__}, moduleName: {e.__class__.__name__}") - if str(e).startswith("ERROR"): - return await callback_query.message.edit_msg(e, reply_markup=keyboard) - - -# Savefilm21 DDL -@app.on_cb("sf21extract#") -@use_chat_lang() -async def savefilm21_scrap(_, callback_query, strings): - try: - if callback_query.from_user.id != int(callback_query.data.split("#")[3]): - return await callback_query.answer(strings("unauth"), True) - idlink = int(callback_query.data.split("#")[2]) - message_id = int(callback_query.data.split("#")[4]) - CurrentPage = int(callback_query.data.split("#")[1]) - link = SCRAP_DICT[message_id][0][CurrentPage - 1][idlink - 1].get("link") - except QueryIdInvalid: - return - except KeyError: - return await callback_query.message.edit_msg(strings("invalid_cb")) - - keyboard = InlineKeyboard() - keyboard.row( - InlineButton( - strings("back_btn"), - f"page_sf21#{CurrentPage}#{message_id}#{callback_query.from_user.id}", - ), - InlineButton(strings("cl_btn"), f"close#{callback_query.from_user.id}"), - ) - with contextlib.redirect_stdout(sys.stderr): - try: - html = await fetch.get(link) - html.raise_for_status() - soup = BeautifulSoup(html.text, "lxml") - res = soup.find_all(class_="button button-shadow") - res = "".join(f"{i.text}\n{i['href']}\n\n" for i in res) - await callback_query.message.edit_msg( - strings("res_scrape").format(link=link, kl=res), reply_markup=keyboard - ) - except httpx.HTTPError as exc: - await callback_query.message.edit_msg( - f"HTTP Exception for {exc.request.url} - {exc}", - reply_markup=keyboard, - ) - except Exception as err: - await callback_query.message.edit_msg( - f"ERROR: {err}", reply_markup=keyboard - ) - - -# NoDrakor DDL -@app.on_cb("nodrakorextract#") -@use_chat_lang() -async def nodrakorddl_scrap(_, callback_query, strings): - try: - if callback_query.from_user.id != int(callback_query.data.split("#")[3]): - return await callback_query.answer(strings("unauth"), True) - idlink = int(callback_query.data.split("#")[2]) - message_id = int(callback_query.data.split("#")[4]) - CurrentPage = int(callback_query.data.split("#")[1]) - link = SCRAP_DICT[message_id][0][CurrentPage - 1][idlink - 1].get("link") - except QueryIdInvalid: - return - except KeyError: - return await callback_query.message.edit_msg(strings("invalid_cb")) - - keyboard = InlineKeyboard() - keyboard.row( - InlineButton( - strings("back_btn"), - f"page_nodrakor#{CurrentPage}#{message_id}#{callback_query.from_user.id}", - ), - InlineButton(strings("cl_btn"), f"close#{callback_query.from_user.id}"), - ) - with contextlib.redirect_stdout(sys.stderr): - try: - html = await fetch.get(link) - html.raise_for_status() - soup = BeautifulSoup(html.text, "lxml") - if "/tv/" in link: - result = soup.find( - "div", {"entry-content entry-content-single"} - ).find_all("p") - msg = "".join(str(f"{i}\n") for i in result) - link = await post_to_telegraph(False, "MissKaty NoDrakor", msg) - return await callback_query.message.edit_msg( - strings("res_scrape").format(link=link, kl=link), - reply_markup=keyboard, - ) - res = soup.find_all(class_="button button-shadow") - res = "".join(f"{i.text}\n{i['href']}\n\n" for i in res) - if len(res) > 3500: - link = await post_to_telegraph(False, "MissKaty NoDrakor", res) - return await callback_query.message.edit_msg( - strings("res_scrape").format(link=link, kl=link), - reply_markup=keyboard, - ) - await callback_query.message.edit_msg( - strings("res_scrape").format(link=link, kl=res), reply_markup=keyboard - ) - except httpx.HTTPError as exc: - await callback_query.message.edit_msg( - f"HTTP Exception for {exc.request.url} - {exc}", - reply_markup=keyboard, - ) - except Exception as err: - await callback_query.message.edit_msg( - f"ERROR: {err}", reply_markup=keyboard - ) - - -# Scrape Link Download Movieku.CC -@app.on_cmd("movieku_scrap") -@use_chat_lang() -async def muviku_scrap(_, message, strings): - with contextlib.redirect_stdout(sys.stderr): - try: - link = message.text.split(maxsplit=1)[1] - html = await fetch.get(link) - html.raise_for_status() - soup = BeautifulSoup(html.text, "lxml") - res = soup.find_all(class_="smokeurl") - data = [] - for i in res: - for b in range(len(i.find_all("a"))): - link = i.find_all("a")[b]["href"] - kualitas = i.find_all("a")[b].text - # print(f"{kualitas}\n{link - data.append({"link": link, "kualitas": kualitas}) - if not data: - return await message.reply(strings("no_result")) - res = "".join( - f"Host: {i['kualitas']}\n{i['link']}\n\n" for i in data - ) - await message.reply(res) - except IndexError: - return await message.reply( - strings("invalid_cmd_scrape").format(cmd=message.command[0]) - ) - except httpx.HTTPError as exc: - await message.reply( - f"HTTP Exception for {exc.request.url} - {exc}" - ) - except Exception as e: - await message.reply(f"ERROR: {str(e)}") - - -# Scrape DDL Link Melongmovie -@app.on_cb("melongextract#") -@use_chat_lang() -async def melong_scrap(_, callback_query, strings): - try: - if callback_query.from_user.id != int(callback_query.data.split("#")[3]): - return await callback_query.answer(strings("unauth"), True) - idlink = int(callback_query.data.split("#")[2]) - message_id = int(callback_query.data.split("#")[4]) - CurrentPage = int(callback_query.data.split("#")[1]) - link = SCRAP_DICT[message_id][0][CurrentPage - 1][idlink - 1].get("link") - except QueryIdInvalid: - return - except KeyError: - return await callback_query.message.edit_msg(strings("invalid_cb")) - - keyboard = InlineKeyboard() - keyboard.row( - InlineButton( - strings("back_btn"), - f"page_melong#{CurrentPage}#{message_id}#{callback_query.from_user.id}", - ), - InlineButton(strings("cl_btn"), f"close#{callback_query.from_user.id}"), - ) - with contextlib.redirect_stdout(sys.stderr): - try: - html = await fetch.get(link) - html.raise_for_status() - soup = BeautifulSoup(html.text, "lxml") - rep = "" - for ep in soup.findAll(text=re.compile(r"(?i)episode\s+\d+|LINK DOWNLOAD")): - hardsub = ep.findPrevious("div") - softsub = ep.findNext("div") - rep += f"{hardsub}\n{softsub}" - await callback_query.message.edit_msg( - strings("res_scrape").format(link=link, kl=rep), reply_markup=keyboard - ) - except httpx.HTTPError as exc: - await callback_query.message.edit_msg( - f"HTTP Exception for {exc.request.url} - {exc}", - reply_markup=keyboard, - ) - except Exception as err: - await callback_query.message.edit_msg( - f"ERROR: {err}", reply_markup=keyboard - ) - - -# Scrape DDL Link Gomov -@app.on_cb("gomovextract#") -@use_chat_lang() -async def gomov_dl(_, callback_query, strings): - try: - if callback_query.from_user.id != int(callback_query.data.split("#")[3]): - return await callback_query.answer(strings("unauth"), True) - idlink = int(callback_query.data.split("#")[2]) - message_id = int(callback_query.data.split("#")[4]) - CurrentPage = int(callback_query.data.split("#")[1]) - link = SCRAP_DICT[message_id][0][CurrentPage - 1][idlink - 1].get("link") - except QueryIdInvalid: - return - except KeyError: - return await callback_query.message.edit_msg(strings("invalid_cb")) - - keyboard = InlineKeyboard() - keyboard.row( - InlineButton( - strings("back_btn"), - f"page_gomov#{CurrentPage}#{message_id}#{callback_query.from_user.id}", - ), - InlineButton(strings("cl_btn"), f"close#{callback_query.from_user.id}"), - ) - with contextlib.redirect_stdout(sys.stderr): - try: - html = await fetch.get(link) - html.raise_for_status() - soup = BeautifulSoup(html.text, "lxml") - entry = soup.find(class_="gmr-download-wrap clearfix") - hasil = soup.find(class_="title-download").text - for i in entry.find(class_="list-inline gmr-download-list clearfix"): - title = i.find("a").text - ddl = i.find("a")["href"] - hasil += f"\n{title}\n{ddl}\n" - await callback_query.message.edit_msg( - strings("res_scrape").format(link=link, kl=hasil), reply_markup=keyboard - ) - except httpx.HTTPError as exc: - await callback_query.message.edit_msg( - f"HTTP Exception for {exc.request.url} - {exc}", - reply_markup=keyboard, - ) - except Exception as err: - await callback_query.message.edit_msg( - f"ERROR: {err}", reply_markup=keyboard - ) - - -@app.on_cb("lendriveextract#") -@use_chat_lang() -async def lendrive_dl(_, callback_query, strings): - if callback_query.from_user.id != int(callback_query.data.split("#")[3]): - return await callback_query.answer(strings("unauth"), True) - idlink = int(callback_query.data.split("#")[2]) - message_id = int(callback_query.data.split("#")[4]) - CurrentPage = int(callback_query.data.split("#")[1]) - try: - link = savedict[message_id][0][CurrentPage - 1][idlink - 1].get("link") - except KeyError: - return await callback_query.message.edit_msg(strings("invalid_cb")) - - keyboard = InlineKeyboard() - keyboard.row( - InlineButton( - strings("back_btn"), - f"page_lendrive#{CurrentPage}#{message_id}#{callback_query.from_user.id}", - ), - InlineButton(strings("cl_btn"), f"close#{callback_query.from_user.id}"), - ) - with contextlib.redirect_stdout(sys.stderr): - try: - hmm = await fetch.get(link) - hmm.raise_for_status() - q = BeautifulSoup(hmm.text, "lxml") - j = q.findAll("div", class_="soraurlx") - kl = "" - for i in j: - if not i.find("a"): - continue - kl += f"{i.find('strong')}:\n" - kl += "".join( - f"[ {a.text} ]\n" - for a in i.findAll("a") - ) - await callback_query.message.edit_msg( - strings("res_scrape").format(link=link, kl=kl), reply_markup=keyboard - ) - except httpx.HTTPError as exc: - await callback_query.message.edit_msg( - f"HTTP Exception for {exc.request.url} - {exc}", - reply_markup=keyboard, - ) - except Exception as err: - await callback_query.message.edit_msg( - f"ERROR: {err}", reply_markup=keyboard - ) +""" +* @author yasir +* @created 2022-12-01 09:12:27 +* @projectName MissKatyPyro +* Copyright @YasirPedia All rights reserved +""" + +import contextlib +import logging +import re +import sys +import traceback + +import cloudscraper +import httpx +from bs4 import BeautifulSoup +from cachetools import TTLCache +from pykeyboard import InlineButton, InlineKeyboard +from pyrogram.errors import QueryIdInvalid +from pyrogram.types import Message + +from database import dbname +from misskaty import app +from misskaty.helper import Cache, Kusonime, fetch, post_to_telegraph, use_chat_lang + +__MODULE__ = "WebScraper" +__HELP__ = """ +/melongmovie [query ] - Scrape website data from MelongMovie Web. +/lk21 [query ] - Scrape website data from LayarKaca21. +/pahe [query ] - Scrape website data from Pahe.li. +/terbit21 [query ] - Scrape website data from Terbit21. +/savefilm21 [query ] - Scrape website data from Savefilm21. +/movieku [query ] - Scrape website data from Movieku.cc +/kusonime [query ] - Scrape website data from Kusonime +/lendrive [query ] - Scrape website data from Lendrive +/klikxxi [query ] - Scrape website data from Klikxxi aka GoMov. +/samehadaku [query ] - Scrape website data from Samehadaku. +/nodrakor [query ] - Scrape website data from NoDrakor +""" + +LOGGER = logging.getLogger("MissKaty") +SCRAP_DICT = Cache(filename="scraper_cache.db", path="cache", in_memory=False) +data_kuso = Cache(filename="kuso_cache.db", path="cache", in_memory=False) +savedict = TTLCache(maxsize=1000, ttl=3600) +webdb = dbname["web"] + +web = { + "yasirapi": "https://yasirapi.eu.org", + "yasirapi_v2": "https://v2.yasirapi.eu.org", + "pahe": "pahe.ink", + "savefilm21": "https://sf1.savefilm21.digital", + "melongmovie": "https://melongmovie.site", + "terbit21": "https://terbit21.gold", + "lk21": "https://tv1.lk21official.pro", + "gomov": "https://klikxxi.com", + "movieku": "https://movieku.cloud", + "kusonime": "https://kusonime.com", + "lendrive": "https://lendrive.web.id", + "samehadaku": "https://samehadaku.help", + "oplovers": "https://oploverz.red", + "nodrakor": "https://no-drakor.xyz", +} + + +def split_arr(arr, size: 5): + arrs = [] + while len(arr) > size: + pice = arr[:size] + arrs.append(pice) + arr = arr[size:] + arrs.append(arr) + return arrs + + +# Terbit21 GetData +async def getDataTerbit21(msg, kueri, CurrentPage, strings): + if not SCRAP_DICT.get(msg.id): + with contextlib.redirect_stdout(sys.stderr): + try: + if kueri: + terbitjson = await fetch.get( + f"{web['yasirapi']}/terbit21?q={kueri}" + ) + else: + terbitjson = await fetch.get(f"{web['yasirapi']}/terbit21") + terbitjson.raise_for_status() + except httpx.HTTPError as exc: + await msg.edit_msg( + f"ERROR: Failed to fetch data from {exc.request.url} - {exc}" + ) + return None, None + res = terbitjson.json() + if not res.get("result"): + await msg.edit_msg(strings("no_result"), del_in=5) + return None, None + SCRAP_DICT.add(msg.id, [split_arr(res["result"], 6), kueri], timeout=1800) + index = int(CurrentPage - 1) + PageLen = len(SCRAP_DICT[msg.id][0]) + if kueri: + TerbitRes = strings("header_with_query").format(web="Terbit21", kueri=kueri) + else: + TerbitRes = strings("header_no_query").format(web="Terbit21", cmd="terbit21") + for c, i in enumerate(SCRAP_DICT[msg.id][0][index], start=1): + TerbitRes += f"{index*6+c}. {i['judul']}\n{strings('cat_text')}: {i['kategori']}\n" + TerbitRes += ( + "\n" + if re.search(r"Complete|Ongoing", i["kategori"]) + else f"{strings('dl_text')}\n\n" + ) + return TerbitRes, PageLen + + +# LK21 GetData +async def getDatalk21(msg, kueri, CurrentPage, strings): + if not SCRAP_DICT.get(msg.id): + with contextlib.redirect_stdout(sys.stderr): + try: + if kueri: + lk21json = await fetch.get(f"{web['yasirapi_v2']}/lk21?q={kueri}") + else: + lk21json = await fetch.get(f"{web['yasirapi_v2']}/lk21") + lk21json.raise_for_status() + except httpx.HTTPError as exc: + await msg.edit_msg( + f"ERROR: Failed to fetch data from {exc.request.url} - {exc}" + ) + return None, None + res = lk21json.json() + if not res.get("result"): + await msg.edit_msg(strings("no_result"), del_in=5) + return None, None + SCRAP_DICT.add(msg.id, [split_arr(res["result"], 6), kueri], timeout=1800) + index = int(CurrentPage - 1) + PageLen = len(SCRAP_DICT[msg.id][0]) + if kueri: + lkResult = strings("header_with_query").format(web="Layarkaca21", kueri=kueri) + else: + lkResult = strings("header_no_query").format(web="Layarkaca21", cmd="lk21") + for c, i in enumerate(SCRAP_DICT[msg.id][0][index], start=1): + lkResult += f"{index*6+c}. {i['judul']}\n{strings('cat_text')}: {i['kategori']}\n" + lkResult += ( + "\n" + if re.search(r"Complete|Ongoing", i["kategori"]) + else f"{strings('dl_text')}\n\n" + ) + return lkResult, PageLen + + +# Pahe GetData +async def getDataPahe(msg, kueri, CurrentPage, strings): + if not SCRAP_DICT.get(msg.id): + with contextlib.redirect_stdout(sys.stderr): + try: + if kueri: + pahejson = await fetch.get( + f"{web['yasirapi']}/pahe?q={kueri}&domain={web['pahe']}" + ) + else: + pahejson = await fetch.get( + f"{web['yasirapi']}/pahe?domain={web['pahe']}" + ) + pahejson.raise_for_status() + except httpx.HTTPError as exc: + await msg.edit_msg( + f"ERROR: Failed to fetch data from {exc.request.url} - {exc}" + ) + return None, None + res = pahejson.json() + if not res.get("result"): + await msg.edit_msg(strings("no_result"), del_in=5) + return None, None + SCRAP_DICT.add(msg.id, [split_arr(res["result"], 6), kueri], timeout=1800) + index = int(CurrentPage - 1) + PageLen = len(SCRAP_DICT[msg.id][0]) + paheResult = ( + strings("header_with_query").format(web="Pahe", kueri=kueri) + if kueri + else strings("header_no_query").format(web="Pahe", cmd="pahe") + ) + for c, i in enumerate(SCRAP_DICT[msg.id][0][index], start=1): + paheResult += f"{index*6+c}. {i['judul']}\n\n" + return paheResult, PageLen + + +# Kusonime GetData +async def getDataKuso(msg, kueri, CurrentPage, user, strings): + if not SCRAP_DICT.get(msg.id): + kusodata = [] + with contextlib.redirect_stdout(sys.stderr): + try: + data = await fetch.get( + f"{web['kusonime']}/?s={kueri}", follow_redirects=True + ) + data.raise_for_status() + except httpx.HTTPError as exc: + await msg.edit_msg( + f"ERROR: Failed to fetch data from {exc.request.url} - {exc}", + disable_web_page_preview=True, + ) + return None, 0, None, None + res = BeautifulSoup(data, "lxml").find_all("h2", {"class": "episodeye"}) + for i in res: + ress = i.find_all("a")[0] + title = ress.text + link = ress["href"] + kusodata.append({"title": title, "link": link}) + if not kusodata: + await msg.edit_msg(strings("no_result"), del_in=5) + return None, 0, None, None + SCRAP_DICT.add(msg.id, [split_arr(kusodata, 10), kueri], timeout=1800) + index = int(CurrentPage - 1) + PageLen = len(SCRAP_DICT[msg.id][0]) + extractbtn1 = [] + extractbtn2 = [] + + kusoResult = ( + strings("header_no_query").format(web="Kusonime", cmd="kusonime") + if kueri == "" + else strings("header_with_query").format(web="Kusonime", kueri=kueri) + ) + for c, i in enumerate(SCRAP_DICT[msg.id][0][index], start=1): + kusoResult += f"{index*6+c}. {i['title']}\n{i['link']}\n\n" + if c < 6: + extractbtn1.append( + InlineButton( + index * 6 + c, f"kusoextract#{CurrentPage}#{c}#{user}#{msg.id}" + ) + ) + else: + extractbtn2.append( + InlineButton( + index * 6 + c, f"kusoextract#{CurrentPage}#{c}#{user}#{msg.id}" + ) + ) + return kusoResult, PageLen, extractbtn1, extractbtn2 + + +# Movieku GetData +async def getDataMovieku(msg, kueri, CurrentPage, strings): + if not SCRAP_DICT.get(msg.id): + moviekudata = [] + with contextlib.redirect_stdout(sys.stderr): + try: + data = await fetch.get( + f"{web['movieku']}/?s={kueri}", follow_redirects=True + ) + data.raise_for_status() + except httpx.HTTPError as exc: + await msg.edit_msg( + f"ERROR: Failed to fetch data from {exc.request.url} - {exc}" + ) + return None, None + r = BeautifulSoup(data, "lxml") + res = r.find_all(class_="bx") + for i in res: + judul = i.find_all("a")[0]["title"] + link = i.find_all("a")[0]["href"] + typ = i.find(class_="overlay").text + typee = typ.strip() if typ.strip() != "" else "~" + moviekudata.append({"judul": judul, "link": link, "type": typee}) + if not moviekudata: + await msg.edit_msg(strings("no_result"), del_in=5) + return None, None + SCRAP_DICT.add(msg.id, [split_arr(moviekudata, 6), kueri], timeout=1800) + index = int(CurrentPage - 1) + PageLen = len(SCRAP_DICT[msg.id][0]) + + moviekuResult = ( + strings("header_no_query").format(web="Movieku", cmd="movieku") + if kueri == "" + else strings("header_with_query").format(web="Movieku", kueri=kueri) + ) + for c, i in enumerate(SCRAP_DICT[msg.id][0][index], start=1): + moviekuResult += f"{index*6+c}. {i['judul']}\n{strings('quality')}/Status: {i['type']}\nExtract: /movieku_scrap {i['link']}\n\n" + return moviekuResult, PageLen + + +# NoDrakor GetData +async def getDataNodrakor(msg, kueri, CurrentPage, user, strings): + if not SCRAP_DICT.get(msg.id): + nodrakordata = [] + with contextlib.redirect_stdout(sys.stderr): + try: + data = await fetch.get( + f"{web['nodrakor']}/?s={kueri}", + follow_redirects=True, + ) + data.raise_for_status() + except httpx.HTTPError as exc: + await msg.edit_msg( + f"HTTP Exception for {exc.request.url} - {exc}", + disable_web_page_preview=True, + ) + return None, 0, None + text = BeautifulSoup(data, "lxml") + entry = text.find_all(class_="entry-header") + if entry[0].text.strip() == "Nothing Found": + if not kueri: + await msg.edit_msg(strings("no_result"), del_in=5) + else: + await msg.edit_msg( + strings("no_result_w_query").format(kueri=kueri), del_in=5 + ) + return None, 0, None + for i in entry: + genre = i.find(class_="gmr-movie-on") + genre = f"{genre.text}" if genre else "N/A" + judul = i.find(class_="entry-title").find("a").text + link = i.find(class_="entry-title").find("a").get("href") + nodrakordata.append({"judul": judul, "link": link, "genre": genre}) + SCRAP_DICT.add(msg.id, [split_arr(nodrakordata, 6), kueri], timeout=1800) + index = int(CurrentPage - 1) + PageLen = len(SCRAP_DICT[msg.id][0]) + extractbtn = [] + nodrakorResult = ( + strings("header_no_query").format(web="NoDrakor", cmd="nodrakor") + if kueri == "" + else strings("header_with_query").format(web="NoDrakor", kueri=kueri) + ) + for c, i in enumerate(SCRAP_DICT[msg.id][0][index], start=1): + nodrakorResult += f"{index*6+c}. {i['judul']}\nGenre: {i['genre']}\n\n" + extractbtn.append( + InlineButton( + index * 6 + c, f"nodrakorextract#{CurrentPage}#{c}#{user}#{msg.id}" + ) + ) + return nodrakorResult, PageLen, extractbtn + + +# Savefilm21 GetData +async def getDataSavefilm21(msg, kueri, CurrentPage, user, strings): + if not SCRAP_DICT.get(msg.id): + sfdata = [] + with contextlib.redirect_stdout(sys.stderr): + try: + data = await fetch.get( + f"{web['savefilm21']}/?s={kueri}", + follow_redirects=True, + ) + data.raise_for_status() + except httpx.HTTPError as exc: + await msg.edit_msg( + f"HTTP Exception for {exc.request.url} - {exc}", + disable_web_page_preview=True, + ) + return None, 0, None + text = BeautifulSoup(data, "lxml") + entry = text.find_all(class_="entry-header") + if "Tidak Ditemukan" in entry[0].text: + if not kueri: + await msg.edit_msg(strings("no_result"), del_in=5) + else: + await msg.edit_msg( + strings("no_result_w_query").format(kueri=kueri), del_in=5 + ) + return None, 0, None + for i in entry: + genre = i.find(class_="gmr-movie-on").text + genre = f"{genre}" if genre != "" else "N/A" + judul = i.find(class_="entry-title").find("a").text + link = i.find(class_="entry-title").find("a").get("href") + sfdata.append({"judul": judul, "link": link, "genre": genre}) + SCRAP_DICT.add(msg.id, [split_arr(sfdata, 6), kueri], timeout=1800) + index = int(CurrentPage - 1) + PageLen = len(SCRAP_DICT[msg.id][0]) + extractbtn = [] + sfResult = ( + strings("header_no_query").format(web="Savefilm21", cmd="savefilm21") + if kueri == "" + else strings("header_with_query").format(web="Savefilm21", kueri=kueri) + ) + for c, i in enumerate(SCRAP_DICT[msg.id][0][index], start=1): + sfResult += f"{index*6+c}. {i['judul']}\nGenre: {i['genre']}\n\n" + extractbtn.append( + InlineButton( + index * 6 + c, f"sf21extract#{CurrentPage}#{c}#{user}#{msg.id}" + ) + ) + return sfResult, PageLen, extractbtn + + +# Lendrive GetData +async def getDataLendrive(msg, kueri, CurrentPage, user, strings): + if not SCRAP_DICT.get(msg.id): + with contextlib.redirect_stdout(sys.stderr): + try: + if kueri: + data = await fetch.get( + f"{web['lendrive']}/?s={kueri}", + follow_redirects=True, + ) + else: + data = await fetch.get(web["lendrive"], follow_redirects=True) + data.raise_for_status() + except httpx.HTTPError as exc: + await msg.edit_msg( + f"ERROR: Failed to fetch data from {exc.request.url} - {exc}", + disable_web_page_preview=True, + ) + return None, 0, None + res = BeautifulSoup(data, "lxml") + lenddata = [] + for o in res.find_all(class_="bsx"): + title = o.find("a")["title"] + link = o.find("a")["href"] + status = ( + o.find(class_="epx").text + if o.find(class_="epx") + else "Not Provided by BOT" + ) + kualitas = ( + o.find(class_="typez TV").text + if o.find(class_="typez TV") + else o.find(class_="typez BD") + ) + lenddata.append( + { + "judul": title, + "link": link, + "quality": kualitas or "N/A", + "status": status, + } + ) + if not lenddata: + await msg.edit_msg(strings("no_result"), del_in=5) + return None, 0, None + savedict[msg.id] = [split_arr(lenddata, 6), kueri] + index = int(CurrentPage - 1) + PageLen = len(savedict[msg.id][0]) + extractbtn = [] + + lenddataResult = ( + strings("header_no_query").format(web="Lendrive", cmd="lendrive") + if kueri == "" + else strings("header_with_query").format(web="Lendrive", kueri=kueri) + ) + for c, i in enumerate(savedict[msg.id][0][index], start=1): + lenddataResult += f"{index*6+c}. {i['judul']}\n{strings('quality')}: {i['quality']}\nStatus: {i['status']}\n\n" + extractbtn.append( + InlineButton( + index * 6 + c, f"lendriveextract#{CurrentPage}#{c}#{user}#{msg.id}" + ) + ) + return lenddataResult, PageLen, extractbtn + + +# MelongMovie GetData +async def getDataMelong(msg, kueri, CurrentPage, user, strings): + if not SCRAP_DICT.get(msg.id): + with contextlib.redirect_stdout(sys.stderr): + try: + data = await fetch.get( + f"{web['melongmovie']}/?s={kueri}", + follow_redirects=True, + ) + data.raise_for_status() + except httpx.HTTPError as exc: + await msg.edit_msg( + f"HTTP Exception for {exc.request.url} - {exc}", + disable_web_page_preview=True, + ) + return None, 0, None + bs4 = BeautifulSoup(data, "lxml") + melongdata = [] + for res in bs4.select(".box"): + dd = res.select("a") + url = dd[0]["href"] + title = dd[0]["title"] + try: + quality = dd[0].find(class_="quality").text + except: + quality = "N/A" + melongdata.append({"judul": title, "link": url, "quality": quality}) + if not melongdata: + await msg.edit_msg(strings("no_result"), del_in=5) + return None, 0, None + SCRAP_DICT.add(msg.id, [split_arr(melongdata, 6), kueri], timeout=1800) + index = int(CurrentPage - 1) + PageLen = len(SCRAP_DICT[msg.id][0]) + extractbtn = [] + + melongResult = ( + strings("header_no_query").format(web="Melongmovie", cmd="melongmovie") + if kueri == "" + else strings("header_with_query").format(web="Melongmovie", kueri=kueri) + ) + for c, i in enumerate(SCRAP_DICT[msg.id][0][index], start=1): + melongResult += f"{index*6+c}. {i['judul']}\n{strings('quality')}: {i['quality']}\n\n" + extractbtn.append( + InlineButton( + index * 6 + c, f"melongextract#{CurrentPage}#{c}#{user}#{msg.id}" + ) + ) + return melongResult, PageLen, extractbtn + + +# GoMov GetData +async def getDataGomov(msg, kueri, CurrentPage, user, strings): + if not SCRAP_DICT.get(msg.id): + with contextlib.redirect_stdout(sys.stderr): + try: + gomovv = await fetch.get( + f"{web['gomov']}/?s={kueri}", follow_redirects=True + ) + gomovv.raise_for_status() + except httpx.HTTPError as exc: + await msg.edit_msg( + f"ERROR: Failed to fetch data from {exc.request.url} - {exc}", + disable_web_page_preview=True, + ) + return None, 0, None + text = BeautifulSoup(gomovv, "lxml") + entry = text.find_all(class_="entry-header") + if entry[0].text.strip() == "Nothing Found": + if not kueri: + await msg.edit_msg(strings("no_result"), del_in=5) + else: + await msg.edit_msg( + strings("no_result_w_query").format(kueri=kueri), del_in=5 + ) + return None, 0, None + else: + data = [] + for i in entry: + genre = i.find(class_="gmr-movie-on") + genre = f"{genre.text}" if genre else "N/A" + judul = i.find(class_="entry-title").find("a").text + link = i.find(class_="entry-title").find("a").get("href") + data.append({"judul": judul, "link": link, "genre": genre}) + SCRAP_DICT.add(msg.id, [split_arr(data, 6), kueri], timeout=1800) + index = int(CurrentPage - 1) + PageLen = len(SCRAP_DICT[msg.id][0]) + extractbtn = [] + + gomovResult = ( + strings("header_with_query").format(web="GoMov", kueri=kueri) + if kueri + else strings("header_no_query").format(web="GoMov", cmd="gomov") + ) + for c, i in enumerate(SCRAP_DICT[msg.id][0][index], start=1): + gomovResult += f"{index*6+c}. {i['judul']}\nGenre: {i['genre']}\n\n" + if not re.search(r"Series", i["genre"]): + extractbtn.append( + InlineButton( + index * 6 + c, f"gomovextract#{CurrentPage}#{c}#{user}#{msg.id}" + ) + ) + gomovResult += strings("unsupport_dl_btn") + return gomovResult, PageLen, extractbtn + + +# getData samehada +async def getSame(msg, query, current_page, strings): + if not SCRAP_DICT.get(msg.id): + cfse = cloudscraper.create_scraper() + if query: + data = cfse.get(f"{web['samehadaku']}/?s={query}") + else: + data = cfse.get(web["samehadaku"]) + if data.status_code != 200: + await msg.edit_msg(strings("err_getweb").format(err=data.status_code)) + return None, None + res = BeautifulSoup(data.text, "lxml").find_all(class_="animposx") + sdata = [] + for i in res: + url = i.find("a")["href"] + title = i.find("a")["title"] + sta = ( + i.find(class_="type TV").text if i.find(class_="type TV") else "Ongoing" + ) + rate = i.find(class_="score") + sdata.append({"url": url, "title": title, "sta": sta, "rate": rate}) + if not sdata: + await msg.edit_msg(strings("no_result"), del_in=5) + return None, None + savedict[msg.id] = [split_arr(sdata, 10), query] + index = int(current_page - 1) + PageLen = len(savedict[msg.id][0]) + sameresult = "".join( + f"{index * 6 + c}. {i['title']}\nStatus: {i['sta']}\nRating: {i['rate']}\n\n" + for c, i in enumerate(savedict[msg.id][0][index], start=1) + ) + return sameresult, PageLen + + +# SameHada CMD +@app.on_cmd("samehadaku", no_channel=True) +@use_chat_lang() +async def same_search(_, msg, strings): + query = msg.text.split(maxsplit=1)[1] if len(msg.command) > 1 else None + bmsg = await msg.reply_msg(strings("get_data"), quote=True) + sameres, PageLen = await getSame(bmsg, query, 1, strings) + if not sameres: + return + keyboard = InlineKeyboard() + keyboard.paginate( + PageLen, 1, "page_same#{number}" + f"#{bmsg.id}#{msg.from_user.id}" + ) + keyboard.row(InlineButton(strings("cl_btn"), f"close#{msg.from_user.id}")) + await bmsg.edit_msg(sameres, disable_web_page_preview=True, reply_markup=keyboard) + + +# Terbit21 CMD +@app.on_cmd("terbit21", no_channel=True) +@use_chat_lang() +async def terbit21_s(_, message, strings): + kueri = " ".join(message.command[1:]) + if not kueri: + kueri = None + pesan = await message.reply_msg(strings("get_data"), quote=True) + CurrentPage = 1 + terbitres, PageLen = await getDataTerbit21(pesan, kueri, CurrentPage, strings) + if not terbitres: + return + keyboard = InlineKeyboard() + keyboard.paginate( + PageLen, + CurrentPage, + "page_terbit21#{number}" + f"#{pesan.id}#{message.from_user.id}", + ) + keyboard.row(InlineButton(strings("cl_btn"), f"close#{message.from_user.id}")) + await pesan.edit_msg( + terbitres, disable_web_page_preview=True, reply_markup=keyboard + ) + + +# LK21 CMD +@app.on_cmd("lk21", no_channel=True) +@use_chat_lang() +async def lk21_s(_, message, strings): + kueri = " ".join(message.command[1:]) + if not kueri: + kueri = None + pesan = await message.reply_msg(strings("get_data"), quote=True) + CurrentPage = 1 + lkres, PageLen = await getDatalk21(pesan, kueri, CurrentPage, strings) + if not lkres: + return + keyboard = InlineKeyboard() + keyboard.paginate( + PageLen, + CurrentPage, + "page_lk21#{number}" + f"#{pesan.id}#{message.from_user.id}", + ) + keyboard.row(InlineButton(strings("cl_btn"), f"close#{message.from_user.id}")) + await pesan.edit_msg(lkres, disable_web_page_preview=True, reply_markup=keyboard) + + +# Pahe CMD +@app.on_cmd("pahe", no_channel=True) +@use_chat_lang() +async def pahe_s(_, message, strings): + kueri = " ".join(message.command[1:]) + if not kueri: + kueri = "" + pesan = await message.reply_msg(strings("get_data"), quote=True) + CurrentPage = 1 + paheres, PageLen = await getDataPahe(pesan, kueri, CurrentPage, strings) + if not paheres: + return + keyboard = InlineKeyboard() + keyboard.paginate( + PageLen, + CurrentPage, + "page_pahe#{number}" + f"#{pesan.id}#{message.from_user.id}", + ) + keyboard.row(InlineButton(strings("cl_btn"), f"close#{message.from_user.id}")) + await pesan.edit_msg(paheres, disable_web_page_preview=True, reply_markup=keyboard) + + +# Gomov CMD +@app.on_cmd(["gomov", "klikxxi"], no_channel=True) +@use_chat_lang() +async def gomov_s(self, message, strings): + kueri = " ".join(message.command[1:]) + if not kueri: + kueri = "" + pesan = await message.reply_msg(strings("get_data"), quote=True) + CurrentPage = 1 + gomovres, PageLen, btn = await getDataGomov( + pesan, kueri, CurrentPage, message.from_user.id, strings + ) + if not gomovres: + return + keyboard = InlineKeyboard() + keyboard.paginate( + PageLen, + CurrentPage, + "page_gomov#{number}" + f"#{pesan.id}#{message.from_user.id}", + ) + keyboard.row(InlineButton(strings("ex_data"), user_id=self.me.id)) + keyboard.row(*btn) + keyboard.row(InlineButton(strings("cl_btn"), f"close#{message.from_user.id}")) + await pesan.edit_msg(gomovres, disable_web_page_preview=True, reply_markup=keyboard) + + +# MelongMovie CMD +@app.on_cmd("melongmovie", no_channel=True) +@use_chat_lang() +async def melong_s(self, message, strings): + kueri = " ".join(message.command[1:]) + if not kueri: + kueri = "" + pesan = await message.reply_msg(strings("get_data"), quote=True) + CurrentPage = 1 + melongres, PageLen, btn = await getDataMelong( + pesan, kueri, CurrentPage, message.from_user.id, strings + ) + if not melongres: + return + keyboard = InlineKeyboard() + keyboard.paginate( + PageLen, + CurrentPage, + "page_melong#{number}" + f"#{pesan.id}#{message.from_user.id}", + ) + keyboard.row(InlineButton(strings("ex_data"), user_id=self.me.id)) + keyboard.row(*btn) + keyboard.row(InlineButton(strings("cl_btn"), f"close#{message.from_user.id}")) + try: + await pesan.edit_msg( + melongres, disable_web_page_preview=True, reply_markup=keyboard + ) + except Exception as err: + await pesan.edit_msg( + f"ERROR: {err}", disable_web_page_preview=True, reply_markup=keyboard + ) + + +# Savefilm21 CMD +@app.on_cmd("savefilm21", no_channel=True) +@use_chat_lang() +async def savefilm_s(self, message, strings): + kueri = " ".join(message.command[1:]) + if not kueri: + kueri = "" + pesan = await message.reply_msg(strings("get_data"), quote=True) + CurrentPage = 1 + savefilmres, PageLen, btn = await getDataSavefilm21( + pesan, kueri, CurrentPage, message.from_user.id, strings + ) + if not savefilmres: + return + keyboard = InlineKeyboard() + keyboard.paginate( + PageLen, + CurrentPage, + "page_sf21#{number}" + f"#{pesan.id}#{message.from_user.id}", + ) + keyboard.row(InlineButton(strings("ex_data"), user_id=self.me.id)) + keyboard.row(*btn) + keyboard.row(InlineButton(strings("cl_btn"), f"close#{message.from_user.id}")) + await pesan.edit_msg( + savefilmres, disable_web_page_preview=True, reply_markup=keyboard + ) + + +# NoDrakor CMD +@app.on_cmd("nodrakor", no_channel=True) +@use_chat_lang() +async def nodrakor_s(self, message, strings): + kueri = " ".join(message.command[1:]) + if not kueri: + kueri = "" + pesan = await message.reply_msg(strings("get_data"), quote=True) + CurrentPage = 1 + nodrakorres, PageLen, btn = await getDataNodrakor( + pesan, kueri, CurrentPage, message.from_user.id, strings + ) + if not nodrakorres: + return + keyboard = InlineKeyboard() + keyboard.paginate( + PageLen, + CurrentPage, + "page_nodrakor#{number}" + f"#{pesan.id}#{message.from_user.id}", + ) + keyboard.row(InlineButton(strings("ex_data"), user_id=self.me.id)) + keyboard.row(*btn) + keyboard.row(InlineButton(strings("cl_btn"), f"close#{message.from_user.id}")) + await pesan.edit_msg( + nodrakorres, disable_web_page_preview=True, reply_markup=keyboard + ) + + +# Kusonime CMD +@app.on_cmd("kusonime", no_channel=True) +@use_chat_lang() +async def kusonime_s(self, message, strings): + kueri = " ".join(message.command[1:]) + if not kueri: + kueri = "" + pesan = await message.reply_msg(strings("get_data"), quote=True) + CurrentPage = 1 + kusores, PageLen, btn1, btn2 = await getDataKuso( + pesan, kueri, CurrentPage, message.from_user.id, strings + ) + if not kusores: + return + keyboard = InlineKeyboard() + keyboard.paginate( + PageLen, + CurrentPage, + "page_kuso#{number}" + f"#{pesan.id}#{message.from_user.id}", + ) + keyboard.row(InlineButton(strings("ex_data"), user_id=self.me.id)) + keyboard.row(*btn1) + if btn2: + keyboard.row(*btn2) + keyboard.row(InlineButton(strings("cl_btn"), f"close#{message.from_user.id}")) + await pesan.edit_msg(kusores, disable_web_page_preview=True, reply_markup=keyboard) + + +# Lendrive CMD +@app.on_cmd("lendrive", no_channel=True) +@use_chat_lang() +async def lendrive_s(self, ctx: Message, strings): + kueri = ctx.input + if not kueri: + kueri = "" + pesan = await ctx.reply_msg(strings("get_data"), quote=True) + CurrentPage = 1 + lendres, PageLen, btn = await getDataLendrive( + pesan, kueri, CurrentPage, ctx.from_user.id, strings + ) + if not lendres: + return + keyboard = InlineKeyboard() + keyboard.paginate( + PageLen, + CurrentPage, + "page_lendrive#{number}" + f"#{pesan.id}#{ctx.from_user.id}", + ) + keyboard.row(InlineButton(strings("ex_data"), user_id=self.me.id)) + keyboard.row(*btn) + keyboard.row(InlineButton(strings("cl_btn"), f"close#{ctx.from_user.id}")) + await pesan.edit_msg(lendres, disable_web_page_preview=True, reply_markup=keyboard) + + +# Movieku CMD +@app.on_cmd("movieku", no_channel=True) +@use_chat_lang() +async def movieku_s(self, ctx: Message, strings): + kueri = ctx.input + if not kueri: + kueri = "" + pesan = await ctx.reply_msg(strings("get_data"), quote=True) + CurrentPage = 1 + moviekures, PageLen = await getDataMovieku(pesan, kueri, CurrentPage, strings) + if not moviekures: + return + keyboard = InlineKeyboard() + keyboard.paginate( + PageLen, + CurrentPage, + "page_movieku#{number}" + f"#{pesan.id}#{ctx.from_user.id}", + ) + keyboard.row(InlineButton(strings("cl_btn"), f"close#{ctx.from_user.id}")) + await pesan.edit_msg( + moviekures, disable_web_page_preview=True, reply_markup=keyboard + ) + + +# Savefillm21 Page Callback +@app.on_cb("page_sf21#") +@use_chat_lang() +async def sf21page_callback(self, callback_query, strings): + try: + if callback_query.from_user.id != int(callback_query.data.split("#")[3]): + return await callback_query.answer(strings("unauth"), True) + message_id = int(callback_query.data.split("#")[2]) + CurrentPage = int(callback_query.data.split("#")[1]) + kueri = SCRAP_DICT[message_id][1] + except (IndexError, ValueError): # Gatau napa err ini + return + except KeyError: + return await callback_query.message.edit_msg(strings("invalid_cb")) + except QueryIdInvalid: + return + + try: + savefilmres, PageLen, btn = await getDataSavefilm21( + callback_query.message, + kueri, + CurrentPage, + callback_query.from_user.id, + strings, + ) + except TypeError: + return + + keyboard = InlineKeyboard() + keyboard.paginate( + PageLen, + CurrentPage, + "page_sf21#{number}" + f"#{message_id}#{callback_query.from_user.id}", + ) + keyboard.row(InlineButton(strings("ex_data"), user_id=self.me.id)) + keyboard.row(*btn) + keyboard.row( + InlineButton(strings("cl_btn"), f"close#{callback_query.from_user.id}") + ) + await callback_query.message.edit_msg( + savefilmres, disable_web_page_preview=True, reply_markup=keyboard + ) + + +# NoDrakor Page Callback +@app.on_cb("page_nodrakor#") +@use_chat_lang() +async def nodrakorpage_cb(self, callback_query, strings): + try: + if callback_query.from_user.id != int(callback_query.data.split("#")[3]): + return await callback_query.answer(strings("unauth"), True) + message_id = int(callback_query.data.split("#")[2]) + CurrentPage = int(callback_query.data.split("#")[1]) + kueri = SCRAP_DICT[message_id][1] + except (IndexError, ValueError): + return + except KeyError: + return await callback_query.message.edit_msg(strings("invalid_cb")) + except QueryIdInvalid: + return + + try: + nodrakorres, PageLen, btn = await getDataNodrakor( + callback_query.message, + kueri, + CurrentPage, + callback_query.from_user.id, + strings, + ) + except TypeError: + return + + keyboard = InlineKeyboard() + keyboard.paginate( + PageLen, + CurrentPage, + "page_nodrakor#{number}" + f"#{message_id}#{callback_query.from_user.id}", + ) + keyboard.row(InlineButton(strings("ex_data"), user_id=self.me.id)) + keyboard.row(*btn) + keyboard.row( + InlineButton(strings("cl_btn"), f"close#{callback_query.from_user.id}") + ) + await callback_query.message.edit_msg( + nodrakorres, disable_web_page_preview=True, reply_markup=keyboard + ) + + +# Kuso Page Callback +@app.on_cb("page_kuso#") +@use_chat_lang() +async def kusopage_callback(self, callback_query, strings): + try: + if callback_query.from_user.id != int(callback_query.data.split("#")[3]): + return await callback_query.answer(strings("unauth"), True) + message_id = int(callback_query.data.split("#")[2]) + CurrentPage = int(callback_query.data.split("#")[1]) + kueri = SCRAP_DICT[message_id][1] + except QueryIdInvalid: + return + except KeyError: + return await callback_query.message.edit_msg(strings("invalid_cb")) + + try: + kusores, PageLen, btn1, btn2 = await getDataKuso( + callback_query.message, + kueri, + CurrentPage, + callback_query.from_user.id, + strings, + ) + except TypeError: + return + + keyboard = InlineKeyboard() + keyboard.paginate( + PageLen, + CurrentPage, + "page_kuso#{number}" + f"#{message_id}#{callback_query.from_user.id}", + ) + keyboard.row(InlineButton(strings("ex_data"), user_id=self.me.id)) + keyboard.row(*btn1) + if btn2: + keyboard.row(*btn2) + keyboard.row( + InlineButton(strings("cl_btn"), f"close#{callback_query.from_user.id}") + ) + await callback_query.message.edit_msg( + kusores, disable_web_page_preview=True, reply_markup=keyboard + ) + + +# Lendrive Page Callback +@app.on_cb("page_lendrive#") +@use_chat_lang() +async def lendrivepage_callback(self, callback_query, strings): + try: + if callback_query.from_user.id != int(callback_query.data.split("#")[3]): + return await callback_query.answer(strings("unauth"), True) + message_id = int(callback_query.data.split("#")[2]) + CurrentPage = int(callback_query.data.split("#")[1]) + kueri = savedict[message_id][1] + except QueryIdInvalid: + return + except KeyError: + return await callback_query.message.edit_msg(strings("invalid_cb")) + + try: + lendres, PageLen, btn = await getDataLendrive( + callback_query.message, + kueri, + CurrentPage, + callback_query.from_user.id, + strings, + ) + except TypeError: + return + + keyboard = InlineKeyboard() + keyboard.paginate( + PageLen, + CurrentPage, + "page_lendrive#{number}" + f"#{message_id}#{callback_query.from_user.id}", + ) + keyboard.row(InlineButton(strings("ex_data"), user_id=self.me.id)) + keyboard.row(*btn) + keyboard.row( + InlineButton(strings("cl_btn"), f"close#{callback_query.from_user.id}") + ) + await callback_query.message.edit_msg( + lendres, disable_web_page_preview=True, reply_markup=keyboard + ) + + +# Movieku Page Callback +@app.on_cb("page_movieku#") +@use_chat_lang() +async def moviekupage_callback(_, callback_query, strings): + try: + if callback_query.from_user.id != int(callback_query.data.split("#")[3]): + return await callback_query.answer(strings("unauth"), True) + message_id = int(callback_query.data.split("#")[2]) + CurrentPage = int(callback_query.data.split("#")[1]) + kueri = SCRAP_DICT[message_id][1] + except QueryIdInvalid: + return + except KeyError: + return await callback_query.message.edit_msg(strings("invalid_cb"), True) + + try: + moviekures, PageLen = await getDataMovieku( + callback_query.message, kueri, CurrentPage, strings + ) + except TypeError: + return + + keyboard = InlineKeyboard() + keyboard.paginate( + PageLen, + CurrentPage, + "page_movieku#{number}" + f"#{message_id}#{callback_query.from_user.id}", + ) + keyboard.row( + InlineButton(strings("cl_btn"), f"close#{callback_query.from_user.id}") + ) + await callback_query.message.edit_msg( + moviekures, disable_web_page_preview=True, reply_markup=keyboard + ) + + +# Samehada Page Callback +@app.on_cb("page_same#") +@use_chat_lang() +async def samepg(_, query, strings): + try: + _, current_page, _id, user_id = query.data.split("#") + if int(user_id) != query.from_user.id: + return await query.answer(strings("unauth"), True) + lquery = savedict[int(_id)][1] + except QueryIdInvalid: + return + except KeyError: + return await query.message.edit_msg(strings("invalid_cb")) + try: + sameres, PageLen = await getSame( + query.message, lquery, int(current_page), strings + ) + except TypeError: + return + keyboard = InlineKeyboard() + keyboard.paginate( + PageLen, + int(current_page), + "page_same#{number}" + f"#{_id}#{query.from_user.id}", + ) + keyboard.row(InlineButton(strings("cl_btn"), f"close#{query.from_user.id}")) + await query.message.edit_msg( + sameres, disable_web_page_preview=True, reply_markup=keyboard + ) + + +# Terbit21 Page Callback +@app.on_cb("page_terbit21#") +@use_chat_lang() +async def terbit21page_callback(_, callback_query, strings): + try: + if callback_query.from_user.id != int(callback_query.data.split("#")[3]): + return await callback_query.answer(strings("unauth"), True) + message_id = int(callback_query.data.split("#")[2]) + CurrentPage = int(callback_query.data.split("#")[1]) + kueri = SCRAP_DICT[message_id][1] + except QueryIdInvalid: + return + except KeyError: + return await callback_query.message.edit_msg(strings("invalid_cb")) + + try: + terbitres, PageLen = await getDataTerbit21( + callback_query.message, kueri, CurrentPage, strings + ) + except TypeError: + return + + keyboard = InlineKeyboard() + keyboard.paginate( + PageLen, + CurrentPage, + "page_terbit21#{number}" + f"#{message_id}#{callback_query.from_user.id}", + ) + keyboard.row( + InlineButton(strings("cl_btn"), f"close#{callback_query.from_user.id}") + ) + await callback_query.message.edit_msg( + terbitres, disable_web_page_preview=True, reply_markup=keyboard + ) + + +# Page Callback Melong +@app.on_cb("page_melong#") +@use_chat_lang() +async def melongpage_callback(self, callback_query, strings): + try: + if callback_query.from_user.id != int(callback_query.data.split("#")[3]): + return await callback_query.answer(strings("unauth"), True) + message_id = int(callback_query.data.split("#")[2]) + CurrentPage = int(callback_query.data.split("#")[1]) + kueri = SCRAP_DICT[message_id][1] + except QueryIdInvalid: + return + except KeyError: + return await callback_query.message.edit_msg(strings("invalid_cb")) + + try: + terbitres, PageLen, btn = await getDataMelong( + callback_query.message, + kueri, + CurrentPage, + callback_query.from_user.id, + strings, + ) + except TypeError: + return + + keyboard = InlineKeyboard() + keyboard.paginate( + PageLen, + CurrentPage, + "page_melong#{number}" + f"#{message_id}#{callback_query.from_user.id}", + ) + keyboard.row(InlineButton(strings("ex_data"), user_id=self.me.id)) + keyboard.row(*btn) + keyboard.row( + InlineButton(strings("cl_btn"), f"close#{callback_query.from_user.id}") + ) + await callback_query.message.edit_msg( + terbitres, disable_web_page_preview=True, reply_markup=keyboard + ) + + +# Lk21 Page Callback +@app.on_cb("page_lk21#") +@use_chat_lang() +async def lk21page_callback(_, callback_query, strings): + try: + if callback_query.from_user.id != int(callback_query.data.split("#")[3]): + return await callback_query.answer(strings("unauth"), True) + message_id = int(callback_query.data.split("#")[2]) + CurrentPage = int(callback_query.data.split("#")[1]) + kueri = SCRAP_DICT[message_id][1] + except QueryIdInvalid: + return + except KeyError: + return await callback_query.message.edit_msg(strings("invalid_cb")) + + try: + lkres, PageLen = await getDatalk21( + callback_query.message, kueri, CurrentPage, strings + ) + except TypeError: + return + + keyboard = InlineKeyboard() + keyboard.paginate( + PageLen, + CurrentPage, + "page_lk21#{number}" + f"#{message_id}#{callback_query.from_user.id}", + ) + keyboard.row( + InlineButton(strings("cl_btn"), f"close#{callback_query.from_user.id}") + ) + await callback_query.message.edit_msg( + lkres, disable_web_page_preview=True, reply_markup=keyboard + ) + + +# Pahe Page Callback +@app.on_cb("page_pahe#") +@use_chat_lang() +async def pahepage_callback(_, callback_query, strings): + try: + if callback_query.from_user.id != int(callback_query.data.split("#")[3]): + return await callback_query.answer(strings("unauth"), True) + message_id = int(callback_query.data.split("#")[2]) + CurrentPage = int(callback_query.data.split("#")[1]) + kueri = SCRAP_DICT[message_id][1] + except QueryIdInvalid: + return + except KeyError: + return await callback_query.message.edit_msg(strings("invalid_cb")) + + try: + lkres, PageLen = await getDataPahe( + callback_query.message, kueri, CurrentPage, strings + ) + except TypeError: + return + + keyboard = InlineKeyboard() + keyboard.paginate( + PageLen, + CurrentPage, + "page_pahe#{number}" + f"#{message_id}#{callback_query.from_user.id}", + ) + keyboard.row( + InlineButton(strings("cl_btn"), f"close#{callback_query.from_user.id}") + ) + await callback_query.message.edit_msg( + lkres, disable_web_page_preview=True, reply_markup=keyboard + ) + + +# Gomov Page Callback +@app.on_cb("page_gomov#") +@use_chat_lang() +async def gomovpage_callback(self, callback_query, strings): + try: + if callback_query.from_user.id != int(callback_query.data.split("#")[3]): + return await callback_query.answer(strings("unauth"), True) + message_id = int(callback_query.data.split("#")[2]) + CurrentPage = int(callback_query.data.split("#")[1]) + kueri = SCRAP_DICT[message_id][1] + except QueryIdInvalid: + return + except KeyError: + return await callback_query.message.edit_msg(strings("invalid_cb")) + + try: + gomovres, PageLen, btn = await getDataGomov( + callback_query.message, + kueri, + CurrentPage, + callback_query.from_user.id, + strings, + ) + except TypeError: + return + + keyboard = InlineKeyboard() + keyboard.paginate( + PageLen, + CurrentPage, + "page_gomov#{number}" + f"#{message_id}#{callback_query.from_user.id}", + ) + keyboard.row(InlineButton(strings("ex_data"), user_id=self.me.id)) + keyboard.row(*btn) + keyboard.row( + InlineButton(strings("cl_btn"), f"close#{callback_query.from_user.id}") + ) + await callback_query.message.edit_msg( + gomovres, disable_web_page_preview=True, reply_markup=keyboard + ) + + +### Scrape DDL Link From Web ### +# Kusonime DDL +@app.on_cb("kusoextract#") +@use_chat_lang() +async def kusonime_scrap(client, callback_query, strings): + try: + if callback_query.from_user.id != int(callback_query.data.split("#")[3]): + return await callback_query.answer(strings("unauth"), True) + idlink = int(callback_query.data.split("#")[2]) + message_id = int(callback_query.data.split("#")[4]) + CurrentPage = int(callback_query.data.split("#")[1]) + link = SCRAP_DICT[message_id][0][CurrentPage - 1][idlink - 1].get("link") + except QueryIdInvalid: + return + except KeyError: + return await callback_query.message.edit_msg(strings("invalid_cb")) + + kuso = Kusonime() + keyboard = InlineKeyboard() + keyboard.row( + InlineButton( + strings("back_btn"), + f"page_kuso#{CurrentPage}#{message_id}#{callback_query.from_user.id}", + ), + InlineButton(strings("cl_btn"), f"close#{callback_query.from_user.id}"), + ) + try: + if init_url := data_kuso.get(link, False): + await callback_query.message.edit_msg( + init_url.get("ph_url"), reply_markup=keyboard + ) + tgh = await kuso.telegraph(link, client.me.username) + data_kuso[link] = {"ph_url": tgh} + return await callback_query.message.edit_msg(tgh, reply_markup=keyboard) + except Exception as e: + LOGGER.error(f"clases: {e.__class__}, moduleName: {e.__class__.__name__}") + if str(e).startswith("ERROR"): + return await callback_query.message.edit_msg(e, reply_markup=keyboard) + + +# Savefilm21 DDL +@app.on_cb("sf21extract#") +@use_chat_lang() +async def savefilm21_scrap(_, callback_query, strings): + try: + if callback_query.from_user.id != int(callback_query.data.split("#")[3]): + return await callback_query.answer(strings("unauth"), True) + idlink = int(callback_query.data.split("#")[2]) + message_id = int(callback_query.data.split("#")[4]) + CurrentPage = int(callback_query.data.split("#")[1]) + link = SCRAP_DICT[message_id][0][CurrentPage - 1][idlink - 1].get("link") + except QueryIdInvalid: + return + except KeyError: + return await callback_query.message.edit_msg(strings("invalid_cb")) + + keyboard = InlineKeyboard() + keyboard.row( + InlineButton( + strings("back_btn"), + f"page_sf21#{CurrentPage}#{message_id}#{callback_query.from_user.id}", + ), + InlineButton(strings("cl_btn"), f"close#{callback_query.from_user.id}"), + ) + with contextlib.redirect_stdout(sys.stderr): + try: + html = await fetch.get(link) + html.raise_for_status() + soup = BeautifulSoup(html.text, "lxml") + res = soup.find_all(class_="button button-shadow") + res = "".join(f"{i.text}\n{i['href']}\n\n" for i in res) + await callback_query.message.edit_msg( + strings("res_scrape").format(link=link, kl=res), reply_markup=keyboard + ) + except httpx.HTTPError as exc: + await callback_query.message.edit_msg( + f"HTTP Exception for {exc.request.url} - {exc}", + reply_markup=keyboard, + ) + except Exception as err: + await callback_query.message.edit_msg( + f"ERROR: {err}", reply_markup=keyboard + ) + + +# NoDrakor DDL +@app.on_cb("nodrakorextract#") +@use_chat_lang() +async def nodrakorddl_scrap(_, callback_query, strings): + try: + if callback_query.from_user.id != int(callback_query.data.split("#")[3]): + return await callback_query.answer(strings("unauth"), True) + idlink = int(callback_query.data.split("#")[2]) + message_id = int(callback_query.data.split("#")[4]) + CurrentPage = int(callback_query.data.split("#")[1]) + link = SCRAP_DICT[message_id][0][CurrentPage - 1][idlink - 1].get("link") + except QueryIdInvalid: + return + except KeyError: + return await callback_query.message.edit_msg(strings("invalid_cb")) + + keyboard = InlineKeyboard() + keyboard.row( + InlineButton( + strings("back_btn"), + f"page_nodrakor#{CurrentPage}#{message_id}#{callback_query.from_user.id}", + ), + InlineButton(strings("cl_btn"), f"close#{callback_query.from_user.id}"), + ) + with contextlib.redirect_stdout(sys.stderr): + try: + html = await fetch.get(link) + html.raise_for_status() + soup = BeautifulSoup(html.text, "lxml") + if "/tv/" in link: + result = soup.find( + "div", {"entry-content entry-content-single"} + ).find_all("p") + msg = "".join(str(f"{i}\n") for i in result) + link = await post_to_telegraph(False, "MissKaty NoDrakor", msg) + return await callback_query.message.edit_msg( + strings("res_scrape").format(link=link, kl=link), + reply_markup=keyboard, + ) + res = soup.find_all(class_="button button-shadow") + res = "".join(f"{i.text}\n{i['href']}\n\n" for i in res) + if len(res) > 3500: + link = await post_to_telegraph(False, "MissKaty NoDrakor", res) + return await callback_query.message.edit_msg( + strings("res_scrape").format(link=link, kl=link), + reply_markup=keyboard, + ) + await callback_query.message.edit_msg( + strings("res_scrape").format(link=link, kl=res), reply_markup=keyboard + ) + except httpx.HTTPError as exc: + await callback_query.message.edit_msg( + f"HTTP Exception for {exc.request.url} - {exc}", + reply_markup=keyboard, + ) + except Exception as err: + await callback_query.message.edit_msg( + f"ERROR: {err}", reply_markup=keyboard + ) + + +# Scrape Link Download Movieku.CC +@app.on_cmd("movieku_scrap") +@use_chat_lang() +async def muviku_scrap(_, message, strings): + with contextlib.redirect_stdout(sys.stderr): + try: + link = message.text.split(maxsplit=1)[1] + html = await fetch.get(link) + html.raise_for_status() + soup = BeautifulSoup(html.text, "lxml") + res = soup.find_all(class_="smokeurl") + data = [] + for i in res: + for b in range(len(i.find_all("a"))): + link = i.find_all("a")[b]["href"] + kualitas = i.find_all("a")[b].text + # print(f"{kualitas}\n{link + data.append({"link": link, "kualitas": kualitas}) + if not data: + return await message.reply(strings("no_result")) + res = "".join( + f"Host: {i['kualitas']}\n{i['link']}\n\n" for i in data + ) + await message.reply(res) + except IndexError: + return await message.reply( + strings("invalid_cmd_scrape").format(cmd=message.command[0]) + ) + except httpx.HTTPError as exc: + await message.reply( + f"HTTP Exception for {exc.request.url} - {exc}" + ) + except Exception as e: + await message.reply(f"ERROR: {str(e)}") + + +# Scrape DDL Link Melongmovie +@app.on_cb("melongextract#") +@use_chat_lang() +async def melong_scrap(_, callback_query, strings): + try: + if callback_query.from_user.id != int(callback_query.data.split("#")[3]): + return await callback_query.answer(strings("unauth"), True) + idlink = int(callback_query.data.split("#")[2]) + message_id = int(callback_query.data.split("#")[4]) + CurrentPage = int(callback_query.data.split("#")[1]) + link = SCRAP_DICT[message_id][0][CurrentPage - 1][idlink - 1].get("link") + except QueryIdInvalid: + return + except KeyError: + return await callback_query.message.edit_msg(strings("invalid_cb")) + + keyboard = InlineKeyboard() + keyboard.row( + InlineButton( + strings("back_btn"), + f"page_melong#{CurrentPage}#{message_id}#{callback_query.from_user.id}", + ), + InlineButton(strings("cl_btn"), f"close#{callback_query.from_user.id}"), + ) + with contextlib.redirect_stdout(sys.stderr): + try: + html = await fetch.get(link) + html.raise_for_status() + soup = BeautifulSoup(html.text, "lxml") + rep = "" + for ep in soup.findAll(text=re.compile(r"(?i)episode\s+\d+|LINK DOWNLOAD")): + hardsub = ep.findPrevious("div") + softsub = ep.findNext("div") + rep += f"{hardsub}\n{softsub}" + await callback_query.message.edit_msg( + strings("res_scrape").format(link=link, kl=rep), reply_markup=keyboard + ) + except httpx.HTTPError as exc: + await callback_query.message.edit_msg( + f"HTTP Exception for {exc.request.url} - {exc}", + reply_markup=keyboard, + ) + except Exception as err: + await callback_query.message.edit_msg( + f"ERROR: {err}", reply_markup=keyboard + ) + + +# Scrape DDL Link Gomov +@app.on_cb("gomovextract#") +@use_chat_lang() +async def gomov_dl(_, callback_query, strings): + try: + if callback_query.from_user.id != int(callback_query.data.split("#")[3]): + return await callback_query.answer(strings("unauth"), True) + idlink = int(callback_query.data.split("#")[2]) + message_id = int(callback_query.data.split("#")[4]) + CurrentPage = int(callback_query.data.split("#")[1]) + link = SCRAP_DICT[message_id][0][CurrentPage - 1][idlink - 1].get("link") + except QueryIdInvalid: + return + except KeyError: + return await callback_query.message.edit_msg(strings("invalid_cb")) + + keyboard = InlineKeyboard() + keyboard.row( + InlineButton( + strings("back_btn"), + f"page_gomov#{CurrentPage}#{message_id}#{callback_query.from_user.id}", + ), + InlineButton(strings("cl_btn"), f"close#{callback_query.from_user.id}"), + ) + with contextlib.redirect_stdout(sys.stderr): + try: + html = await fetch.get(link) + html.raise_for_status() + soup = BeautifulSoup(html.text, "lxml") + entry = soup.find(class_="gmr-download-wrap clearfix") + hasil = soup.find(class_="title-download").text + for i in entry.find(class_="list-inline gmr-download-list clearfix"): + title = i.find("a").text + ddl = i.find("a")["href"] + hasil += f"\n{title}\n{ddl}\n" + await callback_query.message.edit_msg( + strings("res_scrape").format(link=link, kl=hasil), reply_markup=keyboard + ) + except httpx.HTTPError as exc: + await callback_query.message.edit_msg( + f"HTTP Exception for {exc.request.url} - {exc}", + reply_markup=keyboard, + ) + except Exception as err: + await callback_query.message.edit_msg( + f"ERROR: {err}", reply_markup=keyboard + ) + + +@app.on_cb("lendriveextract#") +@use_chat_lang() +async def lendrive_dl(_, callback_query, strings): + if callback_query.from_user.id != int(callback_query.data.split("#")[3]): + return await callback_query.answer(strings("unauth"), True) + idlink = int(callback_query.data.split("#")[2]) + message_id = int(callback_query.data.split("#")[4]) + CurrentPage = int(callback_query.data.split("#")[1]) + try: + link = savedict[message_id][0][CurrentPage - 1][idlink - 1].get("link") + except KeyError: + return await callback_query.message.edit_msg(strings("invalid_cb")) + + keyboard = InlineKeyboard() + keyboard.row( + InlineButton( + strings("back_btn"), + f"page_lendrive#{CurrentPage}#{message_id}#{callback_query.from_user.id}", + ), + InlineButton(strings("cl_btn"), f"close#{callback_query.from_user.id}"), + ) + with contextlib.redirect_stdout(sys.stderr): + try: + hmm = await fetch.get(link) + hmm.raise_for_status() + q = BeautifulSoup(hmm.text, "lxml") + j = q.findAll("div", class_="soraurlx") + kl = "" + for i in j: + if not i.find("a"): + continue + kl += f"{i.find('strong')}:\n" + kl += "".join( + f"[ {a.text} ]\n" + for a in i.findAll("a") + ) + await callback_query.message.edit_msg( + strings("res_scrape").format(link=link, kl=kl), reply_markup=keyboard + ) + except httpx.HTTPError as exc: + await callback_query.message.edit_msg( + f"HTTP Exception for {exc.request.url} - {exc}", + reply_markup=keyboard, + ) + except Exception as err: + await callback_query.message.edit_msg( + f"ERROR: {err}", reply_markup=keyboard + ) diff --git a/requirements.txt b/requirements.txt index 87d7f3cc..e30cf195 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,36 +1,36 @@ -emoji -git+https://github.com/yasirarism/pyrofork -tgcrypto -async_pymongo -pymongo -python-dotenv -requests -beautifulsoup4 -aiohttp -chevron -cv-3 -gTTS -regex -apscheduler==3.10.4 -pytz -pykeyboard -pySmartDL -psutil -python-dateutil -telegraph -hachoir -Pillow==10.4.0 -PrivateBinAPI -httpx[http2] -git+https://github.com/yasirarism/vcsi -git+https://github.com/yasirarism/iytdl -deep-translator -telethon -pyrate_limiter -cachetools -cloudscraper -openai==1.3.2 -GitPython -aiofiles -uvloop==0.19.0 -lxml_html_clean +emoji +git+https://github.com/yasirarism/pyrofork +tgcrypto +async_pymongo +pymongo +python-dotenv +requests +beautifulsoup4 +aiohttp +chevron +cv-3 +gTTS +regex +apscheduler==3.10.4 +pytz +pykeyboard +pySmartDL +psutil +python-dateutil +telegraph +hachoir +Pillow==10.4.0 +PrivateBinAPI +httpx[http2] +git+https://github.com/yasirarism/vcsi +git+https://github.com/yasirarism/iytdl +deep-translator +telethon +pyrate_limiter +cachetools +cloudscraper +openai==1.3.2 +GitPython +aiofiles +uvloop==0.19.0 +lxml_html_clean