├── Dockerfile ├── LICENSE ├── Procfile ├── README.md ├── Script.py ├── app.json ├── bot.py ├── database ├── connections_mdb.py ├── filters_mdb.py ├── ia_filterdb.py └── users_chats_db.py ├── heroku.yml ├── info.py ├── logging.conf ├── plugins ├── __init__.py ├── banned.py ├── broadcast.py ├── channel.py ├── commands.py ├── connection.py ├── filters.py ├── genlink.py ├── index.py ├── inline.py ├── misc.py ├── p_ttishow.py ├── pm_filter.py └── route.py ├── requirements.txt ├── runtime.txt ├── start.sh └── utils.py /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.10-slim-buster 2 | 3 | RUN apt update && apt upgrade -y 4 | RUN apt install git -y 5 | COPY requirements.txt /requirements.txt 6 | 7 | RUN cd / 8 | RUN pip3 install -U pip && pip3 install -U -r requirements.txt 9 | RUN mkdir /LazyPrincessV2 10 | WORKDIR /LazyPrincessV2 11 | COPY start.sh /start.sh 12 | CMD ["/bin/bash", "/start.sh"] 13 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | Version 2, June 1991 3 | 4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc., 5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 6 | Everyone is permitted to copy and distribute verbatim copies 7 | of this license document, but changing it is not allowed. 8 | 9 | Preamble 10 | 11 | The licenses for most software are designed to take away your 12 | freedom to share and change it. By contrast, the GNU General Public 13 | License is intended to guarantee your freedom to share and change free 14 | software--to make sure the software is free for all its users. This 15 | General Public License applies to most of the Free Software 16 | Foundation's software and to any other program whose authors commit to 17 | using it. (Some other Free Software Foundation software is covered by 18 | the GNU Lesser General Public License instead.) You can apply it to 19 | your programs, too. 20 | 21 | When we speak of free software, we are referring to freedom, not 22 | price. Our General Public Licenses are designed to make sure that you 23 | have the freedom to distribute copies of free software (and charge for 24 | this service if you wish), that you receive source code or can get it 25 | if you want it, that you can change the software or use pieces of it 26 | in new free programs; and that you know you can do these things. 27 | 28 | To protect your rights, we need to make restrictions that forbid 29 | anyone to deny you these rights or to ask you to surrender the rights. 30 | These restrictions translate to certain responsibilities for you if you 31 | distribute copies of the software, or if you modify it. 32 | 33 | For example, if you distribute copies of such a program, whether 34 | gratis or for a fee, you must give the recipients all the rights that 35 | you have. You must make sure that they, too, receive or can get the 36 | source code. And you must show them these terms so they know their 37 | rights. 38 | 39 | We protect your rights with two steps: (1) copyright the software, and 40 | (2) offer you this license which gives you legal permission to copy, 41 | distribute and/or modify the software. 42 | 43 | Also, for each author's protection and ours, we want to make certain 44 | that everyone understands that there is no warranty for this free 45 | software. If the software is modified by someone else and passed on, we 46 | want its recipients to know that what they have is not the original, so 47 | that any problems introduced by others will not reflect on the original 48 | authors' reputations. 49 | 50 | Finally, any free program is threatened constantly by software 51 | patents. We wish to avoid the danger that redistributors of a free 52 | program will individually obtain patent licenses, in effect making the 53 | program proprietary. To prevent this, we have made it clear that any 54 | patent must be licensed for everyone's free use or not licensed at all. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | GNU GENERAL PUBLIC LICENSE 60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 61 | 62 | 0. This License applies to any program or other work which contains 63 | a notice placed by the copyright holder saying it may be distributed 64 | under the terms of this General Public License. The "Program", below, 65 | refers to any such program or work, and a "work based on the Program" 66 | means either the Program or any derivative work under copyright law: 67 | that is to say, a work containing the Program or a portion of it, 68 | either verbatim or with modifications and/or translated into another 69 | language. (Hereinafter, translation is included without limitation in 70 | the term "modification".) Each licensee is addressed as "you". 71 | 72 | Activities other than copying, distribution and modification are not 73 | covered by this License; they are outside its scope. The act of 74 | running the Program is not restricted, and the output from the Program 75 | is covered only if its contents constitute a work based on the 76 | Program (independent of having been made by running the Program). 77 | Whether that is true depends on what the Program does. 78 | 79 | 1. You may copy and distribute verbatim copies of the Program's 80 | source code as you receive it, in any medium, provided that you 81 | conspicuously and appropriately publish on each copy an appropriate 82 | copyright notice and disclaimer of warranty; keep intact all the 83 | notices that refer to this License and to the absence of any warranty; 84 | and give any other recipients of the Program a copy of this License 85 | along with the Program. 86 | 87 | You may charge a fee for the physical act of transferring a copy, and 88 | you may at your option offer warranty protection in exchange for a fee. 89 | 90 | 2. You may modify your copy or copies of the Program or any portion 91 | of it, thus forming a work based on the Program, and copy and 92 | distribute such modifications or work under the terms of Section 1 93 | above, provided that you also meet all of these conditions: 94 | 95 | a) You must cause the modified files to carry prominent notices 96 | stating that you changed the files and the date of any change. 97 | 98 | b) You must cause any work that you distribute or publish, that in 99 | whole or in part contains or is derived from the Program or any 100 | part thereof, to be licensed as a whole at no charge to all third 101 | parties under the terms of this License. 102 | 103 | c) If the modified program normally reads commands interactively 104 | when run, you must cause it, when started running for such 105 | interactive use in the most ordinary way, to print or display an 106 | announcement including an appropriate copyright notice and a 107 | notice that there is no warranty (or else, saying that you provide 108 | a warranty) and that users may redistribute the program under 109 | these conditions, and telling the user how to view a copy of this 110 | License. (Exception: if the Program itself is interactive but 111 | does not normally print such an announcement, your work based on 112 | the Program is not required to print an announcement.) 113 | 114 | These requirements apply to the modified work as a whole. If 115 | identifiable sections of that work are not derived from the Program, 116 | and can be reasonably considered independent and separate works in 117 | themselves, then this License, and its terms, do not apply to those 118 | sections when you distribute them as separate works. But when you 119 | distribute the same sections as part of a whole which is a work based 120 | on the Program, the distribution of the whole must be on the terms of 121 | this License, whose permissions for other licensees extend to the 122 | entire whole, and thus to each and every part regardless of who wrote it. 123 | 124 | Thus, it is not the intent of this section to claim rights or contest 125 | your rights to work written entirely by you; rather, the intent is to 126 | exercise the right to control the distribution of derivative or 127 | collective works based on the Program. 128 | 129 | In addition, mere aggregation of another work not based on the Program 130 | with the Program (or with a work based on the Program) on a volume of 131 | a storage or distribution medium does not bring the other work under 132 | the scope of this License. 133 | 134 | 3. You may copy and distribute the Program (or a work based on it, 135 | under Section 2) in object code or executable form under the terms of 136 | Sections 1 and 2 above provided that you also do one of the following: 137 | 138 | a) Accompany it with the complete corresponding machine-readable 139 | source code, which must be distributed under the terms of Sections 140 | 1 and 2 above on a medium customarily used for software interchange; or, 141 | 142 | b) Accompany it with a written offer, valid for at least three 143 | years, to give any third party, for a charge no more than your 144 | cost of physically performing source distribution, a complete 145 | machine-readable copy of the corresponding source code, to be 146 | distributed under the terms of Sections 1 and 2 above on a medium 147 | customarily used for software interchange; or, 148 | 149 | c) Accompany it with the information you received as to the offer 150 | to distribute corresponding source code. (This alternative is 151 | allowed only for noncommercial distribution and only if you 152 | received the program in object code or executable form with such 153 | an offer, in accord with Subsection b above.) 154 | 155 | The source code for a work means the preferred form of the work for 156 | making modifications to it. For an executable work, complete source 157 | code means all the source code for all modules it contains, plus any 158 | associated interface definition files, plus the scripts used to 159 | control compilation and installation of the executable. However, as a 160 | special exception, the source code distributed need not include 161 | anything that is normally distributed (in either source or binary 162 | form) with the major components (compiler, kernel, and so on) of the 163 | operating system on which the executable runs, unless that component 164 | itself accompanies the executable. 165 | 166 | If distribution of executable or object code is made by offering 167 | access to copy from a designated place, then offering equivalent 168 | access to copy the source code from the same place counts as 169 | distribution of the source code, even though third parties are not 170 | compelled to copy the source along with the object code. 171 | 172 | 4. You may not copy, modify, sublicense, or distribute the Program 173 | except as expressly provided under this License. Any attempt 174 | otherwise to copy, modify, sublicense or distribute the Program is 175 | void, and will automatically terminate your rights under this License. 176 | However, parties who have received copies, or rights, from you under 177 | this License will not have their licenses terminated so long as such 178 | parties remain in full compliance. 179 | 180 | 5. You are not required to accept this License, since you have not 181 | signed it. However, nothing else grants you permission to modify or 182 | distribute the Program or its derivative works. These actions are 183 | prohibited by law if you do not accept this License. Therefore, by 184 | modifying or distributing the Program (or any work based on the 185 | Program), you indicate your acceptance of this License to do so, and 186 | all its terms and conditions for copying, distributing or modifying 187 | the Program or works based on it. 188 | 189 | 6. Each time you redistribute the Program (or any work based on the 190 | Program), the recipient automatically receives a license from the 191 | original licensor to copy, distribute or modify the Program subject to 192 | these terms and conditions. You may not impose any further 193 | restrictions on the recipients' exercise of the rights granted herein. 194 | You are not responsible for enforcing compliance by third parties to 195 | this License. 196 | 197 | 7. If, as a consequence of a court judgment or allegation of patent 198 | infringement or for any other reason (not limited to patent issues), 199 | conditions are imposed on you (whether by court order, agreement or 200 | otherwise) that contradict the conditions of this License, they do not 201 | excuse you from the conditions of this License. If you cannot 202 | distribute so as to satisfy simultaneously your obligations under this 203 | License and any other pertinent obligations, then as a consequence you 204 | may not distribute the Program at all. For example, if a patent 205 | license would not permit royalty-free redistribution of the Program by 206 | all those who receive copies directly or indirectly through you, then 207 | the only way you could satisfy both it and this License would be to 208 | refrain entirely from distribution of the Program. 209 | 210 | If any portion of this section is held invalid or unenforceable under 211 | any particular circumstance, the balance of the section is intended to 212 | apply and the section as a whole is intended to apply in other 213 | circumstances. 214 | 215 | It is not the purpose of this section to induce you to infringe any 216 | patents or other property right claims or to contest validity of any 217 | such claims; this section has the sole purpose of protecting the 218 | integrity of the free software distribution system, which is 219 | implemented by public license practices. Many people have made 220 | generous contributions to the wide range of software distributed 221 | through that system in reliance on consistent application of that 222 | system; it is up to the author/donor to decide if he or she is willing 223 | to distribute software through any other system and a licensee cannot 224 | impose that choice. 225 | 226 | This section is intended to make thoroughly clear what is believed to 227 | be a consequence of the rest of this License. 228 | 229 | 8. If the distribution and/or use of the Program is restricted in 230 | certain countries either by patents or by copyrighted interfaces, the 231 | original copyright holder who places the Program under this License 232 | may add an explicit geographical distribution limitation excluding 233 | those countries, so that distribution is permitted only in or among 234 | countries not thus excluded. In such case, this License incorporates 235 | the limitation as if written in the body of this License. 236 | 237 | 9. The Free Software Foundation may publish revised and/or new versions 238 | of the General Public License from time to time. Such new versions will 239 | be similar in spirit to the present version, but may differ in detail to 240 | address new problems or concerns. 241 | 242 | Each version is given a distinguishing version number. If the Program 243 | specifies a version number of this License which applies to it and "any 244 | later version", you have the option of following the terms and conditions 245 | either of that version or of any later version published by the Free 246 | Software Foundation. If the Program does not specify a version number of 247 | this License, you may choose any version ever published by the Free Software 248 | Foundation. 249 | 250 | 10. If you wish to incorporate parts of the Program into other free 251 | programs whose distribution conditions are different, write to the author 252 | to ask for permission. For software which is copyrighted by the Free 253 | Software Foundation, write to the Free Software Foundation; we sometimes 254 | make exceptions for this. Our decision will be guided by the two goals 255 | of preserving the free status of all derivatives of our free software and 256 | of promoting the sharing and reuse of software generally. 257 | 258 | NO WARRANTY 259 | 260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY 261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN 262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES 263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED 264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS 266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE 267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, 268 | REPAIR OR CORRECTION. 269 | 270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR 272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, 273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED 275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY 276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER 277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE 278 | POSSIBILITY OF SUCH DAMAGES. 279 | 280 | END OF TERMS AND CONDITIONS 281 | 282 | How to Apply These Terms to Your New Programs 283 | 284 | If you develop a new program, and you want it to be of the greatest 285 | possible use to the public, the best way to achieve this is to make it 286 | free software which everyone can redistribute and change under these terms. 287 | 288 | To do so, attach the following notices to the program. It is safest 289 | to attach them to the start of each source file to most effectively 290 | convey the exclusion of warranty; and each file should have at least 291 | the "copyright" line and a pointer to where the full notice is found. 292 | 293 | 294 | Copyright (C) 295 | 296 | This program is free software; you can redistribute it and/or modify 297 | it under the terms of the GNU General Public License as published by 298 | the Free Software Foundation; either version 2 of the License, or 299 | (at your option) any later version. 300 | 301 | This program is distributed in the hope that it will be useful, 302 | but WITHOUT ANY WARRANTY; without even the implied warranty of 303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 304 | GNU General Public License for more details. 305 | 306 | You should have received a copy of the GNU General Public License along 307 | with this program; if not, write to the Free Software Foundation, Inc., 308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 309 | 310 | Also add information on how to contact you by electronic and paper mail. 311 | 312 | If the program is interactive, make it output a short notice like this 313 | when it starts in an interactive mode: 314 | 315 | Gnomovision version 69, Copyright (C) year name of author 316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. 317 | This is free software, and you are welcome to redistribute it 318 | under certain conditions; type `show c' for details. 319 | 320 | The hypothetical commands `show w' and `show c' should show the appropriate 321 | parts of the General Public License. Of course, the commands you use may 322 | be called something other than `show w' and `show c'; they could even be 323 | mouse-clicks or menu items--whatever suits your program. 324 | 325 | You should also get your employer (if you work as a programmer) or your 326 | school, if any, to sign a "copyright disclaimer" for the program, if 327 | necessary. Here is a sample; alter the names: 328 | 329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program 330 | `Gnomovision' (which makes passes at compilers) written by James Hacker. 331 | 332 | , 1 April 1989 333 | Ty Coon, President of Vice 334 | 335 | This General Public License does not permit incorporating your program into 336 | proprietary programs. If your program is a subroutine library, you may 337 | consider it more useful to permit linking proprietary applications with the 338 | library. If this is what you want to do, use the GNU Lesser General 339 | Public License instead of this License. 340 | -------------------------------------------------------------------------------- /Procfile: -------------------------------------------------------------------------------- 1 | web: python3 bot.py 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | Lazy Princess Logo 3 |

4 |

5 | Lazy PrincessV2.0 6 |

7 | 8 | 9 | ## Features 10 | 11 | - [x] 🔥 New feature : 12 | - [+] ⚡️ Support 2GB + Files ⚡️ 13 | - [x] Auto Filter 14 | - [x] Manual Filter 15 | - [x] IMDB 16 | - [x] Admin Commands 17 | - [x] Broadcast 18 | - [x] Index 19 | - [x] IMDB search 20 | - [x] Inline Search 21 | - [x] Random pics 22 | - [x] ids and User info 23 | - [x] Stats, Users, Chats, Ban, Unban, Leave, Disable, Channel 24 | - [x] Spelling Check Feature 25 | - [x] File Store 26 | ## • What's New ? 27 | 28 | - [x] URL Shortener Added 29 | - [x] Self Delete Added (Auto delete) 30 | - [x] Filter On Off Option Added 31 | - [x] Custom Welcome Message 32 | - [x] URL Shortener Added 33 | - [x] Custom Download Name And URL 34 | - [x] Custom Texts (About, Help, Stats,More..) 35 | - [x] Custom URL Buttons (Updates channel, Add To Group, Force Sub, More...) 36 | 37 | ## Variables 38 | 39 | Read [this](https://telegram.dog/sources_cods) before you start messing up with your edits. 40 | 41 | ### Required Variables 42 | * `BOT_TOKEN`: Create a bot using [@BotFather](https://telegram.dog/BotFather), and get the Telegram API token. 43 | * `API_ID`: Get this value from [telegram.org](https://my.telegram.org/apps) 44 | * `API_HASH`: Get this value from [telegram.org](https://my.telegram.org/apps) 45 | * `CHANNELS`: Username or ID of channel or group. Separate multiple IDs by space 46 | * `ADMINS`: Username or ID of Admin. Separate multiple Admins by space 47 | * `DATABASE_URI`: [mongoDB](https://www.mongodb.com) URI. Get this value from [mongoDB](https://www.mongodb.com). For more help watch this [video](https://youtu.be/h9QjSSmk5tw) 48 | * `DATABASE_NAME`: Name of the database in [mongoDB](https://www.mongodb.com). For more help watch this [video](https://youtu.be/h9QjSSmk5tw) 49 | * `LOG_CHANNEL` : A channel to log the activities of bot. Make sure bot is an admin in the channel. 50 | ### Optional Variables 51 | * `PICS`: Telegraph links of images to show in start message.( Multiple images can be used separated by space ) 52 | * `FILE_STORE_CHANNEL`: Channel from were file store links of posts should be made.Separate multiple IDs by space 53 | * Check [info.py](https://github.com/AM-ROBOTS/AdvAnurag/blob/main/info.py) for more 54 | ## EXTRA FEATURES 55 | * `URL_SHORTENR_WEBSITE`: URL Shortener Website Link ( Without https://) 56 | * `URL_SHORTNER_WEBSITE_API`: URL Shortener Website API key 57 | * `SELF_DELETE`: True if SELF_DELETE is On, False if Off 58 | * `SELF_DELETE_SECONDS`: Enter Seconds to be SELF_DELETE 59 | * `START_TXT`: Enter Your Start Message 60 | * `ABOUT_TXT`: Enter Your About Message 61 | 62 | 63 | ## Deploy 64 | You can deploy this bot anywhere. 65 | 66 | 67 | Deploy to Koyeb 68 | 69 | 70 |
Deploy To Heroku 71 |

72 |
73 | 74 | Deploy 75 | 76 |

77 |
78 | 79 |
Deploy To VPS 80 |

81 |

 82 | git clone https://github.com/LazyDeveloperr/LazyPrincessv2
 83 | # Install Packages
 84 | pip3 install -U -r requirements.txt
 85 | Edit info.py with variables as given below then run bot
 86 | python3 bot.py
 87 | 
88 |

89 |
90 | 91 | 92 | ## Commands 93 | ``` 94 | • /logs - to get the rescent errors 95 | • /stats - to get status of files in db. 96 | * /filter - add manual filters 97 | * /filters - view filters 98 | * /connect - connect to PM. 99 | * /disconnect - disconnect from PM 100 | * /del - delete a filter 101 | * /delall - delete all filters 102 | * /deleteall - delete all index(autofilter) 103 | * /delete - delete a specific file from index. 104 | * /info - get user info 105 | * /id - get tg ids. 106 | * /imdb - fetch info from imdb. 107 | • /users - to get list of my users and ids. 108 | • /chats - to get list of the my chats and ids 109 | • /index - to add files from a channel 110 | • /leave - to leave from a chat. 111 | • /disable - do disable a chat. 112 | * /enable - re-enable chat. 113 | • /ban - to ban a user. 114 | • /unban - to unban a user. 115 | • /channel - to get list of total connected channels 116 | • /broadcast - to broadcast a message to all LazyPrincess users 117 | • /batch - to create link for multiple posts 118 | • /link - to create link for one post 119 | ``` 120 | ## Support 121 | [![telegram badge](https://img.shields.io/badge/Telegram-Group-30302f?style=flat&logo=telegram)](https://telegram.dog/LazyPrincessSupport) 122 | [![telegram badge](https://img.shields.io/badge/Telegram-Channel-30302f?style=flat&logo=telegram)](https://telegram.dog/LazyDeveloper) 123 | 124 | ## with Love 125 | * [![LazyPrincess-Devs](https://img.shields.io/static/v1?label=LazyPrincess&message=devs&color=critical)](https://telegram.dog/LazyDeveloper) 126 | 127 | 128 | ## Thanks to 129 | - 🦋 Thank you [LazyDeveloper](https://github.com/LazyDeveloperr) for helping us in this journey ❤️. 130 | - 🔺 From the side of [LazyDeveloper](https://github.com/LazyDeveloperr) Thank you [Team-EvaMaria](https://github.com/EvamariaTG) for their awesome repository. 131 | - 🔺 Thanks To Dan For His Awesome [Library](https://github.com/pyrogram/pyrogram). 132 | - 🔺 Thanks To Mahesh For His Awesome [Media-Search-bot](https://github.com/Mahesh0253/Media-Search-bot). 133 | - 🔺 Thanks To [Trojanz](https://github.com/trojanzhex) for Their Awesome [Unlimited Filter Bot](https://github.com/TroJanzHEX/Unlimited-Filter-Bot) And [AutoFilterBoT](https://github.com/trojanzhex/auto-filter-bot). 134 | - Thanks To All Everyone In This Journey 135 | 136 | ### Note 137 | 138 | [Join Developer Channel](https://telegram.dog/LazyDeveloper): LazyDeveloper 139 | 140 | ## Disclaimer 141 | [![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) 142 | Licensed under [GNU AGPL 2.0.](https://github.com/LazyDeveloperr/LazyPrincess/blob/master/LICENSE) 143 | Selling The Codes To Other People For Money Is *Strictly Prohibited*. 144 | -------------------------------------------------------------------------------- /Script.py: -------------------------------------------------------------------------------- 1 | import re 2 | from os import environ 3 | 4 | id_pattern = re.compile(r'^.\d+$') 5 | def is_enabled(value, default): 6 | if value.lower() in ["true", "yes", "1", "enable", "y"]: 7 | return True 8 | elif value.lower() in ["false", "no", "0", "disable", "n"]: 9 | return False 10 | else: 11 | return default 12 | 13 | class script(object): 14 | HOME_BUTTONURL_UPDATES = environ.get("HOME_BUTTONURL_UPDATES", 'https://clicksfly.com/ref/LazyDeveloperr') 15 | START_TXT = environ.get("START_TXT", '''Hello {}, 16 | Myself {},\n\nTrust me ! I can't even imagine how super-fast i can drive your Database channel \n\nAre you ready for Long Drive Baby...🤪''') 17 | HELP_TXT = """𝙷𝙴𝚈 {} 18 | 𝙷𝙴𝚁𝙴 𝙸𝚂 𝙼𝚈 𝙷𝙴𝙻𝙿 𝙲𝙾𝙼𝙼𝙰𝙽𝙳𝚂.""" 19 | ABOUT_TXT = """✯ 𝙼𝚈 𝙽𝙰𝙼𝙴: {} 20 | ✯ 𝙲𝚁𝙴𝙰𝚃𝙾𝚁: LazyDeveloper 21 | ✯ 𝙻𝙸𝙱𝚁𝙰𝚁𝚈: 𝙿𝚈𝚁𝙾𝙶𝚁𝙰𝙼 22 | ✯ 𝙻𝙰𝙽𝙶𝚄𝙰𝙶𝙴: 𝙿𝚈𝚃𝙷𝙾𝙽 𝟹 23 | ✯ 𝙳𝙰𝚃𝙰 𝙱𝙰𝚂𝙴: 𝙼𝙾𝙽𝙶𝙾 𝙳𝙱 24 | ✯ 𝙱𝙾𝚃 𝚂𝙴𝚁𝚅𝙴𝚁: KOYEB 25 | ✯ 𝙱𝚄𝙸𝙻𝙳 𝚂𝚃𝙰𝚃𝚄𝚂: v2.0.1 [ LazyPrincess ]""" 26 | SOURCE_TXT = """LazyPrincess is an open source project 27 | 28 | You can easily get its source code from github - LazyDeveloperr""" 29 | MANUELFILTER_TXT = """Help: Filters 30 | 31 | - Filter is the feature were users can set automated replies for a particular keyword and Search Bot will respond whenever a keyword is found the message 32 | 33 | NOTE: 34 | 1. Search Bot should have admin privillage. 35 | 2. only admins can add filters in a chat. 36 | 3. alert buttons have a limit of 64 characters. 37 | 38 | Commands and Usage: 39 | • /filter - add a filter in chat 40 | • /filters - list all the filters of a chat 41 | • /del - delete a specific filter in chat 42 | • /delall - delete the whole filters in a chat (chat owner only)""" 43 | BUTTON_TXT = """Help: Buttons 44 | 45 | - Search Bot Supports both url and alert inline buttons. 46 | 47 | NOTE: 48 | 1. Telegram will not allows you to send buttons without any content, so content is mandatory. 49 | 2. Search Bot supports buttons with any telegram media type. 50 | 3. Buttons should be properly parsed as markdown format 51 | 52 | URL buttons: 53 | [Button Text](buttonurl:https://t.me/LazyDeveloper) 54 | 55 | Alert buttons: 56 | [Button Text](buttonalert:This is an alert message)""" 57 | AUTOFILTER_TXT = """Help: Auto Filter 58 | 59 | NOTE: 60 | 1. Make me the admin of your channel if it's private. 61 | 2. make sure that your channel does not contains camrips, porn and fake files. 62 | 3. Forward the last message to me with quotes. 63 | I'll add all the files in that channel to my db.""" 64 | CONNECTION_TXT = """Help: Connections 65 | 66 | - Used to connect bot to PM for managing filters 67 | - it helps to avoid spamming in groups. 68 | 69 | NOTE: 70 | 1. Only admins can add a connection. 71 | 2. Send /connect for connecting me to ur PM 72 | 73 | Commands and Usage: 74 | • /connect - connect a particular chat to your PM 75 | • /disconnect - disconnect from a chat 76 | • /connections - list all your connections""" 77 | EXTRAMOD_TXT = """Help: Extra Modules 78 | 79 | NOTE: 80 | these are the extra features of Search Bot 81 | 82 | Commands and Usage: 83 | • /id - get id of a specified user. 84 | • /info - get information about a user. 85 | • /imdb - get the film information from IMDb source. 86 | • /search - get the film information from various sources.""" 87 | ADMIN_TXT = """Help: Admin mods 88 | 89 | NOTE: 90 | This module only works for my admins 91 | 92 | Commands and Usage: 93 | • /logs - to get the rescent errors 94 | • /stats - to get status of files in db. 95 | • /delete - to delete a specific file from db. 96 | • /users - to get list of my users and ids. 97 | • /chats - to get list of the my chats and ids 98 | • /leave - to leave from a chat. 99 | • /disable - do disable a chat. 100 | • /ban - to ban a user. 101 | • /unban - to unban a user. 102 | • /channel - to get list of total connected channels 103 | • /broadcast - to broadcast a message to all users""" 104 | STATUS_TXT = """★ 𝚃𝙾𝚃𝙰𝙻 𝙵𝙸𝙻𝙴𝚂: {} 105 | ★ 𝚃𝙾𝚃𝙰𝙻 𝚄𝚂𝙴𝚁𝚂: {} 106 | ★ 𝚃𝙾𝚃𝙰𝙻 𝙲𝙷𝙰𝚃𝚂: {} 107 | ★ 𝚄𝚂𝙴𝙳 𝚂𝚃𝙾𝚁𝙰𝙶𝙴: {} 𝙼𝚒𝙱 108 | ★ 𝙵𝚁𝙴𝙴 𝚂𝚃𝙾𝚁𝙰𝙶𝙴: {} 𝙼𝚒𝙱""" 109 | LOG_TEXT_G = """#NewGroup 110 | Group = {}({}) 111 | Total Members = {} 112 | Added By - {} 113 | """ 114 | LOG_TEXT_P = """#NewUser 115 | ID - {} 116 | Name - {} 117 | """ 118 | -------------------------------------------------------------------------------- /app.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "LazyPrincessV2", 3 | "description": "LazyPrincess with Url Shortner", 4 | "stack": "container", 5 | "logo": "https://telegra.ph/file/68d28011b2bc356b5db01.png", 6 | "keywords": [ 7 | "telegram", 8 | "auto-filter", 9 | "filter", 10 | "best", 11 | "indian", 12 | "pyrogram", 13 | "media", 14 | "search", 15 | "channel", 16 | "index", 17 | "inline" 18 | ], 19 | "website": "https://github.com/LazyDeveloperr", 20 | "repository": "https://github.com/LazyDeveloperr/LazyPrincessV2", 21 | "env": { 22 | "BOT_TOKEN": { 23 | "description": "Your bot token.", 24 | "required": true 25 | }, 26 | "API_ID": { 27 | "description": "Get this value from https://my.telegram.org", 28 | "required": true 29 | }, 30 | "API_HASH": { 31 | "description": "Get this value from https://my.telegram.org", 32 | "required": true 33 | }, 34 | "CHANNELS": { 35 | "description": "Username or ID of channel or group. Separate multiple IDs by space.", 36 | "required": false 37 | }, 38 | "ADMINS": { 39 | "description": "Username or ID of Admin. Separate multiple Admins by space.", 40 | "required": true 41 | }, 42 | "PICS": { 43 | "description": "Add some telegraph link of pictures .", 44 | "required": false 45 | }, 46 | "LOG_CHANNEL": { 47 | "description": "Bot Logs,Give a channel id with -100xxxxxxx", 48 | "required": true 49 | }, 50 | "AUTH_USERS": { 51 | "description": "Username or ID of users to give access of inline search. Separate multiple users by space.\nLeave it empty if you don't want to restrict bot usage.", 52 | "required": false 53 | }, 54 | "AUTH_CHANNEL": { 55 | "description": "ID of channel.Make sure bot is admin in this channel. Without subscribing this channel users cannot use bot.", 56 | "required": false 57 | }, 58 | "DATABASE_URI": { 59 | "description": "mongoDB URI. Get this value from https://www.mongodb.com", 60 | "required": true 61 | }, 62 | "DATABASE_NAME": { 63 | "description": "Name of the database in mongoDB.", 64 | "required": false 65 | }, 66 | "COLLECTION_NAME": { 67 | "description": "Name of the collections. Defaults to Telegram_files. If you are using the same database, then use different collection name for each bot", 68 | "value": "Anurag_files", 69 | "required": false 70 | } 71 | }, 72 | "addons": [], 73 | "buildpacks": [{ 74 | "url": "heroku/python" 75 | }], 76 | "formation": { 77 | "worker": { 78 | "quantity": 1, 79 | "size": "free" 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /bot.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import logging.config 3 | from aiohttp import web 4 | from plugins import web_server 5 | 6 | # Get logging configurations 7 | logging.config.fileConfig('logging.conf') 8 | logging.getLogger().setLevel(logging.INFO) 9 | logging.getLogger("pyrogram").setLevel(logging.ERROR) 10 | logging.getLogger("imdbpy").setLevel(logging.ERROR) 11 | 12 | from pyrogram import Client, __version__ 13 | from pyrogram.raw.all import layer 14 | from database.ia_filterdb import Media 15 | from database.users_chats_db import db 16 | from info import * 17 | from utils import temp 18 | from typing import Union, Optional, AsyncGenerator 19 | from pyrogram import types 20 | 21 | class Bot(Client): 22 | 23 | def __init__(self): 24 | super().__init__( 25 | name=SESSION, 26 | api_id=API_ID, 27 | api_hash=API_HASH, 28 | bot_token=BOT_TOKEN, 29 | workers=50, 30 | plugins={"root": "plugins"}, 31 | sleep_threshold=5, 32 | ) 33 | 34 | async def start(self): 35 | b_users, b_chats = await db.get_banned() 36 | temp.BANNED_USERS = b_users 37 | temp.BANNED_CHATS = b_chats 38 | await super().start() 39 | await Media.ensure_indexes() 40 | me = await self.get_me() 41 | temp.ME = me.id 42 | temp.U_NAME = me.username 43 | temp.B_NAME = me.first_name 44 | self.username = '@' + me.username 45 | #web-response 46 | app = web.AppRunner(await web_server()) 47 | await app.setup() 48 | bind_address = "0.0.0.0" 49 | await web.TCPSite(app, bind_address, PORT).start() 50 | logging.info(f"{me.first_name} with for Pyrogram v{__version__} (Layer {layer}) started on {me.username}.") 51 | logging.info(LOG_STR) 52 | 53 | async def stop(self, *args): 54 | await super().stop() 55 | logging.info("Bot stopped. Bye.") 56 | 57 | async def iter_messages( 58 | self, 59 | chat_id: Union[int, str], 60 | limit: int, 61 | offset: int = 0, 62 | ) -> Optional[AsyncGenerator["types.Message", None]]: 63 | """Iterate through a chat sequentially. 64 | This convenience method does the same as repeatedly calling :meth:`~pyrogram.Client.get_messages` in a loop, thus saving 65 | you from the hassle of setting up boilerplate code. It is useful for getting the whole chat messages with a 66 | single call. 67 | Parameters: 68 | chat_id (``int`` | ``str``): 69 | Unique identifier (int) or username (str) of the target chat. 70 | For your personal cloud (Saved Messages) you can simply use "me" or "self". 71 | For a contact that exists in your Telegram address book you can use his phone number (str). 72 | 73 | limit (``int``): 74 | Identifier of the last message to be returned. 75 | 76 | offset (``int``, *optional*): 77 | Identifier of the first message to be returned. 78 | Defaults to 0. 79 | Returns: 80 | ``Generator``: A generator yielding :obj:`~pyrogram.types.Message` objects. 81 | Example: 82 | .. code-block:: python 83 | for message in app.iter_messages("pyrogram", 1, 15000): 84 | print(message.text) 85 | """ 86 | current = offset 87 | while True: 88 | new_diff = min(200, limit - current) 89 | if new_diff <= 0: 90 | return 91 | messages = await self.get_messages(chat_id, list(range(current, current+new_diff+1))) 92 | for message in messages: 93 | yield message 94 | current += 1 95 | 96 | 97 | app = Bot() 98 | app.run() 99 | -------------------------------------------------------------------------------- /database/connections_mdb.py: -------------------------------------------------------------------------------- 1 | import pymongo 2 | 3 | from info import DATABASE_URI, DATABASE_NAME 4 | 5 | import logging 6 | logger = logging.getLogger(__name__) 7 | logger.setLevel(logging.ERROR) 8 | 9 | myclient = pymongo.MongoClient(DATABASE_URI) 10 | mydb = myclient[DATABASE_NAME] 11 | mycol = mydb['CONNECTION'] 12 | 13 | 14 | async def add_connection(group_id, user_id): 15 | query = mycol.find_one( 16 | { "_id": user_id }, 17 | { "_id": 0, "active_group": 0 } 18 | ) 19 | if query is not None: 20 | group_ids = [x["group_id"] for x in query["group_details"]] 21 | if group_id in group_ids: 22 | return False 23 | 24 | group_details = { 25 | "group_id" : group_id 26 | } 27 | 28 | data = { 29 | '_id': user_id, 30 | 'group_details' : [group_details], 31 | 'active_group' : group_id, 32 | } 33 | 34 | if mycol.count_documents( {"_id": user_id} ) == 0: 35 | try: 36 | mycol.insert_one(data) 37 | return True 38 | except: 39 | logger.exception('Some error occurred!', exc_info=True) 40 | 41 | else: 42 | try: 43 | mycol.update_one( 44 | {'_id': user_id}, 45 | { 46 | "$push": {"group_details": group_details}, 47 | "$set": {"active_group" : group_id} 48 | } 49 | ) 50 | return True 51 | except: 52 | logger.exception('Some error occurred!', exc_info=True) 53 | 54 | 55 | async def active_connection(user_id): 56 | 57 | query = mycol.find_one( 58 | { "_id": user_id }, 59 | { "_id": 0, "group_details": 0 } 60 | ) 61 | if not query: 62 | return None 63 | 64 | group_id = query['active_group'] 65 | return int(group_id) if group_id != None else None 66 | 67 | 68 | async def all_connections(user_id): 69 | query = mycol.find_one( 70 | { "_id": user_id }, 71 | { "_id": 0, "active_group": 0 } 72 | ) 73 | if query is not None: 74 | return [x["group_id"] for x in query["group_details"]] 75 | else: 76 | return None 77 | 78 | 79 | async def if_active(user_id, group_id): 80 | query = mycol.find_one( 81 | { "_id": user_id }, 82 | { "_id": 0, "group_details": 0 } 83 | ) 84 | return query is not None and query['active_group'] == group_id 85 | 86 | 87 | async def make_active(user_id, group_id): 88 | update = mycol.update_one( 89 | {'_id': user_id}, 90 | {"$set": {"active_group" : group_id}} 91 | ) 92 | return update.modified_count != 0 93 | 94 | 95 | async def make_inactive(user_id): 96 | update = mycol.update_one( 97 | {'_id': user_id}, 98 | {"$set": {"active_group" : None}} 99 | ) 100 | return update.modified_count != 0 101 | 102 | 103 | async def delete_connection(user_id, group_id): 104 | 105 | try: 106 | update = mycol.update_one( 107 | {"_id": user_id}, 108 | {"$pull" : { "group_details" : {"group_id":group_id} } } 109 | ) 110 | if update.modified_count == 0: 111 | return False 112 | query = mycol.find_one( 113 | { "_id": user_id }, 114 | { "_id": 0 } 115 | ) 116 | if len(query["group_details"]) >= 1: 117 | if query['active_group'] == group_id: 118 | prvs_group_id = query["group_details"][len(query["group_details"]) - 1]["group_id"] 119 | 120 | mycol.update_one( 121 | {'_id': user_id}, 122 | {"$set": {"active_group" : prvs_group_id}} 123 | ) 124 | else: 125 | mycol.update_one( 126 | {'_id': user_id}, 127 | {"$set": {"active_group" : None}} 128 | ) 129 | return True 130 | except Exception as e: 131 | logger.exception(f'Some error occurred! {e}', exc_info=True) 132 | return False 133 | 134 | -------------------------------------------------------------------------------- /database/filters_mdb.py: -------------------------------------------------------------------------------- 1 | import pymongo 2 | from pyrogram import enums 3 | from info import DATABASE_URI, DATABASE_NAME 4 | import logging 5 | logger = logging.getLogger(__name__) 6 | logger.setLevel(logging.ERROR) 7 | 8 | myclient = pymongo.MongoClient(DATABASE_URI) 9 | mydb = myclient[DATABASE_NAME] 10 | 11 | 12 | 13 | async def add_filter(grp_id, text, reply_text, btn, file, alert): 14 | mycol = mydb[str(grp_id)] 15 | # mycol.create_index([('text', 'text')]) 16 | 17 | data = { 18 | 'text':str(text), 19 | 'reply':str(reply_text), 20 | 'btn':str(btn), 21 | 'file':str(file), 22 | 'alert':str(alert) 23 | } 24 | 25 | try: 26 | mycol.update_one({'text': str(text)}, {"$set": data}, upsert=True) 27 | except: 28 | logger.exception('Some error occured!', exc_info=True) 29 | 30 | 31 | async def find_filter(group_id, name): 32 | mycol = mydb[str(group_id)] 33 | 34 | query = mycol.find( {"text":name}) 35 | # query = mycol.find( { "$text": {"$search": name}}) 36 | try: 37 | for file in query: 38 | reply_text = file['reply'] 39 | btn = file['btn'] 40 | fileid = file['file'] 41 | try: 42 | alert = file['alert'] 43 | except: 44 | alert = None 45 | return reply_text, btn, alert, fileid 46 | except: 47 | return None, None, None, None 48 | 49 | 50 | async def get_filters(group_id): 51 | mycol = mydb[str(group_id)] 52 | 53 | texts = [] 54 | query = mycol.find() 55 | try: 56 | for file in query: 57 | text = file['text'] 58 | texts.append(text) 59 | except: 60 | pass 61 | return texts 62 | 63 | 64 | async def delete_filter(message, text, group_id): 65 | mycol = mydb[str(group_id)] 66 | 67 | myquery = {'text':text } 68 | query = mycol.count_documents(myquery) 69 | if query == 1: 70 | mycol.delete_one(myquery) 71 | await message.reply_text( 72 | f"'`{text}`' deleted. I'll not respond to that filter anymore.", 73 | quote=True, 74 | parse_mode=enums.ParseMode.MARKDOWN 75 | ) 76 | else: 77 | await message.reply_text("Couldn't find that filter!", quote=True) 78 | 79 | 80 | async def del_all(message, group_id, title): 81 | if str(group_id) not in mydb.list_collection_names(): 82 | await message.edit_text(f"Nothing to remove in {title}!") 83 | return 84 | 85 | mycol = mydb[str(group_id)] 86 | try: 87 | mycol.drop() 88 | await message.edit_text(f"All filters from {title} has been removed") 89 | except: 90 | await message.edit_text("Couldn't remove all filters from group!") 91 | return 92 | 93 | 94 | async def count_filters(group_id): 95 | mycol = mydb[str(group_id)] 96 | 97 | count = mycol.count() 98 | return False if count == 0 else count 99 | 100 | 101 | async def filter_stats(): 102 | collections = mydb.list_collection_names() 103 | 104 | if "CONNECTION" in collections: 105 | collections.remove("CONNECTION") 106 | 107 | totalcount = 0 108 | for collection in collections: 109 | mycol = mydb[collection] 110 | count = mycol.count() 111 | totalcount += count 112 | 113 | totalcollections = len(collections) 114 | 115 | return totalcollections, totalcount 116 | -------------------------------------------------------------------------------- /database/ia_filterdb.py: -------------------------------------------------------------------------------- 1 | import logging 2 | from struct import pack 3 | import re 4 | import base64 5 | from pyrogram.file_id import FileId 6 | from pymongo.errors import DuplicateKeyError 7 | from umongo import Instance, Document, fields 8 | from motor.motor_asyncio import AsyncIOMotorClient 9 | from marshmallow.exceptions import ValidationError 10 | from info import DATABASE_URI, DATABASE_NAME, COLLECTION_NAME, USE_CAPTION_FILTER 11 | 12 | logger = logging.getLogger(__name__) 13 | logger.setLevel(logging.INFO) 14 | 15 | 16 | client = AsyncIOMotorClient(DATABASE_URI) 17 | db = client[DATABASE_NAME] 18 | instance = Instance.from_db(db) 19 | 20 | @instance.register 21 | class Media(Document): 22 | file_id = fields.StrField(attribute='_id') 23 | file_ref = fields.StrField(allow_none=True) 24 | file_name = fields.StrField(required=True) 25 | file_size = fields.IntField(required=True) 26 | file_type = fields.StrField(allow_none=True) 27 | mime_type = fields.StrField(allow_none=True) 28 | caption = fields.StrField(allow_none=True) 29 | 30 | class Meta: 31 | indexes = ('$file_name', ) 32 | collection_name = COLLECTION_NAME 33 | 34 | 35 | async def save_file(media): 36 | """Save file in database""" 37 | 38 | # TODO: Find better way to get same file_id for same media to avoid duplicates 39 | file_id, file_ref = unpack_new_file_id(media.file_id) 40 | file_name = re.sub(r"(_|\-|\.|\+)", " ", str(media.file_name)) 41 | try: 42 | file = Media( 43 | file_id=file_id, 44 | file_ref=file_ref, 45 | file_name=file_name, 46 | file_size=media.file_size, 47 | file_type=media.file_type, 48 | mime_type=media.mime_type, 49 | caption=media.caption.html if media.caption else None, 50 | ) 51 | except ValidationError: 52 | logger.exception('Error occurred while saving file in database') 53 | return False, 2 54 | else: 55 | try: 56 | await file.commit() 57 | except DuplicateKeyError: 58 | logger.warning( 59 | f'{getattr(media, "file_name", "NO_FILE")} is already saved in database' 60 | ) 61 | 62 | return False, 0 63 | else: 64 | logger.info(f'{getattr(media, "file_name", "NO_FILE")} is saved to database') 65 | return True, 1 66 | 67 | 68 | 69 | async def get_search_results(query, file_type=None, max_results=10, offset=0, filter=False): 70 | """For given query return (results, next_offset)""" 71 | 72 | query = query.strip() 73 | #if filter: 74 | #better ? 75 | #query = query.replace(' ', r'(\s|\.|\+|\-|_)') 76 | #raw_pattern = r'(\s|_|\-|\.|\+)' + query + r'(\s|_|\-|\.|\+)' 77 | if not query: 78 | raw_pattern = '.' 79 | elif ' ' not in query: 80 | raw_pattern = r'(\b|[\.\+\-_])' + query + r'(\b|[\.\+\-_])' 81 | else: 82 | raw_pattern = query.replace(' ', r'.*[\s\.\+\-_]') 83 | 84 | try: 85 | regex = re.compile(raw_pattern, flags=re.IGNORECASE) 86 | except: 87 | return [] 88 | 89 | if USE_CAPTION_FILTER: 90 | filter = {'$or': [{'file_name': regex}, {'caption': regex}]} 91 | else: 92 | filter = {'file_name': regex} 93 | 94 | if file_type: 95 | filter['file_type'] = file_type 96 | 97 | total_results = await Media.count_documents(filter) 98 | next_offset = offset + max_results 99 | 100 | if next_offset > total_results: 101 | next_offset = '' 102 | 103 | cursor = Media.find(filter) 104 | # Sort by recent 105 | cursor.sort('$natural', -1) 106 | # Slice files according to offset and max results 107 | cursor.skip(offset).limit(max_results) 108 | # Get list of files 109 | files = await cursor.to_list(length=max_results) 110 | 111 | return files, next_offset, total_results 112 | 113 | 114 | 115 | async def get_file_details(query): 116 | filter = {'file_id': query} 117 | cursor = Media.find(filter) 118 | filedetails = await cursor.to_list(length=1) 119 | return filedetails 120 | 121 | 122 | def encode_file_id(s: bytes) -> str: 123 | r = b"" 124 | n = 0 125 | 126 | for i in s + bytes([22]) + bytes([4]): 127 | if i == 0: 128 | n += 1 129 | else: 130 | if n: 131 | r += b"\x00" + bytes([n]) 132 | n = 0 133 | 134 | r += bytes([i]) 135 | 136 | return base64.urlsafe_b64encode(r).decode().rstrip("=") 137 | 138 | 139 | def encode_file_ref(file_ref: bytes) -> str: 140 | return base64.urlsafe_b64encode(file_ref).decode().rstrip("=") 141 | 142 | 143 | def unpack_new_file_id(new_file_id): 144 | """Return file_id, file_ref""" 145 | decoded = FileId.decode(new_file_id) 146 | file_id = encode_file_id( 147 | pack( 148 | "File uploaded by [Movies Adaa™](https://t.me/real_MoviesAdda1)⚡\n\nName: {file_caption} \n\n⚙️ Size: {file_size}🔥 ↭ Join Now [MoviesAdda™](https://t.me/real_MoviesAdda1) ↭ 🔥") 49 | BATCH_FILE_CAPTION = environ.get("BATCH_FILE_CAPTION", "⚡File uploaded by [Movies Adaa™](https://t.me/real_MoviesAdda1)⚡\n\nName: {file_caption} \n\n⚙️ Size: {file_size}🔥 ↭ Join Now [MoviesAdda™](https://t.me/real_MoviesAdda1) ↭ 🔥") 50 | IMDB_TEMPLATE = environ.get("IMDB_TEMPLATE", "Your Query: {query} \n‌‌‌‌IMDb: \n\n🏷 Title: {title}\n🌟 Rating : {rating}/10\n🎭 Genres: {genres}\n📆 Year: {year}\n⏰ Duration : {runtime}\n🎙️ Languages : {languages}\n🔖 Plot : {plot}\n\n♥️ we are nothing without you ♥️ \n\n💛 Please Share Us 💛\n\n⚠️Click on the button 👇 below to get your query privately") 51 | LONG_IMDB_DESCRIPTION = is_enabled(environ.get("LONG_IMDB_DESCRIPTION", "False"), False) 52 | SPELL_CHECK_REPLY = is_enabled(environ.get("SPELL_CHECK_REPLY", "True"), False) 53 | MAX_LIST_ELM = environ.get("MAX_LIST_ELM", None) 54 | INDEX_REQ_CHANNEL = int(environ.get('INDEX_REQ_CHANNEL', LOG_CHANNEL)) 55 | FILE_STORE_CHANNEL = [int(ch) for ch in (environ.get('FILE_STORE_CHANNEL', '')).split()] 56 | MELCOW_NEW_USERS = is_enabled((environ.get('MELCOW_NEW_USERS', "True")), True) 57 | PROTECT_CONTENT = is_enabled((environ.get('PROTECT_CONTENT', "False")), False) 58 | PUBLIC_FILE_STORE = is_enabled((environ.get('PUBLIC_FILE_STORE', "False")), True) 59 | 60 | LOG_STR = "Current Cusomized Configurations are:-\n" 61 | LOG_STR += ("IMDB Results are enabled, Bot will be showing imdb details for you queries.\n" if IMDB else "IMBD Results are disabled.\n") 62 | LOG_STR += ("P_TTI_SHOW_OFF found , Users will be redirected to send /start to Bot PM instead of sending file file directly\n" if P_TTI_SHOW_OFF else "P_TTI_SHOW_OFF is disabled files will be send in PM, instead of sending start.\n") 63 | LOG_STR += ("SINGLE_BUTTON is Found, filename and files size will be shown in a single button instead of two separate buttons\n" if SINGLE_BUTTON else "SINGLE_BUTTON is disabled , filename and file_sixe will be shown as different buttons\n") 64 | LOG_STR += (f"CUSTOM_FILE_CAPTION enabled with value {CUSTOM_FILE_CAPTION}, your files will be send along with this customized caption.\n" if CUSTOM_FILE_CAPTION else "No CUSTOM_FILE_CAPTION Found, Default captions of file will be used.\n") 65 | LOG_STR += ("Long IMDB storyline enabled." if LONG_IMDB_DESCRIPTION else "LONG_IMDB_DESCRIPTION is disabled , Plot will be shorter.\n") 66 | LOG_STR += ("Spell Check Mode Is Enabled, bot will be suggesting related movies if movie not found\n" if SPELL_CHECK_REPLY else "SPELL_CHECK_REPLY Mode disabled\n") 67 | LOG_STR += (f"MAX_LIST_ELM Found, long list will be shortened to first {MAX_LIST_ELM} elements\n" if MAX_LIST_ELM else "Full List of casts and crew will be shown in imdb template, restrict them by adding a value to MAX_LIST_ELM\n") 68 | LOG_STR += f"Your current IMDB template is {IMDB_TEMPLATE}" 69 | 70 | ## EXTRA FEATURES ## 71 | 72 | # URL Shortener # 73 | 74 | URL_SHORTENR_WEBSITE = environ.get('URL_SHORTENR_WEBSITE', 'api.shareus.in/shortLink') 75 | URL_SHORTNER_WEBSITE_API = environ.get('URL_SHORTNER_WEBSITE_API', 'I3Khu0fwfbWpd1W2ofcyP2znDA12') 76 | 77 | # Auto Delete For Group Message (Self Delete) # 78 | SELF_DELETE_SECONDS = int(environ.get('SELF_DELETE_SECONDS', 100)) 79 | SELF_DELETE = environ.get('SELF_DELETE', True) 80 | if SELF_DELETE == "True": 81 | SELF_DELETE = True 82 | 83 | # Download Tutorial Button # 84 | DOWNLOAD_TEXT_NAME = "📥 HOW TO DOWNLOAD 📥" 85 | DOWNLOAD_TEXT_URL = "https://t.me/LazyDeveloper" 86 | 87 | # Custom Caption Under Button # 88 | CAPTION_BUTTON = "Get Updates" 89 | CAPTION_BUTTON_URL = "https://t.me/LazyDeveloper" 90 | 91 | # Auto Delete For Bot Sending Files # 92 | -------------------------------------------------------------------------------- /logging.conf: -------------------------------------------------------------------------------- 1 | [loggers] 2 | keys=root 3 | 4 | [handlers] 5 | keys=consoleHandler,fileHandler 6 | 7 | [formatters] 8 | keys=consoleFormatter,fileFormatter 9 | 10 | [logger_root] 11 | level=DEBUG 12 | handlers=consoleHandler,fileHandler 13 | 14 | [handler_consoleHandler] 15 | class=StreamHandler 16 | level=INFO 17 | formatter=consoleFormatter 18 | args=(sys.stdout,) 19 | 20 | [handler_fileHandler] 21 | class=FileHandler 22 | level=ERROR 23 | formatter=fileFormatter 24 | args=('TelegramBot.log','w',) 25 | 26 | [formatter_consoleFormatter] 27 | format=%(asctime)s - %(lineno)d - %(name)s - %(module)s - %(levelname)s - %(message)s 28 | datefmt=%I:%M:%S %p 29 | 30 | [formatter_fileFormatter] 31 | format=[%(asctime)s:%(name)s:%(lineno)d:%(levelname)s] %(message)s 32 | datefmt=%m/%d/%Y %I:%M:%S %p -------------------------------------------------------------------------------- /plugins/__init__.py: -------------------------------------------------------------------------------- 1 | #@iryme 2 | 3 | 4 | 5 | 6 | 7 | 8 | from aiohttp import web 9 | from .route import routes 10 | 11 | 12 | async def web_server(): 13 | web_app = web.Application(client_max_size=30000000) 14 | web_app.add_routes(routes) 15 | return web_app 16 | -------------------------------------------------------------------------------- /plugins/banned.py: -------------------------------------------------------------------------------- 1 | from pyrogram import Client, filters 2 | from utils import temp 3 | from pyrogram.types import Message 4 | from database.users_chats_db import db 5 | from pyrogram.types import InlineKeyboardButton, InlineKeyboardMarkup 6 | from info import SUPPORT_CHAT 7 | 8 | async def banned_users(_, client, message: Message): 9 | return ( 10 | message.from_user is not None or not message.sender_chat 11 | ) and message.from_user.id in temp.BANNED_USERS 12 | 13 | banned_user = filters.create(banned_users) 14 | 15 | async def disabled_chat(_, client, message: Message): 16 | return message.chat.id in temp.BANNED_CHATS 17 | 18 | disabled_group=filters.create(disabled_chat) 19 | 20 | 21 | @Client.on_message(filters.private & banned_user & filters.incoming) 22 | async def ban_reply(bot, message): 23 | ban = await db.get_ban_status(message.from_user.id) 24 | await message.reply(f'Sorry Dude, You are Banned to use Me. \nBan Reason: {ban["ban_reason"]}') 25 | 26 | @Client.on_message(filters.group & disabled_group & filters.incoming) 27 | async def grp_bd(bot, message): 28 | buttons = [[ 29 | InlineKeyboardButton('Support', url=f'https://t.me/{SUPPORT_CHAT}') 30 | ]] 31 | reply_markup=InlineKeyboardMarkup(buttons) 32 | vazha = await db.get_chat(message.chat.id) 33 | k = await message.reply( 34 | text=f"CHAT NOT ALLOWED 🐞\n\nMy admins has restricted me from working here ! If you want to know more about it contact support..\nReason : {vazha['reason']}.", 35 | reply_markup=reply_markup) 36 | try: 37 | await k.pin() 38 | except: 39 | pass 40 | await bot.leave_chat(message.chat.id) 41 | -------------------------------------------------------------------------------- /plugins/broadcast.py: -------------------------------------------------------------------------------- 1 | #https://github.com/AM-ROBOTS 2 | from pyrogram import Client, filters 3 | import datetime 4 | import time 5 | from database.users_chats_db import db 6 | from info import ADMINS 7 | from utils import broadcast_messages 8 | import asyncio 9 | 10 | @Client.on_message(filters.command("broadcast") & filters.user(ADMINS) & filters.reply) 11 | # https://t.me/GetTGLink/4178 12 | async def verupikkals(bot, message): 13 | users = await db.get_all_users() 14 | b_msg = message.reply_to_message 15 | sts = await message.reply_text( 16 | text='Broadcasting your messages...😁...' 17 | ) 18 | start_time = time.time() 19 | total_users = await db.total_users_count() 20 | done = 0 21 | blocked = 0 22 | deleted = 0 23 | failed =0 24 | 25 | success = 0 26 | async for user in users: 27 | pti, sh = await broadcast_messages(int(user['id']), b_msg) 28 | if pti: 29 | success += 1 30 | elif pti == False: 31 | if sh == "Blocked": 32 | blocked+=1 33 | elif sh == "Deleted": 34 | deleted += 1 35 | elif sh == "Error": 36 | failed += 1 37 | done += 1 38 | await asyncio.sleep(2) 39 | if not done % 20: 40 | await sts.edit(f"Broadcast in progress:\n\nTotal Users {total_users}\nCompleted: {done} / {total_users}\nSuccess: {success}\nBlocked: {blocked}\nDeleted: {deleted}") 41 | time_taken = datetime.timedelta(seconds=int(time.time()-start_time)) 42 | await sts.edit(f"Broadcast Completed:\nCompleted in {time_taken} seconds.\n\nTotal Users {total_users}\nCompleted: {done} / {total_users}\nSuccess: {success}\nBlocked: {blocked}\nDeleted: {deleted}") 43 | -------------------------------------------------------------------------------- /plugins/channel.py: -------------------------------------------------------------------------------- 1 | from pyrogram import Client, filters 2 | from info import CHANNELS 3 | from database.ia_filterdb import save_file 4 | 5 | media_filter = filters.document | filters.video | filters.audio 6 | 7 | 8 | @Client.on_message(filters.chat(CHANNELS) & media_filter) 9 | async def media(bot, message): 10 | """Media Handler""" 11 | for file_type in ("document", "video", "audio"): 12 | media = getattr(message, file_type, None) 13 | if media is not None: 14 | break 15 | else: 16 | return 17 | 18 | media.file_type = file_type 19 | media.caption = message.caption 20 | await save_file(media) -------------------------------------------------------------------------------- /plugins/commands.py: -------------------------------------------------------------------------------- 1 | import os 2 | import logging 3 | import random 4 | import asyncio 5 | from Script import script 6 | from pyrogram import Client, filters, enums 7 | from pyrogram.errors import ChatAdminRequired, FloodWait 8 | from pyrogram.types import InlineKeyboardButton, InlineKeyboardMarkup 9 | from database.ia_filterdb import Media, get_file_details, unpack_new_file_id 10 | from database.users_chats_db import db 11 | from info import * 12 | from utils import get_settings, get_size, is_subscribed, save_group_settings, temp 13 | from database.connections_mdb import active_connection 14 | import re 15 | import json 16 | import base64 17 | logger = logging.getLogger(__name__) 18 | 19 | BATCH_FILES = {} 20 | 21 | @Client.on_message(filters.command("start") & filters.incoming) 22 | async def start(client, message): 23 | if message.chat.type in [enums.ChatType.GROUP, enums.ChatType.SUPERGROUP]: 24 | buttons = [ 25 | [ 26 | InlineKeyboardButton('🔔 BOT Updates 🤖', url='https://telegram.me/LazyDeveloper') 27 | ], 28 | [ 29 | InlineKeyboardButton('⚡ Movie Updates ⚡', url=f"https://telegram.me/real_MoviesAdda1"), 30 | ], 31 | [ 32 | InlineKeyboardButton(text=DOWNLOAD_TEXT_NAME,url=DOWNLOAD_TEXT_URL) 33 | ] 34 | ] 35 | reply_markup = InlineKeyboardMarkup(buttons) 36 | await message.reply(script.START_TXT.format(message.from_user.mention if message.from_user else message.chat.title, temp.U_NAME, temp.B_NAME), reply_markup=reply_markup) 37 | await asyncio.sleep(2) # 😢 https://github.com/EvamariaTG/EvaMaria/blob/master/plugins/p_ttishow.py#L17 😬 wait a bit, before checking. 38 | if not await db.get_chat(message.chat.id): 39 | total=await client.get_chat_members_count(message.chat.id) 40 | await client.send_message(LOG_CHANNEL, script.LOG_TEXT_G.format(message.chat.title, message.chat.id, total, "Unknown")) 41 | await db.add_chat(message.chat.id, message.chat.title) 42 | return 43 | if not await db.is_user_exist(message.from_user.id): 44 | await db.add_user(message.from_user.id, message.from_user.first_name) 45 | await client.send_message(LOG_CHANNEL, script.LOG_TEXT_P.format(message.from_user.id, message.from_user.mention)) 46 | if len(message.command) != 2: 47 | buttons = [[ 48 | InlineKeyboardButton('➕↖️ Add Me To Your Groups ↗️➕', url=f'http://t.me/{temp.U_NAME}?startgroup=true') 49 | ],[ 50 | InlineKeyboardButton('⚡ Movie Updates ⚡', url=f"https://telegram.me/real_MoviesAdda1"), 51 | InlineKeyboardButton('🔔 BOT Updates 🤖', url='https://t.me/LazyDeveloper') 52 | ],[ 53 | InlineKeyboardButton('🙆🏻 Help 🦾', callback_data='help'), 54 | InlineKeyboardButton('♥️ About ♥️', callback_data='about') 55 | ]] 56 | reply_markup = InlineKeyboardMarkup(buttons) 57 | await message.reply_photo( 58 | photo=random.choice(PICS), 59 | caption=script.START_TXT.format(message.from_user.mention, temp.U_NAME, temp.B_NAME), 60 | reply_markup=reply_markup, 61 | parse_mode=enums.ParseMode.HTML 62 | ) 63 | return 64 | if AUTH_CHANNEL and not await is_subscribed(client, message): 65 | try: 66 | invite_link = await client.create_chat_invite_link(int(AUTH_CHANNEL)) 67 | except ChatAdminRequired: 68 | logger.error("Make sure Bot is admin in Force Sub channel") 69 | return 70 | btn = [ 71 | [ 72 | InlineKeyboardButton( 73 | "🔥 Join Updates Channel 🔥", url=invite_link.invite_link 74 | ) 75 | ] 76 | ] 77 | 78 | if message.command[1] != "subscribe": 79 | try: 80 | kk, file_id = message.command[1].split("_", 1) 81 | pre = 'checksubp' if kk == 'filep' else 'checksub' 82 | btn.append([InlineKeyboardButton(" 🔄 Try Again", callback_data=f"{pre}#{file_id}")]) 83 | except (IndexError, ValueError): 84 | btn.append([InlineKeyboardButton(" 🔄 Try Again", url=f"https://t.me/{temp.U_NAME}?start={message.command[1]}")]) 85 | await client.send_message( 86 | chat_id=message.from_user.id, 87 | text="**Please Join My Updates Channel to use this Bot!**", 88 | reply_markup=InlineKeyboardMarkup(btn), 89 | parse_mode=enums.ParseMode.MARKDOWN 90 | ) 91 | return 92 | if len(message.command) == 2 and message.command[1] in ["subscribe", "error", "okay", "help"]: 93 | buttons = [[ 94 | InlineKeyboardButton('➕↖️ Add Me To Your Groups ↗️➕', url=f'http://t.me/{temp.U_NAME}?startgroup=true') 95 | ],[ 96 | InlineKeyboardButton('⚡ Movie Updates ⚡', url=f"https://telegram.me/real_MoviesAdda1"), 97 | InlineKeyboardButton('🔔 BOT Updates 🤖', url='https://t.me/LazyDeveloper') 98 | ],[ 99 | InlineKeyboardButton('🙆🏻 Help 🦾', callback_data='help'), 100 | InlineKeyboardButton('♥️ About ♥️', callback_data='about') 101 | ]] 102 | reply_markup = InlineKeyboardMarkup(buttons) 103 | await message.reply_photo( 104 | photo=random.choice(PICS), 105 | caption=script.START_TXT.format(message.from_user.mention, temp.U_NAME, temp.B_NAME), 106 | reply_markup=reply_markup, 107 | parse_mode=enums.ParseMode.HTML 108 | ) 109 | return 110 | data = message.command[1] 111 | try: 112 | pre, file_id = data.split('_', 1) 113 | except: 114 | file_id = data 115 | pre = "" 116 | if data.split("-", 1)[0] == "BATCH": 117 | sts = await message.reply("𝙰𝙲𝙲𝙴𝚂𝚂𝙸𝙽𝙶 𝙵𝙸𝙻𝙴𝚂.../") 118 | file_id = data.split("-", 1)[1] 119 | msgs = BATCH_FILES.get(file_id) 120 | if not msgs: 121 | file = await client.download_media(file_id) 122 | try: 123 | with open(file) as file_data: 124 | msgs=json.loads(file_data.read()) 125 | except: 126 | await sts.edit("FAILED") 127 | return await client.send_message(LOG_CHANNEL, "UNABLE TO OPEN FILE.") 128 | os.remove(file) 129 | BATCH_FILES[file_id] = msgs 130 | for msg in msgs: 131 | title = msg.get("title") 132 | size=get_size(int(msg.get("size", 0))) 133 | f_caption=msg.get("caption", "") 134 | if BATCH_FILE_CAPTION: 135 | try: 136 | f_caption=BATCH_FILE_CAPTION.format(file_name= '' if title is None else title, file_size='' if size is None else size, file_caption='' if f_caption is None else f_caption) 137 | except Exception as e: 138 | logger.exception(e) 139 | f_caption=f_caption 140 | if f_caption is None: 141 | f_caption = f"{title}" 142 | try: 143 | await client.send_cached_media( 144 | chat_id=message.from_user.id, 145 | file_id=msg.get("file_id"), 146 | caption=f_caption, 147 | protect_content=msg.get('protect', False), 148 | ) 149 | except FloodWait as e: 150 | await asyncio.sleep(e.x) 151 | logger.warning(f"Floodwait of {e.x} sec.") 152 | await client.send_cached_media( 153 | chat_id=message.from_user.id, 154 | file_id=msg.get("file_id"), 155 | caption=f_caption, 156 | protect_content=msg.get('protect', False), 157 | ) 158 | except Exception as e: 159 | logger.warning(e, exc_info=True) 160 | continue 161 | await asyncio.sleep(1) 162 | await sts.delete() 163 | return 164 | elif data.split("-", 1)[0] == "DSTORE": 165 | sts = await message.reply("𝙰𝙲𝙲𝙴𝚂𝚂𝙸𝙽𝙶 𝙵𝙸𝙻𝙴𝚂.../") 166 | b_string = data.split("-", 1)[1] 167 | decoded = (base64.urlsafe_b64decode(b_string + "=" * (-len(b_string) % 4))).decode("ascii") 168 | try: 169 | f_msg_id, l_msg_id, f_chat_id, protect = decoded.split("_", 3) 170 | except: 171 | f_msg_id, l_msg_id, f_chat_id = decoded.split("_", 2) 172 | protect = "/pbatch" if PROTECT_CONTENT else "batch" 173 | diff = int(l_msg_id) - int(f_msg_id) 174 | async for msg in client.iter_messages(int(f_chat_id), int(l_msg_id), int(f_msg_id)): 175 | if msg.media: 176 | media = getattr(msg, msg.media.value) 177 | if BATCH_FILE_CAPTION: 178 | try: 179 | f_caption=BATCH_FILE_CAPTION.format(file_name=getattr(media, 'file_name', ''), file_size=getattr(media, 'file_size', ''), file_caption=getattr(msg, 'caption', '')) 180 | except Exception as e: 181 | logger.exception(e) 182 | f_caption = getattr(msg, 'caption', '') 183 | else: 184 | media = getattr(msg, msg.media.value) 185 | file_name = getattr(media, 'file_name', '') 186 | f_caption = getattr(msg, 'caption', file_name) 187 | try: 188 | await msg.copy(message.chat.id, caption=f_caption, protect_content=True if protect == "/pbatch" else False) 189 | except FloodWait as e: 190 | await asyncio.sleep(e.x) 191 | await msg.copy(message.chat.id, caption=f_caption, protect_content=True if protect == "/pbatch" else False) 192 | except Exception as e: 193 | logger.exception(e) 194 | continue 195 | elif msg.empty: 196 | continue 197 | else: 198 | try: 199 | await msg.copy(message.chat.id, protect_content=True if protect == "/pbatch" else False) 200 | except FloodWait as e: 201 | await asyncio.sleep(e.x) 202 | await msg.copy(message.chat.id, protect_content=True if protect == "/pbatch" else False) 203 | except Exception as e: 204 | logger.exception(e) 205 | continue 206 | await asyncio.sleep(1) 207 | return await sts.delete() 208 | 209 | 210 | files_ = await get_file_details(file_id) 211 | if not files_: 212 | pre, file_id = ((base64.urlsafe_b64decode(data + "=" * (-len(data) % 4))).decode("ascii")).split("_", 1) 213 | try: 214 | msg = await client.send_cached_media( 215 | chat_id=message.from_user.id, 216 | file_id=file_id, 217 | protect_content=True if pre == 'filep' else False, 218 | ) 219 | filetype = msg.media 220 | file = getattr(msg, filetype.value) 221 | title = file.file_name 222 | size=get_size(file.file_size) 223 | f_caption = f"{title}" 224 | if CUSTOM_FILE_CAPTION: 225 | try: 226 | f_caption=CUSTOM_FILE_CAPTION.format(file_name= '' if title is None else title, file_size='' if size is None else size, file_caption='') 227 | except: 228 | return 229 | await msg.edit_caption(f_caption) 230 | return 231 | except: 232 | pass 233 | return await message.reply('No such file exist.') 234 | files = files_[0] 235 | title = files.file_name 236 | size=get_size(files.file_size) 237 | f_caption=files.caption 238 | if CUSTOM_FILE_CAPTION: 239 | try: 240 | f_caption=CUSTOM_FILE_CAPTION.format(file_name= '' if title is None else title, file_size='' if size is None else size, file_caption='' if f_caption is None else f_caption) 241 | except Exception as e: 242 | logger.exception(e) 243 | f_caption=f_caption 244 | if f_caption is None: 245 | f_caption = f"{files.file_name}" 246 | await client.send_cached_media( 247 | chat_id=message.from_user.id, 248 | file_id=file_id, 249 | caption=f_caption, 250 | reply_markup=InlineKeyboardMarkup( [ [InlineKeyboardButton('sᴜʙsᴄʀɪʙᴇ', url='https://youtube.com/@LazyDeveloperr')] ] ), 251 | protect_content=True if pre == 'filep' else False, 252 | ) 253 | 254 | 255 | @Client.on_message(filters.command('channel') & filters.user(ADMINS)) 256 | async def channel_info(bot, message): 257 | 258 | """Send basic information of channel""" 259 | if isinstance(CHANNELS, (int, str)): 260 | channels = [CHANNELS] 261 | elif isinstance(CHANNELS, list): 262 | channels = CHANNELS 263 | else: 264 | raise ValueError("Unexpected type of CHANNELS") 265 | 266 | text = '📑 **Indexed channels/groups**\n' 267 | for channel in channels: 268 | chat = await bot.get_chat(channel) 269 | if chat.username: 270 | text += '\n@' + chat.username 271 | else: 272 | text += '\n' + chat.title or chat.first_name 273 | 274 | text += f'\n\n**Total:** {len(CHANNELS)}' 275 | 276 | if len(text) < 4096: 277 | await message.reply(text) 278 | else: 279 | file = 'Indexed channels.txt' 280 | with open(file, 'w') as f: 281 | f.write(text) 282 | await message.reply_document(file) 283 | os.remove(file) 284 | 285 | 286 | @Client.on_message(filters.command('logs') & filters.user(ADMINS)) 287 | async def log_file(bot, message): 288 | """Send log file""" 289 | try: 290 | await message.reply_document('TelegramBot.log') 291 | except Exception as e: 292 | await message.reply(str(e)) 293 | 294 | @Client.on_message(filters.command('delete') & filters.user(ADMINS)) 295 | async def delete(bot, message): 296 | """Delete file from database""" 297 | reply = message.reply_to_message 298 | if reply and reply.media: 299 | msg = await message.reply("𝐃𝐞𝐥𝐞𝐭𝐢𝐧𝐠....🗑️", quote=True) 300 | else: 301 | await message.reply('Reply to file with /delete which you want to delete', quote=True) 302 | return 303 | 304 | for file_type in ("document", "video", "audio"): 305 | media = getattr(reply, file_type, None) 306 | if media is not None: 307 | break 308 | else: 309 | await msg.edit('This is not supported file format') 310 | return 311 | 312 | file_id, file_ref = unpack_new_file_id(media.file_id) 313 | 314 | result = await Media.collection.delete_one({ 315 | '_id': file_id, 316 | }) 317 | if result.deleted_count: 318 | await msg.edit('**𝙵𝙸𝙻𝙴 𝚂𝚄𝙲𝙲𝙴𝚂𝚂𝙵𝚄𝙻𝙻𝚈 𝙳𝙴𝙻𝙴𝚃𝙴𝙳**') 319 | else: 320 | file_name = re.sub(r"(_|\-|\.|\+)", " ", str(media.file_name)) 321 | result = await Media.collection.delete_many({ 322 | 'file_name': file_name, 323 | 'file_size': media.file_size, 324 | 'mime_type': media.mime_type 325 | }) 326 | if result.deleted_count: 327 | await msg.edit('**𝙵𝙸𝙻𝙴 𝚂𝚄𝙲𝙲𝙴𝚂𝚂𝙵𝚄𝙻𝙻𝚈 𝙳𝙴𝙻𝙴𝚃𝙴𝙳**') 328 | else: 329 | # files indexed before https://github.com/EvamariaTG/EvaMaria/commit/f3d2a1bcb155faf44178e5d7a685a1b533e714bf#diff-86b613edf1748372103e94cacff3b578b36b698ef9c16817bb98fe9ef22fb669R39 330 | # have original file name. 331 | result = await Media.collection.delete_many({ 332 | 'file_name': media.file_name, 333 | 'file_size': media.file_size, 334 | 'mime_type': media.mime_type 335 | }) 336 | if result.deleted_count: 337 | await msg.edit('**𝙵𝙸𝙻𝙴 𝚂𝚄𝙲𝙲𝙴𝚂𝚂𝙵𝚄𝙻𝙻𝚈 𝙳𝙴𝙻𝙴𝚃𝙴𝙳**') 338 | else: 339 | await msg.edit('File not found in database') 340 | 341 | 342 | @Client.on_message(filters.command('deleteall') & filters.user(ADMINS)) 343 | async def delete_all_index(bot, message): 344 | await message.reply_text( 345 | '**𝚃𝙷𝙸𝚂 𝙿𝚁𝙾𝙲𝙴𝚂𝚂 𝚆𝙸𝙻𝙻 𝙳𝙴𝙻𝙴𝚃𝙴 𝙰𝙻𝙻 𝚃𝙷𝙴 𝙵𝙸𝙻𝙴𝚂 𝙵𝚁𝙾𝙼 𝚈𝙾𝚄𝚁 𝙳𝙰𝚃𝙰𝙱𝙰𝚂𝙴.\n𝙳𝙾 𝚈𝙾𝚄 𝚆𝙰𝙽𝚃 𝚃𝙾 𝙲𝙾𝙽𝚃𝙸𝙽𝚄𝙴 𝚃𝙷𝙸𝚂..??**', 346 | reply_markup=InlineKeyboardMarkup( 347 | [ 348 | [ 349 | InlineKeyboardButton( 350 | text="⚡ 𝐘𝐞𝐬 ⚡", callback_data="autofilter_delete" 351 | ) 352 | ], 353 | [ 354 | InlineKeyboardButton( 355 | text="❄ 𝐂𝐚𝐧𝐜𝐞𝐥 ❄", callback_data="close_data" 356 | ) 357 | ], 358 | ] 359 | ), 360 | quote=True, 361 | ) 362 | 363 | 364 | @Client.on_callback_query(filters.regex(r'^autofilter_delete')) 365 | async def delete_all_index_confirm(bot, message): 366 | await Media.collection.drop() 367 | await message.answer('𝙿𝙻𝙴𝙰𝚂𝙴 𝚂𝙷𝙰𝚁𝙴 𝙰𝙽𝙳 𝚂𝚄𝙿𝙿𝙾𝚁𝚃') 368 | await message.message.edit('Succesfully Deleted All The Indexed Files.') 369 | 370 | 371 | @Client.on_message(filters.command('settings')) 372 | async def settings(client, message): 373 | userid = message.from_user.id if message.from_user else None 374 | if not userid: 375 | return await message.reply(f"You are anonymous admin. Use /connect {message.chat.id} in PM") 376 | chat_type = message.chat.type 377 | 378 | if chat_type == enums.ChatType.PRIVATE: 379 | grpid = await active_connection(str(userid)) 380 | if grpid is not None: 381 | grp_id = grpid 382 | try: 383 | chat = await client.get_chat(grpid) 384 | title = chat.title 385 | except: 386 | await message.reply_text("Make sure I'm present in your group!!", quote=True) 387 | return 388 | else: 389 | await message.reply_text("I'm not connected to any groups!", quote=True) 390 | return 391 | 392 | elif chat_type in [enums.ChatType.GROUP, enums.ChatType.SUPERGROUP]: 393 | grp_id = message.chat.id 394 | title = message.chat.title 395 | 396 | else: 397 | return 398 | 399 | st = await client.get_chat_member(grp_id, userid) 400 | if ( 401 | st.status != enums.ChatMemberStatus.ADMINISTRATOR 402 | and st.status != enums.ChatMemberStatus.OWNER 403 | and str(userid) not in ADMINS 404 | ): 405 | return 406 | 407 | settings = await get_settings(grp_id) 408 | 409 | if settings is not None: 410 | buttons = [ 411 | [ 412 | InlineKeyboardButton( 413 | '𝐅𝐈𝐋𝐓𝐄𝐑 𝐁𝐔𝐓𝐓𝐎𝐍', 414 | callback_data=f'setgs#button#{settings["button"]}#{grp_id}', 415 | ), 416 | InlineKeyboardButton( 417 | '𝐒𝐈𝐍𝐆𝐋𝐄' if settings["button"] else '𝐃𝐎𝐔𝐁𝐋𝐄', 418 | callback_data=f'setgs#button#{settings["button"]}#{grp_id}', 419 | ), 420 | ], 421 | [ 422 | InlineKeyboardButton( 423 | '𝐁𝐎𝐓 𝐏𝐌', 424 | callback_data=f'setgs#botpm#{settings["botpm"]}#{grp_id}', 425 | ), 426 | InlineKeyboardButton( 427 | '✅ 𝐘𝐄𝐒' if settings["botpm"] else '❌ 𝐍𝐎', 428 | callback_data=f'setgs#botpm#{settings["botpm"]}#{grp_id}', 429 | ), 430 | ], 431 | [ 432 | InlineKeyboardButton( 433 | '𝐅𝐈𝐋𝐄 𝐒𝐄𝐂𝐔𝐑𝐄', 434 | callback_data=f'setgs#file_secure#{settings["file_secure"]}#{grp_id}', 435 | ), 436 | InlineKeyboardButton( 437 | '✅ 𝐘𝐄𝐒' if settings["file_secure"] else '❌ 𝐍𝐎', 438 | callback_data=f'setgs#file_secure#{settings["file_secure"]}#{grp_id}', 439 | ), 440 | ], 441 | [ 442 | InlineKeyboardButton( 443 | '𝐈𝐌𝐃𝐁', 444 | callback_data=f'setgs#imdb#{settings["imdb"]}#{grp_id}', 445 | ), 446 | InlineKeyboardButton( 447 | '✅ 𝐘𝐄𝐒' if settings["imdb"] else '❌ 𝐍𝐎', 448 | callback_data=f'setgs#imdb#{settings["imdb"]}#{grp_id}', 449 | ), 450 | ], 451 | [ 452 | InlineKeyboardButton( 453 | '𝐒𝐏𝐄𝐋𝐋 𝐂𝐇𝐄𝐂𝐊', 454 | callback_data=f'setgs#spell_check#{settings["spell_check"]}#{grp_id}', 455 | ), 456 | InlineKeyboardButton( 457 | '✅ 𝐘𝐄𝐒' if settings["spell_check"] else '❌ 𝐍𝐎', 458 | callback_data=f'setgs#spell_check#{settings["spell_check"]}#{grp_id}', 459 | ), 460 | ], 461 | [ 462 | InlineKeyboardButton( 463 | '𝐖𝐄𝐋𝐂𝐎𝐌𝐄', 464 | callback_data=f'setgs#welcome#{settings["welcome"]}#{grp_id}', 465 | ), 466 | InlineKeyboardButton( 467 | '✅ 𝐘𝐄𝐒' if settings["welcome"] else '❌ 𝐍𝐎', 468 | callback_data=f'setgs#welcome#{settings["welcome"]}#{grp_id}', 469 | ), 470 | ], 471 | ] 472 | 473 | reply_markup = InlineKeyboardMarkup(buttons) 474 | 475 | await message.reply_text( 476 | text=f"𝙲𝙷𝙰𝙽𝙶𝙴 𝚃𝙷𝙴 𝙱𝙾𝚃 𝚂𝙴𝚃𝚃𝙸𝙽𝙶𝚂 𝙵𝙾𝚁 {title}..⚙", 477 | reply_markup=reply_markup, 478 | disable_web_page_preview=True, 479 | parse_mode=enums.ParseMode.HTML, 480 | reply_to_message_id=message.id 481 | ) 482 | 483 | 484 | 485 | @Client.on_message(filters.command('set_template')) 486 | async def save_template(client, message): 487 | sts = await message.reply("**𝙲𝙷𝙴𝙲𝙺𝙸𝙽𝙶 𝙽𝙴𝚆 𝚃𝙴𝙼𝙿𝙻𝙰𝚃𝙴**") 488 | userid = message.from_user.id if message.from_user else None 489 | if not userid: 490 | return await message.reply(f"You are anonymous admin. Use /connect {message.chat.id} in PM") 491 | chat_type = message.chat.type 492 | 493 | if chat_type == enums.ChatType.PRIVATE: 494 | grpid = await active_connection(str(userid)) 495 | if grpid is not None: 496 | grp_id = grpid 497 | try: 498 | chat = await client.get_chat(grpid) 499 | title = chat.title 500 | except: 501 | await message.reply_text("Make sure I'm present in your group!!", quote=True) 502 | return 503 | else: 504 | await message.reply_text("I'm not connected to any groups!", quote=True) 505 | return 506 | 507 | elif chat_type in [enums.ChatType.GROUP, enums.ChatType.SUPERGROUP]: 508 | grp_id = message.chat.id 509 | title = message.chat.title 510 | 511 | else: 512 | return 513 | 514 | st = await client.get_chat_member(grp_id, userid) 515 | if ( 516 | st.status != enums.ChatMemberStatus.ADMINISTRATOR 517 | and st.status != enums.ChatMemberStatus.OWNER 518 | and str(userid) not in ADMINS 519 | ): 520 | return 521 | 522 | if len(message.command) < 2: 523 | return await sts.edit("No Input!!") 524 | template = message.text.split(" ", 1)[1] 525 | await save_group_settings(grp_id, 'template', template) 526 | await sts.edit(f"𝚂𝚄𝙲𝙲𝙴𝚂𝚂𝙵𝚄𝙻𝙻𝚈 𝚄𝙿𝙶𝚁𝙰𝙳𝙴𝙳 𝚈𝙾𝚄𝚁 𝚃𝙴𝙼𝙿𝙻𝙰𝚃𝙴 𝙵𝙾𝚁 {title} to\n\n{template}") 527 | -------------------------------------------------------------------------------- /plugins/connection.py: -------------------------------------------------------------------------------- 1 | from pyrogram import filters, Client, enums 2 | from pyrogram.types import InlineKeyboardButton, InlineKeyboardMarkup 3 | from database.connections_mdb import add_connection, all_connections, if_active, delete_connection 4 | from info import ADMINS 5 | import logging 6 | 7 | logger = logging.getLogger(__name__) 8 | logger.setLevel(logging.ERROR) 9 | 10 | 11 | @Client.on_message((filters.private | filters.group) & filters.command('connect')) 12 | async def addconnection(client, message): 13 | userid = message.from_user.id if message.from_user else None 14 | if not userid: 15 | return await message.reply(f"You are anonymous admin. Use /connect {message.chat.id} in PM") 16 | chat_type = message.chat.type 17 | 18 | if chat_type == enums.ChatType.PRIVATE: 19 | try: 20 | cmd, group_id = message.text.split(" ", 1) 21 | except: 22 | await message.reply_text( 23 | "𝙴𝙽𝚃𝙴𝚁 𝙸𝙽 𝙲𝙾𝚁𝚁𝙴𝙲𝚃 𝙵𝙾𝚁𝙼𝙰𝚃!\n\n" 24 | "/connect 𝙶𝚁𝙾𝚄𝙿 𝙸𝙳\n\n" 25 | "Get your Group id by adding this bot to your group and use /id", 26 | quote=True 27 | ) 28 | return 29 | 30 | elif chat_type in [enums.ChatType.GROUP, enums.ChatType.SUPERGROUP]: 31 | group_id = message.chat.id 32 | 33 | try: 34 | st = await client.get_chat_member(group_id, userid) 35 | if ( 36 | st.status != enums.ChatMemberStatus.ADMINISTRATOR 37 | and st.status != enums.ChatMemberStatus.OWNER 38 | and userid not in ADMINS 39 | ): 40 | await message.reply_text("You should be an admin in Given group!", quote=True) 41 | return 42 | except Exception as e: 43 | logger.exception(e) 44 | await message.reply_text( 45 | "Invalid Group ID!\n\nIf correct, Make sure I'm present in your group!!", 46 | quote=True, 47 | ) 48 | 49 | return 50 | try: 51 | st = await client.get_chat_member(group_id, "me") 52 | if st.status == enums.ChatMemberStatus.ADMINISTRATOR: 53 | ttl = await client.get_chat(group_id) 54 | title = ttl.title 55 | 56 | addcon = await add_connection(str(group_id), str(userid)) 57 | if addcon: 58 | await message.reply_text( 59 | f"𝚂𝚄𝙲𝙲𝙴𝚂𝚂𝙵𝚄𝙻𝙻𝚈 𝙲𝙾𝙽𝙽𝙴𝙲𝚃 𝚃𝙾 **{title}**\n𝙽𝙾𝚆 𝚈𝙾𝚄 𝙲𝙰𝙽 𝙼𝙰𝙽𝙰𝙶𝙴 𝚈𝙾𝚄𝚁 𝙶𝚁𝙾𝚄𝙿 𝙵𝚁𝙾𝙼 𝙷𝙴𝚁𝙴../", 60 | quote=True, 61 | parse_mode=enums.ParseMode.MARKDOWN 62 | ) 63 | if chat_type in [enums.ChatType.GROUP, enums.ChatType.SUPERGROUP]: 64 | await client.send_message( 65 | userid, 66 | f"Connected to **{title}** !", 67 | parse_mode=enums.ParseMode.MARKDOWN 68 | ) 69 | else: 70 | await message.reply_text( 71 | "You're already connected to this chat!", 72 | quote=True 73 | ) 74 | else: 75 | await message.reply_text("Add me as an admin in group", quote=True) 76 | except Exception as e: 77 | logger.exception(e) 78 | await message.reply_text('Some error occurred! Try again later.', quote=True) 79 | return 80 | 81 | 82 | @Client.on_message((filters.private | filters.group) & filters.command('disconnect')) 83 | async def deleteconnection(client, message): 84 | userid = message.from_user.id if message.from_user else None 85 | if not userid: 86 | return await message.reply(f"You are anonymous admin. Use /connect {message.chat.id} in PM") 87 | chat_type = message.chat.type 88 | 89 | if chat_type == enums.ChatType.PRIVATE: 90 | await message.reply_text("Run /connections to view or disconnect from groups!", quote=True) 91 | 92 | elif chat_type in [enums.ChatType.GROUP, enums.ChatType.SUPERGROUP]: 93 | group_id = message.chat.id 94 | 95 | st = await client.get_chat_member(group_id, userid) 96 | if ( 97 | st.status != enums.ChatMemberStatus.ADMINISTRATOR 98 | and st.status != enums.ChatMemberStatus.OWNER 99 | and str(userid) not in ADMINS 100 | ): 101 | return 102 | 103 | delcon = await delete_connection(str(userid), str(group_id)) 104 | if delcon: 105 | await message.reply_text("Successfully disconnected from this chat", quote=True) 106 | else: 107 | await message.reply_text("This chat isn't connected to me!\nDo /connect to connect.", quote=True) 108 | 109 | 110 | @Client.on_message(filters.private & filters.command(["connections"])) 111 | async def connections(client, message): 112 | userid = message.from_user.id 113 | 114 | groupids = await all_connections(str(userid)) 115 | if groupids is None: 116 | await message.reply_text( 117 | "There are no active connections!! Connect to some groups first.", 118 | quote=True 119 | ) 120 | return 121 | buttons = [] 122 | for groupid in groupids: 123 | try: 124 | ttl = await client.get_chat(int(groupid)) 125 | title = ttl.title 126 | active = await if_active(str(userid), str(groupid)) 127 | act = " - ACTIVE" if active else "" 128 | buttons.append( 129 | [ 130 | InlineKeyboardButton( 131 | text=f"{title}{act}", callback_data=f"groupcb:{groupid}:{act}" 132 | ) 133 | ] 134 | ) 135 | except: 136 | pass 137 | if buttons: 138 | await message.reply_text( 139 | "𝙲𝙾𝙽𝙽𝙴𝙲𝚃𝙴𝙳 𝙶𝚁𝙾𝚄𝙿𝚂 :-\n\n", 140 | reply_markup=InlineKeyboardMarkup(buttons), 141 | quote=True 142 | ) 143 | else: 144 | await message.reply_text( 145 | "There are no active connections!! Connect to some groups first.", 146 | quote=True 147 | ) 148 | -------------------------------------------------------------------------------- /plugins/filters.py: -------------------------------------------------------------------------------- 1 | import io 2 | from pyrogram import filters, Client, enums 3 | from pyrogram.types import InlineKeyboardButton, InlineKeyboardMarkup 4 | from database.filters_mdb import( 5 | add_filter, 6 | get_filters, 7 | delete_filter, 8 | count_filters 9 | ) 10 | 11 | from database.connections_mdb import active_connection 12 | from utils import get_file_id, parser, split_quotes 13 | from info import ADMINS 14 | 15 | 16 | @Client.on_message(filters.command(['filter', 'add']) & filters.incoming) 17 | async def addfilter(client, message): 18 | userid = message.from_user.id if message.from_user else None 19 | if not userid: 20 | return await message.reply(f"You are anonymous admin. Use /connect {message.chat.id} in PM") 21 | chat_type = message.chat.type 22 | args = message.text.html.split(None, 1) 23 | 24 | if chat_type == enums.ChatType.PRIVATE: 25 | grpid = await active_connection(str(userid)) 26 | if grpid is not None: 27 | grp_id = grpid 28 | try: 29 | chat = await client.get_chat(grpid) 30 | title = chat.title 31 | except: 32 | await message.reply_text("Make sure I'm present in your group!!", quote=True) 33 | return 34 | else: 35 | await message.reply_text("I'm not connected to any groups!", quote=True) 36 | return 37 | 38 | elif chat_type in [enums.ChatType.GROUP, enums.ChatType.SUPERGROUP]: 39 | grp_id = message.chat.id 40 | title = message.chat.title 41 | 42 | else: 43 | return 44 | 45 | st = await client.get_chat_member(grp_id, userid) 46 | if ( 47 | st.status != enums.ChatMemberStatus.ADMINISTRATOR 48 | and st.status != enums.ChatMemberStatus.OWNER 49 | and str(userid) not in ADMINS 50 | ): 51 | return 52 | 53 | 54 | if len(args) < 2: 55 | await message.reply_text("Command Incomplete :(", quote=True) 56 | return 57 | 58 | extracted = split_quotes(args[1]) 59 | text = extracted[0].lower() 60 | 61 | if not message.reply_to_message and len(extracted) < 2: 62 | await message.reply_text("Add some content to save your filter!", quote=True) 63 | return 64 | 65 | if (len(extracted) >= 2) and not message.reply_to_message: 66 | reply_text, btn, alert = parser(extracted[1], text) 67 | fileid = None 68 | if not reply_text: 69 | await message.reply_text("You cannot have buttons alone, give some text to go with it!", quote=True) 70 | return 71 | 72 | elif message.reply_to_message and message.reply_to_message.reply_markup: 73 | try: 74 | rm = message.reply_to_message.reply_markup 75 | btn = rm.inline_keyboard 76 | msg = get_file_id(message.reply_to_message) 77 | if msg: 78 | fileid = msg.file_id 79 | reply_text = message.reply_to_message.caption.html 80 | else: 81 | reply_text = message.reply_to_message.text.html 82 | fileid = None 83 | alert = None 84 | except: 85 | reply_text = "" 86 | btn = "[]" 87 | fileid = None 88 | alert = None 89 | 90 | elif message.reply_to_message and message.reply_to_message.media: 91 | try: 92 | msg = get_file_id(message.reply_to_message) 93 | fileid = msg.file_id if msg else None 94 | reply_text, btn, alert = parser(extracted[1], text) if message.reply_to_message.sticker else parser(message.reply_to_message.caption.html, text) 95 | except: 96 | reply_text = "" 97 | btn = "[]" 98 | alert = None 99 | elif message.reply_to_message and message.reply_to_message.text: 100 | try: 101 | fileid = None 102 | reply_text, btn, alert = parser(message.reply_to_message.text.html, text) 103 | except: 104 | reply_text = "" 105 | btn = "[]" 106 | alert = None 107 | else: 108 | return 109 | 110 | await add_filter(grp_id, text, reply_text, btn, fileid, alert) 111 | 112 | await message.reply_text( 113 | f"Filter for `{text}` added in **{title}**", 114 | quote=True, 115 | parse_mode=enums.ParseMode.MARKDOWN 116 | ) 117 | 118 | 119 | @Client.on_message(filters.command(['viewfilters', 'filters']) & filters.incoming) 120 | async def get_all(client, message): 121 | 122 | chat_type = message.chat.type 123 | userid = message.from_user.id if message.from_user else None 124 | if not userid: 125 | return await message.reply(f"You are anonymous admin. Use /connect {message.chat.id} in PM") 126 | if chat_type == enums.ChatType.PRIVATE: 127 | grpid = await active_connection(str(userid)) 128 | if grpid is not None: 129 | grp_id = grpid 130 | try: 131 | chat = await client.get_chat(grpid) 132 | title = chat.title 133 | except: 134 | await message.reply_text("Make sure I'm present in your group!!", quote=True) 135 | return 136 | else: 137 | await message.reply_text("I'm not connected to any groups!", quote=True) 138 | return 139 | 140 | elif chat_type in [enums.ChatType.GROUP, enums.ChatType.SUPERGROUP]: 141 | grp_id = message.chat.id 142 | title = message.chat.title 143 | 144 | else: 145 | return 146 | 147 | st = await client.get_chat_member(grp_id, userid) 148 | if ( 149 | st.status != enums.ChatMemberStatus.ADMINISTRATOR 150 | and st.status != enums.ChatMemberStatus.OWNER 151 | and str(userid) not in ADMINS 152 | ): 153 | return 154 | 155 | texts = await get_filters(grp_id) 156 | count = await count_filters(grp_id) 157 | if count: 158 | filterlist = f"Total number of filters in **{title}** : {count}\n\n" 159 | 160 | for text in texts: 161 | keywords = " × `{}`\n".format(text) 162 | 163 | filterlist += keywords 164 | 165 | if len(filterlist) > 4096: 166 | with io.BytesIO(str.encode(filterlist.replace("`", ""))) as keyword_file: 167 | keyword_file.name = "keywords.txt" 168 | await message.reply_document( 169 | document=keyword_file, 170 | quote=True 171 | ) 172 | return 173 | else: 174 | filterlist = f"There are no active filters in **{title}**" 175 | 176 | await message.reply_text( 177 | text=filterlist, 178 | quote=True, 179 | parse_mode=enums.ParseMode.MARKDOWN 180 | ) 181 | 182 | @Client.on_message(filters.command('del') & filters.incoming) 183 | async def deletefilter(client, message): 184 | userid = message.from_user.id if message.from_user else None 185 | if not userid: 186 | return await message.reply(f"You are anonymous admin. Use /connect {message.chat.id} in PM") 187 | chat_type = message.chat.type 188 | 189 | if chat_type == enums.ChatType.PRIVATE: 190 | grpid = await active_connection(str(userid)) 191 | if grpid is not None: 192 | grp_id = grpid 193 | try: 194 | chat = await client.get_chat(grpid) 195 | title = chat.title 196 | except: 197 | await message.reply_text("Make sure I'm present in your group!!", quote=True) 198 | return 199 | else: 200 | await message.reply_text("I'm not connected to any groups!", quote=True) 201 | return 202 | 203 | elif chat_type in [enums.ChatType.GROUP, enums.ChatType.SUPERGROUP]: 204 | grp_id = message.chat.id 205 | title = message.chat.title 206 | 207 | else: 208 | return 209 | 210 | st = await client.get_chat_member(grp_id, userid) 211 | if ( 212 | st.status != enums.ChatMemberStatus.ADMINISTRATOR 213 | and st.status != enums.ChatMemberStatus.OWNER 214 | and str(userid) not in ADMINS 215 | ): 216 | return 217 | 218 | try: 219 | cmd, text = message.text.split(" ", 1) 220 | except: 221 | await message.reply_text( 222 | "Mention the filtername which you wanna delete!\n\n" 223 | "/del filtername\n\n" 224 | "Use /viewfilters to view all available filters", 225 | quote=True 226 | ) 227 | return 228 | 229 | query = text.lower() 230 | 231 | await delete_filter(message, query, grp_id) 232 | 233 | 234 | @Client.on_message(filters.command('delall') & filters.incoming) 235 | async def delallconfirm(client, message): 236 | userid = message.from_user.id if message.from_user else None 237 | if not userid: 238 | return await message.reply(f"You are anonymous admin. Use /connect {message.chat.id} in PM") 239 | chat_type = message.chat.type 240 | 241 | if chat_type == enums.ChatType.PRIVATE: 242 | grpid = await active_connection(str(userid)) 243 | if grpid is not None: 244 | grp_id = grpid 245 | try: 246 | chat = await client.get_chat(grpid) 247 | title = chat.title 248 | except: 249 | await message.reply_text("Make sure I'm present in your group!!", quote=True) 250 | return 251 | else: 252 | await message.reply_text("I'm not connected to any groups!", quote=True) 253 | return 254 | 255 | elif chat_type in [enums.ChatType.GROUP, enums.ChatType.SUPERGROUP]: 256 | grp_id = message.chat.id 257 | title = message.chat.title 258 | 259 | else: 260 | return 261 | 262 | 263 | st = await client.get_chat_member(grp_id, userid) 264 | if (st.status == enums.ChatMemberStatus.OWNER) or (str(userid) in ADMINS): 265 | await message.reply_text( 266 | f"This will delete all filters from '{title}'.\nDo you want to continue??", 267 | reply_markup=InlineKeyboardMarkup([ 268 | [InlineKeyboardButton(text="YES",callback_data="delallconfirm")], 269 | [InlineKeyboardButton(text="CANCEL",callback_data="delallcancel")] 270 | ]), 271 | quote=True 272 | ) 273 | 274 | -------------------------------------------------------------------------------- /plugins/genlink.py: -------------------------------------------------------------------------------- 1 | import re 2 | from pyrogram import filters, Client, enums 3 | from pyrogram.errors.exceptions.bad_request_400 import ChannelInvalid, UsernameInvalid, UsernameNotModified 4 | from info import ADMINS, LOG_CHANNEL, FILE_STORE_CHANNEL, PUBLIC_FILE_STORE 5 | from database.ia_filterdb import unpack_new_file_id 6 | from utils import temp 7 | import re 8 | import os 9 | import json 10 | import base64 11 | import logging 12 | 13 | logger = logging.getLogger(__name__) 14 | logger.setLevel(logging.INFO) 15 | 16 | async def allowed(_, __, message): 17 | if PUBLIC_FILE_STORE: 18 | return True 19 | if message.from_user and message.from_user.id in ADMINS: 20 | return True 21 | return False 22 | 23 | @Client.on_message(filters.command(['link', 'plink']) & filters.create(allowed)) 24 | async def gen_link_s(bot, message): 25 | replied = message.reply_to_message 26 | if not replied: 27 | return await message.reply('𝚁𝙴𝙿𝙻𝚈 𝚃𝙾 𝙰 𝙼𝙴𝚂𝚂𝙰𝙶𝙴 𝙾𝚁 𝙰 𝙵𝙸𝙻𝙴. 𝙸 𝚆𝙸𝙻𝙻 𝙶𝙸𝚅𝙴 𝚈𝙾𝚄 𝙰 𝚂𝙷𝙰𝚁𝙰𝙱𝙻𝙴 𝙿𝙴𝚁𝙼𝙰𝙽𝙴𝙽𝚃 𝙻𝙸𝙽𝙺') 28 | file_type = replied.media 29 | if file_type not in [enums.MessageMediaType.VIDEO, enums.MessageMediaType.AUDIO, enums.MessageMediaType.DOCUMENT]: 30 | return await message.reply("𝚁𝙴𝙿𝙻𝚈 𝚃𝙾 𝙰 𝚂𝚄𝙿𝙿𝙾𝚁𝚃𝙴𝙳 𝙼𝙴𝙳𝙸𝙰") 31 | if message.has_protected_content and message.chat.id not in ADMINS: 32 | return await message.reply("𝙾𝙺 𝙱𝚁𝙾") 33 | file_id, ref = unpack_new_file_id((getattr(replied, file_type.value)).file_id) 34 | string = 'filep_' if message.text.lower().strip() == "/plink" else 'file_' 35 | string += file_id 36 | outstr = base64.urlsafe_b64encode(string.encode("ascii")).decode().strip("=") 37 | await message.reply(f"⪼ 𝙷𝙴𝚁𝙴 𝙸𝚂 𝚈𝙾𝚄𝚁 𝙻𝙸𝙽𝙺:\nhttps://t.me/{temp.U_NAME}?start={outstr}") 38 | 39 | 40 | @Client.on_message(filters.command(['batch', 'pbatch']) & filters.create(allowed)) 41 | async def gen_link_batch(bot, message): 42 | if " " not in message.text: 43 | return await message.reply("𝚄𝚂𝙴 𝙲𝙾𝚁𝚁𝙴𝙲𝚃 𝙵𝙾𝚁𝙼𝙰𝚃.\n𝙴𝚇𝙰𝙼𝙿𝙻𝙴 ›› /batch https://t.me/LazyDeveloper/10 https://t.me/LazyDeveloper/20.") 44 | links = message.text.strip().split(" ") 45 | if len(links) != 3: 46 | return await message.reply("Use correct format.\nExample /batch https://t.me/LazyDeveloper/10 https://t.me/LazyDeveloper/20.") 47 | cmd, first, last = links 48 | regex = re.compile("(https://)?(t\.me/|telegram\.me/|telegram\.dog/)(c/)?(\d+|[a-zA-Z_0-9]+)/(\d+)$") 49 | match = regex.match(first) 50 | if not match: 51 | return await message.reply('Invalid link') 52 | f_chat_id = match.group(4) 53 | f_msg_id = int(match.group(5)) 54 | if f_chat_id.isnumeric(): 55 | f_chat_id = int(("-100" + f_chat_id)) 56 | 57 | match = regex.match(last) 58 | if not match: 59 | return await message.reply('Invalid link') 60 | l_chat_id = match.group(4) 61 | l_msg_id = int(match.group(5)) 62 | if l_chat_id.isnumeric(): 63 | l_chat_id = int(("-100" + l_chat_id)) 64 | 65 | if f_chat_id != l_chat_id: 66 | return await message.reply("Chat ids not matched.") 67 | try: 68 | chat_id = (await bot.get_chat(f_chat_id)).id 69 | except ChannelInvalid: 70 | return await message.reply('𝚃𝙷𝙸𝚂 𝙼𝙰𝚈 𝙱𝙴 𝙰 𝙿𝚁𝙸𝚅𝙰𝚃𝙴 𝙲𝙷𝙰𝙽𝙽𝙴𝙻 / 𝙶𝚁𝙾𝚄𝙿. 𝙼𝙰𝙺𝙴 𝙼𝙴 𝙰𝙽 𝙰𝙳𝙼𝙸𝙽 𝙾𝚅𝙴𝚁 𝚃𝙷𝙴𝚁𝙴 𝚃𝙾 𝙸𝙽𝙳𝙴𝚇 𝚃𝙷𝙴 𝙵𝙸𝙻𝙴𝚂.') 71 | except (UsernameInvalid, UsernameNotModified): 72 | return await message.reply('Invalid Link specified.') 73 | except Exception as e: 74 | return await message.reply(f'Errors - {e}') 75 | 76 | sts = await message.reply("𝙶𝚎𝚗𝚎𝚛𝚊𝚝𝚒𝚗𝚐 𝙻𝚒𝚗𝚔 𝙵𝚘𝚛 𝚈𝚘𝚞𝚛 𝙼𝚎𝚜𝚜𝚊𝚐𝚎.\n𝚃𝙷𝙸𝚂 𝙼𝙰𝚈𝙱𝙴 𝚃𝙰𝙺𝙴 𝚃𝙸𝙼𝙴 𝙳𝙴𝙿𝙴𝙽𝙳𝙸𝙽𝙶 𝚄𝙿𝙾𝙽 𝚃𝙷𝙴 𝙽𝚄𝙼𝙱𝙴𝚁 𝙾𝙵 𝙼𝙴𝚂𝚂𝙰𝙶𝙴𝚂") 77 | if chat_id in FILE_STORE_CHANNEL: 78 | string = f"{f_msg_id}_{l_msg_id}_{chat_id}_{cmd.lower().strip()}" 79 | b_64 = base64.urlsafe_b64encode(string.encode("ascii")).decode().strip("=") 80 | return await sts.edit(f"⪼ 𝙷𝙴𝚁𝙴 𝙸𝚂 𝚈𝙾𝚄𝚁 𝙻𝙸𝙽𝙺 ›› https://t.me/{temp.U_NAME}?start=DSTORE-{b_64}") 81 | 82 | FRMT = "╭━━━━━━━━━━━━━━━➣\n┣⪼𝙶𝙴𝙽𝙴𝚁𝙰𝚃𝙸𝙽𝙶 𝙻𝙸𝙽𝙺...\n┣⪼𝚃𝙾𝚃𝙰𝙻 𝙼𝙴𝚂𝚂𝙰𝙶𝙴𝚂: `{total}`\n┣⪼𝙳𝙾𝙽𝙴: `{current}`\n┣⪼𝚁𝙴𝙼𝙰𝙸𝙽𝙸𝙽𝙶: `{rem}`\n┣⪼𝚂𝚃𝙰𝚃𝚄𝚂: `{sts}`\n╰━━━━━━━━━━━━━━━➣" 83 | 84 | outlist = [] 85 | 86 | # file store without db channel 87 | og_msg = 0 88 | tot = 0 89 | async for msg in bot.iter_messages(f_chat_id, l_msg_id, f_msg_id): 90 | tot += 1 91 | if msg.empty or msg.service: 92 | continue 93 | if not msg.media: 94 | # only media messages supported. 95 | continue 96 | try: 97 | file_type = msg.media 98 | file = getattr(msg, file_type.value) 99 | caption = getattr(msg, 'caption', '') 100 | if caption: 101 | caption = caption.html 102 | if file: 103 | file = { 104 | "file_id": file.file_id, 105 | "caption": caption, 106 | "title": getattr(file, "file_name", ""), 107 | "size": file.file_size, 108 | "protect": cmd.lower().strip() == "/pbatch", 109 | } 110 | 111 | og_msg +=1 112 | outlist.append(file) 113 | except: 114 | pass 115 | if not og_msg % 20: 116 | try: 117 | await sts.edit(FRMT.format(total=l_msg_id-f_msg_id, current=tot, rem=((l_msg_id-f_msg_id) - tot), sts="Saving Messages")) 118 | except: 119 | pass 120 | with open(f"batchmode_{message.from_user.id}.json", "w+") as out: 121 | json.dump(outlist, out) 122 | post = await bot.send_document(LOG_CHANNEL, f"batchmode_{message.from_user.id}.json", file_name="Batch.json", caption="👩🏻‍💻 File Store Logs 👩🏻‍💻") 123 | os.remove(f"batchmode_{message.from_user.id}.json") 124 | file_id, ref = unpack_new_file_id(post.document.file_id) 125 | await sts.edit(f"⪼ 𝙷𝙴𝚁𝙴 𝙸𝚂 𝚈𝙾𝚄𝚁 𝙻𝙸𝙽𝙺\n𝙲𝙾𝙽𝚃𝙰𝙸𝙽𝚂 `{og_msg}` 𝙵𝙸𝙻𝙴𝚂.\n https://t.me/{temp.U_NAME}?start=BATCH-{file_id}") 126 | -------------------------------------------------------------------------------- /plugins/index.py: -------------------------------------------------------------------------------- 1 | import logging 2 | import asyncio 3 | from pyrogram import Client, filters, enums 4 | from pyrogram.errors import FloodWait 5 | from pyrogram.errors.exceptions.bad_request_400 import ChannelInvalid, ChatAdminRequired, UsernameInvalid, UsernameNotModified 6 | from info import ADMINS 7 | from info import INDEX_REQ_CHANNEL as LOG_CHANNEL 8 | from database.ia_filterdb import save_file 9 | from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton 10 | from utils import temp 11 | import re 12 | logger = logging.getLogger(__name__) 13 | logger.setLevel(logging.INFO) 14 | lock = asyncio.Lock() 15 | 16 | 17 | @Client.on_callback_query(filters.regex(r'^index')) 18 | async def index_files(bot, query): 19 | if query.data.startswith('index_cancel'): 20 | temp.CANCEL = True 21 | return await query.answer("Cancelling Indexing") 22 | _, raju, chat, lst_msg_id, from_user = query.data.split("#") 23 | if raju == 'reject': 24 | await query.message.delete() 25 | await bot.send_message(int(from_user), 26 | f'Your Submission for indexing {chat} has been decliened by our moderators.', 27 | reply_to_message_id=int(lst_msg_id)) 28 | return 29 | 30 | if lock.locked(): 31 | return await query.answer('Wait until previous process complete.', show_alert=True) 32 | msg = query.message 33 | 34 | await query.answer('Processing...⏳', show_alert=True) 35 | if int(from_user) not in ADMINS: 36 | await bot.send_message(int(from_user), 37 | f'Your Submission for indexing {chat} has been accepted by our moderators and will be added soon.', 38 | reply_to_message_id=int(lst_msg_id)) 39 | await msg.edit( 40 | "Starting Indexing", 41 | reply_markup=InlineKeyboardMarkup( 42 | [[InlineKeyboardButton('Cancel', callback_data='index_cancel')]] 43 | ) 44 | ) 45 | try: 46 | chat = int(chat) 47 | except: 48 | chat = chat 49 | await index_files_to_db(int(lst_msg_id), chat, msg, bot) 50 | 51 | 52 | @Client.on_message((filters.forwarded | (filters.regex("(https://)?(t\.me/|telegram\.me/|telegram\.dog/)(c/)?(\d+|[a-zA-Z_0-9]+)/(\d+)$")) & filters.text ) & filters.private & filters.incoming) 53 | async def send_for_index(bot, message): 54 | if message.text: 55 | regex = re.compile("(https://)?(t\.me/|telegram\.me/|telegram\.dog/)(c/)?(\d+|[a-zA-Z_0-9]+)/(\d+)$") 56 | match = regex.match(message.text) 57 | if not match: 58 | return await message.reply('Invalid link') 59 | chat_id = match.group(4) 60 | last_msg_id = int(match.group(5)) 61 | if chat_id.isnumeric(): 62 | chat_id = int(("-100" + chat_id)) 63 | elif message.forward_from_chat.type == enums.ChatType.CHANNEL: 64 | last_msg_id = message.forward_from_message_id 65 | chat_id = message.forward_from_chat.username or message.forward_from_chat.id 66 | else: 67 | return 68 | try: 69 | await bot.get_chat(chat_id) 70 | except ChannelInvalid: 71 | return await message.reply('This may be a private channel / group. Make me an admin over there to index the files.') 72 | except (UsernameInvalid, UsernameNotModified): 73 | return await message.reply('Invalid Link specified.') 74 | except Exception as e: 75 | logger.exception(e) 76 | return await message.reply(f'Errors - {e}') 77 | try: 78 | k = await bot.get_messages(chat_id, last_msg_id) 79 | except: 80 | return await message.reply('Make Sure That Iam An Admin In The Channel, if channel is private') 81 | if k.empty: 82 | return await message.reply('This may be group and iam not a admin of the group.') 83 | 84 | if message.from_user.id in ADMINS: 85 | buttons = [ 86 | [ 87 | InlineKeyboardButton('Yes', 88 | callback_data=f'index#accept#{chat_id}#{last_msg_id}#{message.from_user.id}') 89 | ], 90 | [ 91 | InlineKeyboardButton('close', callback_data='close_data'), 92 | ] 93 | ] 94 | reply_markup = InlineKeyboardMarkup(buttons) 95 | return await message.reply( 96 | f'Do you Want To Index This Channel/ Group ?\n\nChat ID/ Username: {chat_id}\nLast Message ID: {last_msg_id}', 97 | reply_markup=reply_markup) 98 | 99 | if type(chat_id) is int: 100 | try: 101 | link = (await bot.create_chat_invite_link(chat_id)).invite_link 102 | except ChatAdminRequired: 103 | return await message.reply('Make sure iam an admin in the chat and have permission to invite users.') 104 | else: 105 | link = f"@{message.forward_from_chat.username}" 106 | buttons = [ 107 | [ 108 | InlineKeyboardButton('Accept Index', 109 | callback_data=f'index#accept#{chat_id}#{last_msg_id}#{message.from_user.id}') 110 | ], 111 | [ 112 | InlineKeyboardButton('Reject Index', 113 | callback_data=f'index#reject#{chat_id}#{message.id}#{message.from_user.id}'), 114 | ] 115 | ] 116 | reply_markup = InlineKeyboardMarkup(buttons) 117 | await bot.send_message(LOG_CHANNEL, 118 | f'#IndexRequest\n\nBy : {message.from_user.mention} ({message.from_user.id})\nChat ID/ Username - {chat_id}\nLast Message ID - {last_msg_id}\nInviteLink - {link}', 119 | reply_markup=reply_markup) 120 | await message.reply('ThankYou For the Contribution, Wait For My Moderators to verify the files.') 121 | 122 | 123 | @Client.on_message(filters.command('setskip') & filters.user(ADMINS)) 124 | async def set_skip_number(bot, message): 125 | if ' ' in message.text: 126 | _, skip = message.text.split(" ") 127 | try: 128 | skip = int(skip) 129 | except: 130 | return await message.reply("Skip number should be an integer.") 131 | await message.reply(f"Successfully set SKIP number as {skip}") 132 | temp.CURRENT = int(skip) 133 | else: 134 | await message.reply("Give me a skip number") 135 | 136 | 137 | async def index_files_to_db(lst_msg_id, chat, msg, bot): 138 | total_files = 0 139 | duplicate = 0 140 | errors = 0 141 | deleted = 0 142 | no_media = 0 143 | unsupported = 0 144 | async with lock: 145 | try: 146 | current = temp.CURRENT 147 | temp.CANCEL = False 148 | async for message in bot.iter_messages(chat, lst_msg_id, temp.CURRENT): 149 | if temp.CANCEL: 150 | await msg.edit(f"Successfully Cancelled!!\n\nSaved {total_files} files to dataBase!\nDuplicate Files Skipped: {duplicate}\nDeleted Messages Skipped: {deleted}\nNon-Media messages skipped: {no_media + unsupported}(Unsupported Media - `{unsupported}` )\nErrors Occurred: {errors}") 151 | break 152 | current += 1 153 | if current % 20 == 0: 154 | can = [[InlineKeyboardButton('Cancel', callback_data='index_cancel')]] 155 | reply = InlineKeyboardMarkup(can) 156 | await msg.edit_text( 157 | text=f"Total messages fetched: {current}\nTotal messages saved: {total_files}\nDuplicate Files Skipped: {duplicate}\nDeleted Messages Skipped: {deleted}\nNon-Media messages skipped: {no_media + unsupported}(Unsupported Media - `{unsupported}` )\nErrors Occurred: {errors}", 158 | reply_markup=reply) 159 | if message.empty: 160 | deleted += 1 161 | continue 162 | elif not message.media: 163 | no_media += 1 164 | continue 165 | elif message.media not in [enums.MessageMediaType.VIDEO, enums.MessageMediaType.AUDIO, enums.MessageMediaType.DOCUMENT]: 166 | unsupported += 1 167 | continue 168 | media = getattr(message, message.media.value, None) 169 | if not media: 170 | unsupported += 1 171 | continue 172 | media.file_type = message.media.value 173 | media.caption = message.caption 174 | aynav, vnay = await save_file(media) 175 | if aynav: 176 | total_files += 1 177 | elif vnay == 0: 178 | duplicate += 1 179 | elif vnay == 2: 180 | errors += 1 181 | except Exception as e: 182 | logger.exception(e) 183 | await msg.edit(f'Error: {e}') 184 | else: 185 | await msg.edit(f'Succesfully saved {total_files} to dataBase!\nDuplicate Files Skipped: {duplicate}\nDeleted Messages Skipped: {deleted}\nNon-Media messages skipped: {no_media + unsupported}(Unsupported Media - `{unsupported}` )\nErrors Occurred: {errors}') 186 | -------------------------------------------------------------------------------- /plugins/inline.py: -------------------------------------------------------------------------------- 1 | import logging 2 | from pyrogram import Client, emoji, filters 3 | from pyrogram.errors.exceptions.bad_request_400 import QueryIdInvalid 4 | from pyrogram.types import InlineKeyboardButton, InlineKeyboardMarkup, InlineQueryResultCachedDocument, InlineQuery 5 | from database.ia_filterdb import get_search_results 6 | from utils import is_subscribed, get_size, temp 7 | from info import CACHE_TIME, AUTH_USERS, AUTH_CHANNEL, CUSTOM_FILE_CAPTION 8 | 9 | logger = logging.getLogger(__name__) 10 | cache_time = 0 if AUTH_USERS or AUTH_CHANNEL else CACHE_TIME 11 | 12 | async def inline_users(query: InlineQuery): 13 | if AUTH_USERS: 14 | if query.from_user and query.from_user.id in AUTH_USERS: 15 | return True 16 | else: 17 | return False 18 | if query.from_user and query.from_user.id not in temp.BANNED_USERS: 19 | return True 20 | return False 21 | 22 | @Client.on_inline_query() 23 | async def answer(bot, query): 24 | """Show search results for given inline query""" 25 | 26 | if not await inline_users(query): 27 | await query.answer(results=[], 28 | cache_time=0, 29 | switch_pm_text='okDa', 30 | switch_pm_parameter="hehe") 31 | return 32 | 33 | if AUTH_CHANNEL and not await is_subscribed(bot, query): 34 | await query.answer(results=[], 35 | cache_time=0, 36 | switch_pm_text='You have to subscribe my channel to use the bot', 37 | switch_pm_parameter="subscribe") 38 | return 39 | 40 | results = [] 41 | if '|' in query.query: 42 | string, file_type = query.query.split('|', maxsplit=1) 43 | string = string.strip() 44 | file_type = file_type.strip().lower() 45 | else: 46 | string = query.query.strip() 47 | file_type = None 48 | 49 | offset = int(query.offset or 0) 50 | reply_markup = get_reply_markup(query=string) 51 | files, next_offset, total = await get_search_results(string, 52 | file_type=file_type, 53 | max_results=10, 54 | offset=offset) 55 | 56 | for file in files: 57 | title=file.file_name 58 | size=get_size(file.file_size) 59 | f_caption=file.caption 60 | if CUSTOM_FILE_CAPTION: 61 | try: 62 | f_caption=CUSTOM_FILE_CAPTION.format(file_name= '' if title is None else title, file_size='' if size is None else size, file_caption='' if f_caption is None else f_caption) 63 | except Exception as e: 64 | logger.exception(e) 65 | f_caption=f_caption 66 | if f_caption is None: 67 | f_caption = f"{file.file_name}" 68 | results.append( 69 | InlineQueryResultCachedDocument( 70 | title=file.file_name, 71 | document_file_id=file.file_id, 72 | caption=f_caption, 73 | description=f'Size: {get_size(file.file_size)}\nType: {file.file_type}', 74 | reply_markup=reply_markup)) 75 | 76 | if results: 77 | switch_pm_text = f"{emoji.FILE_FOLDER} Results - {total}" 78 | if string: 79 | switch_pm_text += f" for {string}" 80 | try: 81 | await query.answer(results=results, 82 | is_personal = True, 83 | cache_time=cache_time, 84 | switch_pm_text=switch_pm_text, 85 | switch_pm_parameter="start", 86 | next_offset=str(next_offset)) 87 | except QueryIdInvalid: 88 | pass 89 | except Exception as e: 90 | logging.exception(str(e)) 91 | else: 92 | switch_pm_text = f'{emoji.CROSS_MARK} No results' 93 | if string: 94 | switch_pm_text += f' for "{string}"' 95 | 96 | await query.answer(results=[], 97 | is_personal = True, 98 | cache_time=cache_time, 99 | switch_pm_text=switch_pm_text, 100 | switch_pm_parameter="okay") 101 | 102 | 103 | def get_reply_markup(query): 104 | buttons = [ 105 | [ 106 | InlineKeyboardButton('Search again', switch_inline_query_current_chat=query) 107 | ] 108 | ] 109 | return InlineKeyboardMarkup(buttons) 110 | 111 | 112 | 113 | 114 | -------------------------------------------------------------------------------- /plugins/misc.py: -------------------------------------------------------------------------------- 1 | import os 2 | from pyrogram import Client, filters, enums 3 | from pyrogram.errors.exceptions.bad_request_400 import UserNotParticipant, MediaEmpty, PhotoInvalidDimensions, WebpageMediaEmpty 4 | from info import IMDB_TEMPLATE 5 | from utils import extract_user, get_file_id, get_poster, last_online 6 | import time 7 | from datetime import datetime 8 | from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton, CallbackQuery 9 | import logging 10 | logger = logging.getLogger(__name__) 11 | logger.setLevel(logging.ERROR) 12 | 13 | @Client.on_message(filters.command('id')) 14 | async def showid(client, message): 15 | chat_type = message.chat.type 16 | if chat_type == enums.ChatType.PRIVATE: 17 | user_id = message.chat.id 18 | first = message.from_user.first_name 19 | last = message.from_user.last_name or "" 20 | username = message.from_user.username 21 | dc_id = message.from_user.dc_id or "" 22 | await message.reply_text( 23 | f"➲ First Name: {first}\n➲ Last Name: {last}\n➲ Username: {username}\n➲ Telegram ID: {user_id}\n➲ Data Centre: {dc_id}", 24 | quote=True 25 | ) 26 | 27 | elif chat_type in [enums.ChatType.GROUP, enums.ChatType.SUPERGROUP]: 28 | _id = "" 29 | _id += ( 30 | "➲ Chat ID: " 31 | f"{message.chat.id}\n" 32 | ) 33 | if message.reply_to_message: 34 | _id += ( 35 | "➲ User ID: " 36 | f"{message.from_user.id if message.from_user else 'Anonymous'}\n" 37 | "➲ Replied User ID: " 38 | f"{message.reply_to_message.from_user.id if message.reply_to_message.from_user else 'Anonymous'}\n" 39 | ) 40 | file_info = get_file_id(message.reply_to_message) 41 | else: 42 | _id += ( 43 | "➲ User ID: " 44 | f"{message.from_user.id if message.from_user else 'Anonymous'}\n" 45 | ) 46 | file_info = get_file_id(message) 47 | if file_info: 48 | _id += ( 49 | f"{file_info.message_type}: " 50 | f"{file_info.file_id}\n" 51 | ) 52 | await message.reply_text( 53 | _id, 54 | quote=True 55 | ) 56 | 57 | @Client.on_message(filters.command(["info"])) 58 | async def who_is(client, message): 59 | # https://github.com/SpEcHiDe/PyroGramBot/blob/master/pyrobot/plugins/admemes/whois.py#L19 60 | status_message = await message.reply_text( 61 | "`𝚂𝙴𝙰𝚁𝙲𝙷𝙸𝙽𝙶 𝚄𝚂𝙴𝚁...`" 62 | ) 63 | await status_message.edit( 64 | "`𝙰𝙲𝙲𝙴𝚂𝚂𝙸𝙽𝙶 𝙸𝙽𝙵𝙾𝚁𝙼𝙰𝚃𝙸𝙾𝙽...`" 65 | ) 66 | from_user = None 67 | from_user_id, _ = extract_user(message) 68 | try: 69 | from_user = await client.get_users(from_user_id) 70 | except Exception as error: 71 | await status_message.edit(str(error)) 72 | return 73 | if from_user is None: 74 | return await status_message.edit("no valid user_id / message specified") 75 | message_out_str = "" 76 | message_out_str += f"➲First Name: {from_user.first_name}\n" 77 | last_name = from_user.last_name or "None" 78 | message_out_str += f"➲Last Name: {last_name}\n" 79 | message_out_str += f"➲Telegram ID: {from_user.id}\n" 80 | username = from_user.username or "None" 81 | dc_id = from_user.dc_id or "[User Doesn't Have A Valid DP]" 82 | message_out_str += f"➲Data Centre: {dc_id}\n" 83 | message_out_str += f"➲User Name: @{username}\n" 84 | message_out_str += f"➲User 𝖫𝗂𝗇𝗄: Click Here\n" 85 | if message.chat.type in ((enums.ChatType.SUPERGROUP, enums.ChatType.CHANNEL)): 86 | try: 87 | chat_member_p = await message.chat.get_member(from_user.id) 88 | joined_date = ( 89 | chat_member_p.joined_date or datetime.now() 90 | ).strftime("%Y.%m.%d %H:%M:%S") 91 | message_out_str += ( 92 | "➲Joined this Chat on: " 93 | f"{joined_date}" 94 | "\n" 95 | ) 96 | except UserNotParticipant: 97 | pass 98 | chat_photo = from_user.photo 99 | if chat_photo: 100 | local_user_photo = await client.download_media( 101 | message=chat_photo.big_file_id 102 | ) 103 | buttons = [[ 104 | InlineKeyboardButton('🔐 Close', callback_data='close_data') 105 | ]] 106 | reply_markup = InlineKeyboardMarkup(buttons) 107 | await message.reply_photo( 108 | photo=local_user_photo, 109 | quote=True, 110 | reply_markup=reply_markup, 111 | caption=message_out_str, 112 | parse_mode=enums.ParseMode.HTML, 113 | disable_notification=True 114 | ) 115 | os.remove(local_user_photo) 116 | else: 117 | buttons = [[ 118 | InlineKeyboardButton('🔐 Close', callback_data='close_data') 119 | ]] 120 | reply_markup = InlineKeyboardMarkup(buttons) 121 | await message.reply_text( 122 | text=message_out_str, 123 | reply_markup=reply_markup, 124 | quote=True, 125 | parse_mode=enums.ParseMode.HTML, 126 | disable_notification=True 127 | ) 128 | await status_message.delete() 129 | 130 | @Client.on_message(filters.command(["imdb", 'search'])) 131 | async def imdb_search(client, message): 132 | if ' ' in message.text: 133 | k = await message.reply('Searching ImDB') 134 | r, title = message.text.split(None, 1) 135 | movies = await get_poster(title, bulk=True) 136 | if not movies: 137 | return await message.reply("No results Found") 138 | btn = [ 139 | [ 140 | InlineKeyboardButton( 141 | text=f"{movie.get('title')} - {movie.get('year')}", 142 | callback_data=f"imdb#{movie.movieID}", 143 | ) 144 | ] 145 | for movie in movies 146 | ] 147 | await k.edit('Here is what i found on IMDb', reply_markup=InlineKeyboardMarkup(btn)) 148 | else: 149 | await message.reply('Give me a movie / series Name') 150 | 151 | @Client.on_callback_query(filters.regex('^imdb')) 152 | async def imdb_callback(bot: Client, quer_y: CallbackQuery): 153 | i, movie = quer_y.data.split('#') 154 | imdb = await get_poster(query=movie, id=True) 155 | btn = [ 156 | [ 157 | InlineKeyboardButton( 158 | text=f"{imdb.get('title')}", 159 | url=imdb['url'], 160 | ) 161 | ] 162 | ] 163 | message = quer_y.message.reply_to_message or quer_y.message 164 | if imdb: 165 | caption = IMDB_TEMPLATE.format( 166 | query = imdb['title'], 167 | title = imdb['title'], 168 | votes = imdb['votes'], 169 | aka = imdb["aka"], 170 | seasons = imdb["seasons"], 171 | box_office = imdb['box_office'], 172 | localized_title = imdb['localized_title'], 173 | kind = imdb['kind'], 174 | imdb_id = imdb["imdb_id"], 175 | cast = imdb["cast"], 176 | runtime = imdb["runtime"], 177 | countries = imdb["countries"], 178 | certificates = imdb["certificates"], 179 | languages = imdb["languages"], 180 | director = imdb["director"], 181 | writer = imdb["writer"], 182 | producer = imdb["producer"], 183 | composer = imdb["composer"], 184 | cinematographer = imdb["cinematographer"], 185 | music_team = imdb["music_team"], 186 | distributors = imdb["distributors"], 187 | release_date = imdb['release_date'], 188 | year = imdb['year'], 189 | genres = imdb['genres'], 190 | poster = imdb['poster'], 191 | plot = imdb['plot'], 192 | rating = imdb['rating'], 193 | url = imdb['url'], 194 | **locals() 195 | ) 196 | else: 197 | caption = "No Results" 198 | if imdb.get('poster'): 199 | try: 200 | await quer_y.message.reply_photo(photo=imdb['poster'], caption=caption, reply_markup=InlineKeyboardMarkup(btn)) 201 | except (MediaEmpty, PhotoInvalidDimensions, WebpageMediaEmpty): 202 | pic = imdb.get('poster') 203 | poster = pic.replace('.jpg', "._V1_UX360.jpg") 204 | await quer_y.message.reply_photo(photo=poster, caption=caption, reply_markup=InlineKeyboardMarkup(btn)) 205 | except Exception as e: 206 | logger.exception(e) 207 | await quer_y.message.reply(caption, reply_markup=InlineKeyboardMarkup(btn), disable_web_page_preview=False) 208 | await quer_y.message.delete() 209 | else: 210 | await quer_y.message.edit(caption, reply_markup=InlineKeyboardMarkup(btn), disable_web_page_preview=False) 211 | await quer_y.answer() 212 | 213 | 214 | 215 | -------------------------------------------------------------------------------- /plugins/p_ttishow.py: -------------------------------------------------------------------------------- 1 | from pyrogram import Client, filters, enums 2 | from pyrogram.types import InlineKeyboardButton, InlineKeyboardMarkup 3 | from pyrogram.errors.exceptions.bad_request_400 import MessageTooLong, PeerIdInvalid 4 | from info import ADMINS, LOG_CHANNEL, SUPPORT_CHAT, MELCOW_NEW_USERS 5 | from database.users_chats_db import db 6 | from database.ia_filterdb import Media 7 | from utils import get_size, temp, get_settings 8 | from Script import script 9 | from pyrogram.errors import ChatAdminRequired 10 | 11 | """-------------------------------------------------------------------------------""" 12 | 13 | @Client.on_message(filters.new_chat_members & filters.group) 14 | async def save_group(bot, message): 15 | r_j_check = [u.id for u in message.new_chat_members] 16 | if temp.ME in r_j_check: 17 | if not await db.get_chat(message.chat.id): 18 | total=await bot.get_chat_members_count(message.chat.id) 19 | r_j = message.from_user.mention if message.from_user else "Anonymous" 20 | await bot.send_message(LOG_CHANNEL, script.LOG_TEXT_G.format(message.chat.title, message.chat.id, total, r_j)) 21 | await db.add_chat(message.chat.id, message.chat.title) 22 | if message.chat.id in temp.BANNED_CHATS: 23 | # Inspired from a boat of a banana tree 24 | buttons = [[ 25 | InlineKeyboardButton('𝚂𝚄𝙿𝙿𝙾𝚁𝚃', url=f'https://t.me/{SUPPORT_CHAT}') 26 | ]] 27 | reply_markup=InlineKeyboardMarkup(buttons) 28 | k = await message.reply( 29 | text='CHAT NOT ALLOWED 🐞\n\n𝙼𝚈 𝙰𝙳𝙼𝙸𝙽𝚂 𝙷𝙰𝚂 𝚁𝙴𝚂𝚃𝚁𝙸𝙲𝚃𝙴𝙳 𝙼𝙴 𝙵𝚁𝙾𝙼 𝚆𝙾𝚁𝙺𝙸𝙽𝙶 𝙷𝙴𝚁𝙴 !𝙸𝙵 𝚈𝙾𝚄 𝚆𝙰𝙽𝚃 𝚃𝙾 𝙺𝙽𝙾𝚆 𝙼𝙾𝚁𝙴 𝙰𝙱𝙾𝚄𝚃 𝙸𝚃 𝙲𝙾𝙽𝚃𝙰𝙲𝚃 𝙾𝚆𝙽𝙴𝚁...', 30 | reply_markup=reply_markup, 31 | ) 32 | 33 | try: 34 | await k.pin() 35 | except: 36 | pass 37 | await bot.leave_chat(message.chat.id) 38 | return 39 | buttons = [[ 40 | InlineKeyboardButton('𝙷𝙾𝚆 𝚃𝙾 𝚄𝚂𝙴 𝙼𝙴', url=f"https://t.me/{temp.U_NAME}?start=help"), 41 | InlineKeyboardButton('📢 UPDATES 📢', url='https://t.me/LazyDeveloper') 42 | ]] 43 | reply_markup=InlineKeyboardMarkup(buttons) 44 | await message.reply_text( 45 | text=f"›› 𝚃𝙷𝙰𝙽𝙺𝚂 𝚃𝙾 𝙰𝙳𝙳 𝙼𝙴 𝚃𝙾 𝚈𝙾𝚄𝚁 𝙶𝚁𝙾𝚄𝙿. {message.chat.title} ❣️\n›› 𝙳𝙾𝙽'𝚃 𝙵𝙾𝚁𝙶𝙴𝚃 𝚃𝙾 𝙼𝙰𝙺𝙴 𝙼𝙴 𝙰𝙳𝙼𝙸𝙽.\n›› 𝙸f 𝙰𝙽𝚈 𝙳𝙾𝚄𝙱𝚃𝚂 𝙰𝙱𝙾𝚄𝚃 𝚄𝚂𝙸𝙽𝙶 𝙼𝙴 𝙲𝙻𝙸𝙲𝙺 𝙱𝙴𝙻𝙾𝚆 𝙱𝚄𝚃𝚃𝙾𝙽..⚡⚡.", 46 | reply_markup=reply_markup) 47 | else: 48 | settings = await get_settings(message.chat.id) 49 | if settings["welcome"]: 50 | for u in message.new_chat_members: 51 | if (temp.MELCOW).get('welcome') is not None: 52 | try: 53 | await (temp.MELCOW['welcome']).delete() 54 | except: 55 | pass 56 | temp.MELCOW['welcome'] = await message.reply_video( 57 | video="https://telegra.ph/file/03691465baa774e46506d.mp4", 58 | caption=f'ʜᴇʏ, {u.mention} 👋🏻\nᴡᴇʟᴄᴏᴍᴇ ᴛᴏ ᴏᴜʀ ɢʀᴏᴜᴘ {message.chat.title}\n\nFind Any Media ! if you need any movie then then enter the movie name + years. 👍\n\nGuys Enter Only movie Or Webseries Name like This 👇\nPushpa ✅\nPushpa 2021 ✅\nPushpa in Hindi ❌\nLucifer ✅\nLucifer S01 ✅\nLucifer all season ❌', 59 | reply_markup=InlineKeyboardMarkup( [ [ InlineKeyboardButton('🔥 ↭ Main Channel ↭ 🔥', url='http://t.me/real_MoviesAdda1') ], 60 | [ InlineKeyboardButton('🔥 ↭ DEV Channel ↭ 🔥', url='http://t.me/LazyDeveloper') ] 61 | ] ) 62 | ) 63 | 64 | @Client.on_message(filters.command('leave') & filters.user(ADMINS)) 65 | async def leave_a_chat(bot, message): 66 | if len(message.command) == 1: 67 | return await message.reply('Give me a chat id') 68 | chat = message.command[1] 69 | try: 70 | chat = int(chat) 71 | except: 72 | chat = chat 73 | try: 74 | buttons = [[ 75 | InlineKeyboardButton('𝚂𝚄𝙿𝙿𝙾𝚁𝚃', url=f'https://t.me/{SUPPORT_CHAT}') 76 | ]] 77 | reply_markup=InlineKeyboardMarkup(buttons) 78 | await bot.send_message( 79 | chat_id=chat, 80 | text='Hello Friends, \nMy admin has told me to leave from group so i go! If you wanna add me again contact my support group.', 81 | reply_markup=reply_markup, 82 | ) 83 | 84 | await bot.leave_chat(chat) 85 | await message.reply(f"left the chat `{chat}`") 86 | except Exception as e: 87 | await message.reply(f'Error - {e}') 88 | 89 | @Client.on_message(filters.command('disable') & filters.user(ADMINS)) 90 | async def disable_chat(bot, message): 91 | if len(message.command) == 1: 92 | return await message.reply('Give me a chat id') 93 | r = message.text.split(None) 94 | if len(r) > 2: 95 | reason = message.text.split(None, 2)[2] 96 | chat = message.text.split(None, 2)[1] 97 | else: 98 | chat = message.command[1] 99 | reason = "No reason Provided" 100 | try: 101 | chat_ = int(chat) 102 | except: 103 | return await message.reply('Give Me A Valid Chat ID') 104 | cha_t = await db.get_chat(int(chat_)) 105 | if not cha_t: 106 | return await message.reply("Chat Not Found In DB") 107 | if cha_t['is_disabled']: 108 | return await message.reply(f"This chat is already disabled:\nReason- {cha_t['reason']} ") 109 | await db.disable_chat(int(chat_), reason) 110 | temp.BANNED_CHATS.append(int(chat_)) 111 | await message.reply('Chat Successfully Disabled') 112 | try: 113 | buttons = [[ 114 | InlineKeyboardButton('𝚂𝚄𝙿𝙿𝙾𝚁𝚃', url=f'https://t.me/{SUPPORT_CHAT}') 115 | ]] 116 | reply_markup=InlineKeyboardMarkup(buttons) 117 | await bot.send_message( 118 | chat_id=chat_, 119 | text=f'Hello Friends, \nMy admin has told me to leave from group so i go! If you wanna add me again contact my support group. \nReason : {reason}', 120 | reply_markup=reply_markup) 121 | await bot.leave_chat(chat_) 122 | except Exception as e: 123 | await message.reply(f"Error - {e}") 124 | 125 | 126 | @Client.on_message(filters.command('enable') & filters.user(ADMINS)) 127 | async def re_enable_chat(bot, message): 128 | if len(message.command) == 1: 129 | return await message.reply('Give me a chat id') 130 | chat = message.command[1] 131 | try: 132 | chat_ = int(chat) 133 | except: 134 | return await message.reply('Give Me A Valid Chat ID') 135 | sts = await db.get_chat(int(chat)) 136 | if not sts: 137 | return await message.reply("Chat Not Found In DB !") 138 | if not sts.get('is_disabled'): 139 | return await message.reply('This chat is not yet disabled.') 140 | await db.re_enable_chat(int(chat_)) 141 | temp.BANNED_CHATS.remove(int(chat_)) 142 | await message.reply("Chat Successfully re-enabled") 143 | 144 | 145 | @Client.on_message(filters.command('stats') & filters.incoming) 146 | async def get_ststs(bot, message): 147 | rju = await message.reply('𝙰𝙲𝙲𝙴𝚂𝚂𝙸𝙽𝙶 𝚂𝚃𝙰𝚃𝚄𝚂 𝙳𝙴𝚃𝙰𝙸𝙻𝚂...') 148 | total_users = await db.total_users_count() 149 | totl_chats = await db.total_chat_count() 150 | files = await Media.count_documents() 151 | size = await db.get_db_size() 152 | free = 536870912 - size 153 | size = get_size(size) 154 | free = get_size(free) 155 | await rju.edit(script.STATUS_TXT.format(files, total_users, totl_chats, size, free)) 156 | 157 | 158 | # a function for trespassing into others groups, Inspired by a Vazha 159 | # Not to be used , But Just to showcase his vazhatharam. 160 | # @Client.on_message(filters.command('invite') & filters.user(ADMINS)) 161 | async def gen_invite(bot, message): 162 | if len(message.command) == 1: 163 | return await message.reply('Give me a chat id') 164 | chat = message.command[1] 165 | try: 166 | chat = int(chat) 167 | except: 168 | return await message.reply('Give Me A Valid Chat ID') 169 | try: 170 | link = await bot.create_chat_invite_link(chat) 171 | except ChatAdminRequired: 172 | return await message.reply("Invite Link Generation Failed, Iam Not Having Sufficient Rights") 173 | except Exception as e: 174 | return await message.reply(f'Error {e}') 175 | await message.reply(f'Here is your Invite Link {link.invite_link}') 176 | 177 | @Client.on_message(filters.command('ban') & filters.user(ADMINS)) 178 | async def ban_a_user(bot, message): 179 | # https://t.me/GetTGLink/4185 180 | if len(message.command) == 1: 181 | return await message.reply('Give me a user id / username') 182 | r = message.text.split(None) 183 | if len(r) > 2: 184 | reason = message.text.split(None, 2)[2] 185 | chat = message.text.split(None, 2)[1] 186 | else: 187 | chat = message.command[1] 188 | reason = "No reason Provided" 189 | try: 190 | chat = int(chat) 191 | except: 192 | pass 193 | try: 194 | k = await bot.get_users(chat) 195 | except PeerIdInvalid: 196 | return await message.reply("This is an invalid user, make sure ia have met him before.") 197 | except IndexError: 198 | return await message.reply("This might be a channel, make sure its a user.") 199 | except Exception as e: 200 | return await message.reply(f'Error - {e}') 201 | else: 202 | jar = await db.get_ban_status(k.id) 203 | if jar['is_banned']: 204 | return await message.reply(f"{k.mention} is already banned\nReason: {jar['ban_reason']}") 205 | await db.ban_user(k.id, reason) 206 | temp.BANNED_USERS.append(k.id) 207 | await message.reply(f"Successfully banned {k.mention}") 208 | 209 | 210 | 211 | @Client.on_message(filters.command('unban') & filters.user(ADMINS)) 212 | async def unban_a_user(bot, message): 213 | if len(message.command) == 1: 214 | return await message.reply('Give me a user id / username') 215 | r = message.text.split(None) 216 | if len(r) > 2: 217 | reason = message.text.split(None, 2)[2] 218 | chat = message.text.split(None, 2)[1] 219 | else: 220 | chat = message.command[1] 221 | reason = "No reason Provided" 222 | try: 223 | chat = int(chat) 224 | except: 225 | pass 226 | try: 227 | k = await bot.get_users(chat) 228 | except PeerIdInvalid: 229 | return await message.reply("This is an invalid user, make sure ia have met him before.") 230 | except IndexError: 231 | return await message.reply("Thismight be a channel, make sure its a user.") 232 | except Exception as e: 233 | return await message.reply(f'Error - {e}') 234 | else: 235 | jar = await db.get_ban_status(k.id) 236 | if not jar['is_banned']: 237 | return await message.reply(f"{k.mention} is not yet banned.") 238 | await db.remove_ban(k.id) 239 | temp.BANNED_USERS.remove(k.id) 240 | await message.reply(f"Successfully unbanned {k.mention}") 241 | 242 | 243 | 244 | @Client.on_message(filters.command('users') & filters.user(ADMINS)) 245 | async def list_users(bot, message): 246 | # https://t.me/GetTGLink/4184 247 | raju = await message.reply('Getting List Of Users') 248 | users = await db.get_all_users() 249 | out = "Users Saved In DB Are:\n\n" 250 | async for user in users: 251 | out += f"{user['name']}" 252 | if user['ban_status']['is_banned']: 253 | out += '( Banned User )' 254 | out += '\n' 255 | try: 256 | await raju.edit_text(out) 257 | except MessageTooLong: 258 | with open('users.txt', 'w+') as outfile: 259 | outfile.write(out) 260 | await message.reply_document('users.txt', caption="List Of Users") 261 | 262 | @Client.on_message(filters.command('chats') & filters.user(ADMINS)) 263 | async def list_chats(bot, message): 264 | raju = await message.reply('Getting List Of chats') 265 | chats = await db.get_all_chats() 266 | out = "Chats Saved In DB Are:\n\n" 267 | async for chat in chats: 268 | out += f"**Title:** `{chat['title']}`\n**- ID:** `{chat['id']}`" 269 | if chat['chat_status']['is_disabled']: 270 | out += '( Disabled Chat )' 271 | out += '\n' 272 | try: 273 | await raju.edit_text(out) 274 | except MessageTooLong: 275 | with open('chats.txt', 'w+') as outfile: 276 | outfile.write(out) 277 | await message.reply_document('chats.txt', caption="List Of Chats") 278 | -------------------------------------------------------------------------------- /plugins/pm_filter.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | import re 3 | import ast 4 | import math 5 | from utils import get_shortlink 6 | from pyrogram.errors.exceptions.bad_request_400 import MediaEmpty, PhotoInvalidDimensions, WebpageMediaEmpty 7 | from Script import script 8 | import pyrogram 9 | from database.connections_mdb import active_connection, all_connections, delete_connection, if_active, make_active, \ 10 | make_inactive 11 | from info import * 12 | from pyrogram.types import InlineKeyboardMarkup, InlineKeyboardButton, CallbackQuery 13 | from pyrogram import Client, filters, enums 14 | from pyrogram.errors import FloodWait, UserIsBlocked, MessageNotModified, PeerIdInvalid 15 | from utils import get_size, is_subscribed, get_poster, search_gagala, temp, get_settings, save_group_settings 16 | from database.users_chats_db import db 17 | from database.ia_filterdb import Media, get_file_details, get_search_results 18 | from database.filters_mdb import ( 19 | del_all, 20 | find_filter, 21 | get_filters, 22 | ) 23 | import logging 24 | 25 | logger = logging.getLogger(__name__) 26 | logger.setLevel(logging.ERROR) 27 | 28 | BUTTONS = {} 29 | SPELL_CHECK = {} 30 | FILTER_MODE = {} 31 | 32 | @Client.on_message(filters.command('autofilter')) 33 | async def fil_mod(client, message): 34 | mode_on = ["yes", "on", "true"] 35 | mode_of = ["no", "off", "false"] 36 | 37 | try: 38 | args = message.text.split(None, 1)[1].lower() 39 | except: 40 | return await message.reply("**𝙸𝙽𝙲𝙾𝙼𝙿𝙻𝙴𝚃𝙴 𝙲𝙾𝙼𝙼𝙰𝙽𝙳...**") 41 | 42 | m = await message.reply("**𝚂𝙴𝚃𝚃𝙸𝙽𝙶.../**") 43 | 44 | if args in mode_on: 45 | FILTER_MODE[str(message.chat.id)] = "True" 46 | await m.edit("**𝙰𝚄𝚃𝙾𝙵𝙸𝙻𝚃𝙴𝚁 𝙴𝙽𝙰𝙱𝙻𝙴𝙳**") 47 | 48 | elif args in mode_of: 49 | FILTER_MODE[str(message.chat.id)] = "False" 50 | await m.edit("**𝙰𝚄𝚃𝙾𝙵𝙸𝙻𝚃𝙴𝚁 𝙳𝙸𝚂𝙰𝙱𝙻𝙴𝙳**") 51 | else: 52 | await m.edit("USE :- /autofilter on 𝙾𝚁 /autofilter off") 53 | 54 | @Client.on_message((filters.group | filters.private) & filters.text & filters.incoming) 55 | async def give_filter(client, message): 56 | k = await manual_filters(client, message) 57 | if k == False: 58 | await auto_filter(client, message) 59 | 60 | 61 | @Client.on_callback_query(filters.regex(r"^next")) 62 | async def next_page(bot, query): 63 | ident, req, key, offset = query.data.split("_") 64 | if int(req) not in [query.from_user.id, 0]: 65 | return await query.answer("oKda", show_alert=True) 66 | try: 67 | offset = int(offset) 68 | except: 69 | offset = 0 70 | search = BUTTONS.get(key) 71 | if not search: 72 | await query.answer("You are using one of my old messages, please send the request again.", show_alert=True) 73 | return 74 | 75 | files, n_offset, total = await get_search_results(search, offset=offset, filter=True) 76 | try: 77 | n_offset = int(n_offset) 78 | except: 79 | n_offset = 0 80 | 81 | if not files: 82 | return 83 | settings = await get_settings(query.message.chat.id) 84 | if settings['button']: 85 | btn = [ 86 | [ 87 | InlineKeyboardButton( 88 | text=f"[{get_size(file.file_size)}] {file.file_name}", 89 | url=await get_shortlink(f"https://telegram.dog/{temp.U_NAME}?start=files_{file.file_id}") 90 | ), 91 | ] 92 | for file in files 93 | ] 94 | else: 95 | btn = [ 96 | [ 97 | InlineKeyboardButton( 98 | text=f"[{get_size(file.file_size)}] {file.file_name}", 99 | url=await get_shortlink(f"https://telegram.dog/{temp.U_NAME}?start=files_{file.file_id}") 100 | ), 101 | InlineKeyboardButton( 102 | text=f"[{get_size(file.file_size)}] {file.file_name}", 103 | url=await get_shortlink(f"https://telegram.dog/{temp.U_NAME}?start=files_{file.file_id}") 104 | ), 105 | ] 106 | for file in files 107 | ] 108 | 109 | btn.insert(0, 110 | [ 111 | InlineKeyboardButton(text="⚡ʜᴏᴡ ᴛᴏ ᴅᴏᴡɴʟᴏᴀᴅ⚡", url='https://telegram.me/LazyDeveloper') 112 | ] 113 | ) 114 | 115 | if 0 < offset <= 10: 116 | off_set = 0 117 | elif offset == 0: 118 | off_set = None 119 | else: 120 | off_set = offset - 10 121 | if n_offset == 0: 122 | btn.append( 123 | [InlineKeyboardButton("⏪ 𝗕𝗮𝗰𝗸", callback_data=f"next_{req}_{key}_{off_set}"), 124 | InlineKeyboardButton(f"📃 𝗣𝗮𝗴𝗲s {math.ceil(int(offset) / 10) + 1} / {math.ceil(total / 10)}", 125 | callback_data="pages")] 126 | ) 127 | elif off_set is None: 128 | btn.append( 129 | [InlineKeyboardButton(f"🗓 {math.ceil(int(offset) / 10) + 1} / {math.ceil(total / 10)}", callback_data="pages"), 130 | InlineKeyboardButton("𝗡𝗲𝘅𝘁 ➡️", callback_data=f"next_{req}_{key}_{n_offset}")]) 131 | else: 132 | btn.append( 133 | [ 134 | InlineKeyboardButton("⏪ 𝗕𝗮𝗰𝗸", callback_data=f"next_{req}_{key}_{off_set}"), 135 | InlineKeyboardButton(f"🗓 {math.ceil(int(offset) / 10) + 1} / {math.ceil(total / 10)}", callback_data="pages"), 136 | InlineKeyboardButton("𝗡𝗲𝘅𝘁 ➡️", callback_data=f"next_{req}_{key}_{n_offset}") 137 | ], 138 | ) 139 | try: 140 | await query.edit_message_reply_markup( 141 | reply_markup=InlineKeyboardMarkup(btn) 142 | ) 143 | except MessageNotModified: 144 | pass 145 | await query.answer() 146 | 147 | 148 | @Client.on_callback_query(filters.regex(r"^spolling")) 149 | async def advantage_spoll_choker(bot, query): 150 | _, user, movie_ = query.data.split('#') 151 | if int(user) != 0 and query.from_user.id != int(user): 152 | return await query.answer("😁 𝗛𝗲𝘆 𝗙𝗿𝗶𝗲𝗻𝗱,𝗣𝗹𝗲𝗮𝘀𝗲 𝗦𝗲𝗮𝗿𝗰𝗵 𝗬𝗼𝘂𝗿𝘀𝗲𝗹𝗳.", show_alert=True) 153 | if movie_ == "close_spellcheck": 154 | return await query.message.delete() 155 | movies = SPELL_CHECK.get(query.message.reply_to_message.id) 156 | if not movies: 157 | return await query.answer("𝐋𝐢𝐧𝐤 𝐄𝐱𝐩𝐢𝐫𝐞𝐝 𝐊𝐢𝐧𝐝𝐥𝐲 𝐏𝐥𝐞𝐚𝐬𝐞 𝐒𝐞𝐚𝐫𝐜𝐡 𝐀𝐠𝐚𝐢𝐧 🙂.", show_alert=True) 158 | movie = movies[(int(movie_))] 159 | await query.answer('𝙲𝙷𝙴𝙲𝙺𝙸𝙽𝙶 𝙵𝙸𝙻𝙴 𝙾𝙽 𝙼𝚈 𝙳𝙰𝚃𝙰𝙱𝙰𝚂𝙴...//') 160 | k = await manual_filters(bot, query.message, text=movie) 161 | if k == False: 162 | files, offset, total_results = await get_search_results(movie, offset=0, filter=True) 163 | if files: 164 | k = (movie, files, offset, total_results) 165 | await auto_filter(bot, query, k) 166 | else: 167 | k = await query.message.edit('𝚃𝙷𝙸𝚂 𝙼𝙾𝚅𝙸𝙴 I𝚂 𝙽𝙾𝚃 𝚈𝙴𝚃 𝚁𝙴𝙻𝙴𝙰𝚂𝙴𝙳 𝙾𝚁 𝙰𝙳𝙳𝙴𝙳 𝚃𝙾 𝙳𝙰𝚃𝚂𝙱𝙰𝚂𝙴 💌') 168 | await asyncio.sleep(10) 169 | await k.delete() 170 | 171 | 172 | @Client.on_callback_query() 173 | async def cb_handler(client: Client, query: CallbackQuery): 174 | if query.data == "close_data": 175 | await query.message.delete() 176 | elif query.data == "delallconfirm": 177 | userid = query.from_user.id 178 | chat_type = query.message.chat.type 179 | 180 | if chat_type == enums.ChatType.PRIVATE: 181 | grpid = await active_connection(str(userid)) 182 | if grpid is not None: 183 | grp_id = grpid 184 | try: 185 | chat = await client.get_chat(grpid) 186 | title = chat.title 187 | except: 188 | await query.message.edit_text("Make sure I'm present in your group!!", quote=True) 189 | return await query.answer('𝙿𝙻𝙴𝙰𝚂𝙴 𝚂𝙷𝙰𝚁𝙴 𝙰𝙽𝙳 𝚂𝚄𝙿𝙿𝙾𝚁𝚃') 190 | else: 191 | await query.message.edit_text( 192 | "I'm not connected to any groups!\nCheck /connections or connect to any groups", 193 | quote=True 194 | ) 195 | return await query.answer('𝙿𝙻𝙴𝙰𝚂𝙴 𝚂𝙷𝙰𝚁𝙴 𝙰𝙽𝙳 𝚂𝚄𝙿𝙿𝙾𝚁𝚃') 196 | 197 | elif chat_type in [enums.ChatType.GROUP, enums.ChatType.SUPERGROUP]: 198 | grp_id = query.message.chat.id 199 | title = query.message.chat.title 200 | 201 | else: 202 | return await query.answer('Piracy Is Crime') 203 | 204 | st = await client.get_chat_member(grp_id, userid) 205 | if (st.status == enums.ChatMemberStatus.OWNER) or (str(userid) in ADMINS): 206 | await del_all(query.message, grp_id, title) 207 | else: 208 | await query.answer("You need to be Group Owner or an Auth User to do that!", show_alert=True) 209 | elif query.data == "delallcancel": 210 | userid = query.from_user.id 211 | chat_type = query.message.chat.type 212 | 213 | if chat_type == enums.ChatType.PRIVATE: 214 | await query.message.reply_to_message.delete() 215 | await query.message.delete() 216 | 217 | elif chat_type in [enums.ChatType.GROUP, enums.ChatType.SUPERGROUP]: 218 | grp_id = query.message.chat.id 219 | st = await client.get_chat_member(grp_id, userid) 220 | if (st.status == enums.ChatMemberStatus.OWNER) or (str(userid) in ADMINS): 221 | await query.message.delete() 222 | try: 223 | await query.message.reply_to_message.delete() 224 | except: 225 | pass 226 | else: 227 | await query.answer("Buddy Don't Touch Others Property 😁", show_alert=True) 228 | elif "groupcb" in query.data: 229 | await query.answer() 230 | 231 | group_id = query.data.split(":")[1] 232 | 233 | act = query.data.split(":")[2] 234 | hr = await client.get_chat(int(group_id)) 235 | title = hr.title 236 | user_id = query.from_user.id 237 | 238 | if act == "": 239 | stat = "𝙲𝙾𝙽𝙽𝙴𝙲𝚃" 240 | cb = "connectcb" 241 | else: 242 | stat = "𝙳𝙸𝚂𝙲𝙾𝙽𝙽𝙴𝙲𝚃" 243 | cb = "disconnect" 244 | 245 | keyboard = InlineKeyboardMarkup([ 246 | [InlineKeyboardButton(f"{stat}", callback_data=f"{cb}:{group_id}"), 247 | InlineKeyboardButton("𝙳𝙴𝙻𝙴𝚃𝙴", callback_data=f"deletecb:{group_id}")], 248 | [InlineKeyboardButton("𝙱𝙰𝙲𝙺", callback_data="backcb")] 249 | ]) 250 | 251 | await query.message.edit_text( 252 | f"𝙶𝚁𝙾𝚄𝙿 𝙽𝙰𝙼𝙴 :- **{title}**\n𝙶𝚁𝙾𝚄𝙿 𝙸𝙳 :- `{group_id}`", 253 | reply_markup=keyboard, 254 | parse_mode=enums.ParseMode.MARKDOWN 255 | ) 256 | return await query.answer('Piracy Is Crime') 257 | elif "connectcb" in query.data: 258 | await query.answer() 259 | 260 | group_id = query.data.split(":")[1] 261 | 262 | hr = await client.get_chat(int(group_id)) 263 | 264 | title = hr.title 265 | 266 | user_id = query.from_user.id 267 | 268 | mkact = await make_active(str(user_id), str(group_id)) 269 | 270 | if mkact: 271 | await query.message.edit_text( 272 | f"𝙲𝙾𝙽𝙽𝙴𝙲𝚃𝙴𝙳 𝚃𝙾 **{title}**", 273 | parse_mode=enums.ParseMode.MARKDOWN 274 | ) 275 | else: 276 | await query.message.edit_text('Some error occurred!!', parse_mode=enums.ParseMode.MARKDOWN) 277 | return await query.answer('𝙿𝙻𝙴𝙰𝚂𝙴 𝚂𝙷𝙰𝚁𝙴 𝙰𝙽𝙳 𝚂𝚄𝙿𝙿𝙾𝚁𝚃') 278 | elif "disconnect" in query.data: 279 | await query.answer() 280 | 281 | group_id = query.data.split(":")[1] 282 | 283 | hr = await client.get_chat(int(group_id)) 284 | 285 | title = hr.title 286 | user_id = query.from_user.id 287 | 288 | mkinact = await make_inactive(str(user_id)) 289 | 290 | if mkinact: 291 | await query.message.edit_text( 292 | f"𝙳𝙸𝚂𝙲𝙾𝙽𝙽𝙴𝙲𝚃 FROM **{title}**", 293 | parse_mode=enums.ParseMode.MARKDOWN 294 | ) 295 | else: 296 | await query.message.edit_text( 297 | f"Some error occurred!!", 298 | parse_mode=enums.ParseMode.MARKDOWN 299 | ) 300 | return await query.answer('𝙿𝙻𝙴𝙰𝚂𝙴 𝚂𝙷𝙰𝚁𝙴 𝙰𝙽𝙳 𝚂𝚄𝙿𝙿𝙾𝚁𝚃') 301 | elif "deletecb" in query.data: 302 | await query.answer() 303 | 304 | user_id = query.from_user.id 305 | group_id = query.data.split(":")[1] 306 | 307 | delcon = await delete_connection(str(user_id), str(group_id)) 308 | 309 | if delcon: 310 | await query.message.edit_text( 311 | "Successfully deleted connection" 312 | ) 313 | else: 314 | await query.message.edit_text( 315 | f"Some error occurred!!", 316 | parse_mode=enums.ParseMode.MARKDOWN 317 | ) 318 | return await query.answer('𝙿𝙻𝙴𝙰𝚂𝙴 𝚂𝙷𝙰𝚁𝙴 𝙰𝙽𝙳 𝚂𝚄𝙿𝙿𝙾𝚁𝚃') 319 | elif query.data == "backcb": 320 | await query.answer() 321 | 322 | userid = query.from_user.id 323 | 324 | groupids = await all_connections(str(userid)) 325 | if groupids is None: 326 | await query.message.edit_text( 327 | "There are no active connections!! Connect to some groups first.", 328 | ) 329 | return await query.answer('𝙿𝙻𝙴𝙰𝚂𝙴 𝚂𝙷𝙰𝚁𝙴 𝙰𝙽𝙳 𝚂𝚄𝙿𝙿𝙾𝚁𝚃') 330 | buttons = [] 331 | for groupid in groupids: 332 | try: 333 | ttl = await client.get_chat(int(groupid)) 334 | title = ttl.title 335 | active = await if_active(str(userid), str(groupid)) 336 | act = " - ACTIVE" if active else "" 337 | buttons.append( 338 | [ 339 | InlineKeyboardButton( 340 | text=f"{title}{act}", callback_data=f"groupcb:{groupid}:{act}" 341 | ) 342 | ] 343 | ) 344 | except: 345 | pass 346 | if buttons: 347 | await query.message.edit_text( 348 | "Your connected group details ;\n\n", 349 | reply_markup=InlineKeyboardMarkup(buttons) 350 | ) 351 | elif "alertmessage" in query.data: 352 | grp_id = query.message.chat.id 353 | i = query.data.split(":")[1] 354 | keyword = query.data.split(":")[2] 355 | reply_text, btn, alerts, fileid = await find_filter(grp_id, keyword) 356 | if alerts is not None: 357 | alerts = ast.literal_eval(alerts) 358 | alert = alerts[int(i)] 359 | alert = alert.replace("\\n", "\n").replace("\\t", "\t") 360 | await query.answer(alert, show_alert=True) 361 | if query.data.startswith("file"): 362 | ident, file_id = query.data.split("#") 363 | files_ = await get_file_details(file_id) 364 | if not files_: 365 | return await query.answer('No such file exist.') 366 | files = files_[0] 367 | title = files.file_name 368 | size = get_size(files.file_size) 369 | f_caption = files.caption 370 | settings = await get_settings(query.message.chat.id) 371 | if CUSTOM_FILE_CAPTION: 372 | try: 373 | f_caption = CUSTOM_FILE_CAPTION.format(file_name='' if title is None else title, 374 | file_size='' if size is None else size, 375 | file_caption='' if f_caption is None else f_caption) 376 | except Exception as e: 377 | logger.exception(e) 378 | f_caption = f_caption 379 | if f_caption is None: 380 | f_caption = f"{files.file_name}" 381 | 382 | try: 383 | if AUTH_CHANNEL and not await is_subscribed(client, query): 384 | await query.answer(url=f"https://telegram.dog/{temp.U_NAME}?start={ident}_{file_id}") 385 | return 386 | elif settings['botpm']: 387 | await query.answer(url=f"https://telegram.dog/{temp.U_NAME}?start={ident}_{file_id}") 388 | return 389 | else: 390 | await client.send_cached_media( 391 | chat_id=query.from_user.id, 392 | file_id=file_id, 393 | caption=f_caption, 394 | protect_content=True if ident == "filep" else False 395 | ) 396 | await query.answer('Check PM, I have sent files in pm', show_alert=True) 397 | except UserIsBlocked: 398 | await query.answer('You Are Blocked to use me !', show_alert=True) 399 | except PeerIdInvalid: 400 | await query.answer(url=f"https://telegram.dog/{temp.U_NAME}?start={ident}_{file_id}") 401 | except Exception as e: 402 | await query.answer(url=f"https://telegram.dog/{temp.U_NAME}?start={ident}_{file_id}") 403 | elif query.data.startswith("checksub"): 404 | if AUTH_CHANNEL and not await is_subscribed(client, query): 405 | await query.answer("I Like Your Smartness, But Don't Be Oversmart Okay 😒", show_alert=True) 406 | return 407 | ident, file_id = query.data.split("#") 408 | files_ = await get_file_details(file_id) 409 | if not files_: 410 | return await query.answer('No such file exist.') 411 | files = files_[0] 412 | title = files.file_name 413 | size = get_size(files.file_size) 414 | f_caption = files.caption 415 | if CUSTOM_FILE_CAPTION: 416 | try: 417 | f_caption = CUSTOM_FILE_CAPTION.format(file_name='' if title is None else title, 418 | file_size='' if size is None else size, 419 | file_caption='' if f_caption is None else f_caption) 420 | except Exception as e: 421 | logger.exception(e) 422 | f_caption = f_caption 423 | if f_caption is None: 424 | f_caption = f"{title}" 425 | await query.answer() 426 | await client.send_cached_media( 427 | chat_id=query.from_user.id, 428 | file_id=file_id, 429 | caption=f_caption, 430 | protect_content=True if ident == 'checksubp' else False 431 | ) 432 | elif query.data == "pages": 433 | await query.answer() 434 | elif query.data == "start": 435 | buttons = [[ 436 | InlineKeyboardButton('➕↖️ Add Me To Your Groups ↗️➕', url=f'http://t.me/{temp.U_NAME}?startgroup=true') 437 | ],[ 438 | InlineKeyboardButton('⚡ Movie Updates ⚡', url=f"https://telegram.me/real_MoviesAdda1"), 439 | InlineKeyboardButton('🔔 BOT Updates 🤖', url='https://t.me/LazyDeveloper') 440 | ],[ 441 | InlineKeyboardButton('🙆🏻 Help 🦾', callback_data='help'), 442 | InlineKeyboardButton('♥️ About ♥️', callback_data='about') 443 | ]] 444 | reply_markup = InlineKeyboardMarkup(buttons) 445 | await query.message.edit_text( 446 | text=script.START_TXT.format(query.from_user.mention, temp.U_NAME, temp.B_NAME), 447 | reply_markup=reply_markup, 448 | parse_mode=enums.ParseMode.HTML 449 | ) 450 | await query.answer('𝙿𝙻𝙴𝙰𝚂𝙴 𝚂𝙷𝙰𝚁𝙴 𝙰𝙽𝙳 𝚂𝚄𝙿𝙿𝙾𝚁𝚃') 451 | elif query.data == "help": 452 | buttons = [[ 453 | InlineKeyboardButton('𝙼𝙰𝙽𝚄𝙴𝙻 𝙵𝙸𝙻𝚃𝙴𝚁', callback_data='manuelfilter'), 454 | InlineKeyboardButton('𝙰𝚄𝚃𝙾 𝙵𝙸𝙻𝚃𝙴𝚁', callback_data='autofilter') 455 | ], [ 456 | InlineKeyboardButton('𝙲𝙾𝙽𝙽𝙴𝙲𝚃𝙸𝙾𝙽𝚂', callback_data='coct'), 457 | InlineKeyboardButton('𝙴𝚇𝚃𝚁𝙰 𝙼𝙾D𝚂', callback_data='extra') 458 | ], [ 459 | InlineKeyboardButton('🏠 H𝙾𝙼𝙴 🏠', callback_data='start'), 460 | ]] 461 | reply_markup = InlineKeyboardMarkup(buttons) 462 | await query.message.edit_text( 463 | text=script.HELP_TXT.format(query.from_user.mention), 464 | reply_markup=reply_markup, 465 | parse_mode=enums.ParseMode.HTML 466 | ) 467 | elif query.data == "about": 468 | buttons = [[ 469 | InlineKeyboardButton('🏠 H𝙾𝙼𝙴 🏠', callback_data='start'), 470 | ]] 471 | reply_markup = InlineKeyboardMarkup(buttons) 472 | await query.message.edit_text( 473 | text=script.ABOUT_TXT.format(temp.B_NAME), 474 | reply_markup=reply_markup, 475 | parse_mode=enums.ParseMode.HTML 476 | ) 477 | elif query.data == "source": 478 | buttons = [[ 479 | InlineKeyboardButton('👩‍🦯 𝙱𝙰𝙲𝙺', callback_data='about') 480 | ]] 481 | reply_markup = InlineKeyboardMarkup(buttons) 482 | await query.message.edit_text( 483 | text=script.SOURCE_TXT, 484 | reply_markup=reply_markup, 485 | parse_mode=enums.ParseMode.HTML 486 | ) 487 | elif query.data == "manuelfilter": 488 | buttons = [[ 489 | InlineKeyboardButton('👩‍🦯 𝙱𝙰𝙲𝙺', callback_data='help'), 490 | InlineKeyboardButton('⏹️ 𝙱𝚄𝚃𝚃𝙾𝙽𝚂', callback_data='button') 491 | ]] 492 | reply_markup = InlineKeyboardMarkup(buttons) 493 | await query.message.edit_text( 494 | text=script.MANUELFILTER_TXT, 495 | reply_markup=reply_markup, 496 | parse_mode=enums.ParseMode.HTML 497 | ) 498 | elif query.data == "button": 499 | buttons = [[ 500 | InlineKeyboardButton('👩‍🦯 𝙱𝙰𝙲𝙺', callback_data='manuelfilter') 501 | ]] 502 | reply_markup = InlineKeyboardMarkup(buttons) 503 | await query.message.edit_text( 504 | text=script.BUTTON_TXT, 505 | reply_markup=reply_markup, 506 | parse_mode=enums.ParseMode.HTML 507 | ) 508 | elif query.data == "autofilter": 509 | buttons = [[ 510 | InlineKeyboardButton('👩‍🦯 𝙱𝙰𝙲𝙺', callback_data='help') 511 | ]] 512 | reply_markup = InlineKeyboardMarkup(buttons) 513 | await query.message.edit_text( 514 | text=script.AUTOFILTER_TXT, 515 | reply_markup=reply_markup, 516 | parse_mode=enums.ParseMode.HTML 517 | ) 518 | elif query.data == "coct": 519 | buttons = [[ 520 | InlineKeyboardButton('👩‍🦯 𝙱𝙰𝙲𝙺', callback_data='help') 521 | ]] 522 | reply_markup = InlineKeyboardMarkup(buttons) 523 | await query.message.edit_text( 524 | text=script.CONNECTION_TXT, 525 | reply_markup=reply_markup, 526 | parse_mode=enums.ParseMode.HTML 527 | ) 528 | elif query.data == "extra": 529 | buttons = [[ 530 | InlineKeyboardButton('👩‍🦯 𝙱𝙰𝙲𝙺', callback_data='help'), 531 | InlineKeyboardButton('👮‍♂️ 𝙰𝙳𝙼𝙸𝙽', callback_data='admin') 532 | ]] 533 | reply_markup = InlineKeyboardMarkup(buttons) 534 | await query.message.edit_text( 535 | text=script.EXTRAMOD_TXT, 536 | reply_markup=reply_markup, 537 | parse_mode=enums.ParseMode.HTML 538 | ) 539 | elif query.data == "admin": 540 | buttons = [[ 541 | InlineKeyboardButton('👩‍🦯 𝙱𝙰𝙲𝙺', callback_data='extra') 542 | ]] 543 | reply_markup = InlineKeyboardMarkup(buttons) 544 | await query.message.edit_text( 545 | text=script.ADMIN_TXT, 546 | reply_markup=reply_markup, 547 | parse_mode=enums.ParseMode.HTML 548 | ) 549 | elif query.data == "stats": 550 | buttons = [[ 551 | InlineKeyboardButton('👩‍🦯 𝙱𝙰𝙲𝙺', callback_data='help'), 552 | InlineKeyboardButton('♻️ 𝚁𝙴𝙵𝚁𝙴𝚂𝙷', callback_data='rfrsh') 553 | ]] 554 | reply_markup = InlineKeyboardMarkup(buttons) 555 | total = await Media.count_documents() 556 | users = await db.total_users_count() 557 | chats = await db.total_chat_count() 558 | monsize = await db.get_db_size() 559 | free = 536870912 - monsize 560 | monsize = get_size(monsize) 561 | free = get_size(free) 562 | await query.message.edit_text( 563 | text=script.STATUS_TXT.format(total, users, chats, monsize, free), 564 | reply_markup=reply_markup, 565 | parse_mode=enums.ParseMode.HTML 566 | ) 567 | elif query.data == "rfrsh": 568 | await query.answer("Fetching MongoDb DataBase") 569 | buttons = [[ 570 | InlineKeyboardButton('👩‍🦯 𝙱𝙰𝙲𝙺', callback_data='help'), 571 | InlineKeyboardButton('♻️ 𝚁𝙴𝙵𝚁𝙴𝚂𝙷', callback_data='rfrsh') 572 | ]] 573 | reply_markup = InlineKeyboardMarkup(buttons) 574 | total = await Media.count_documents() 575 | users = await db.total_users_count() 576 | chats = await db.total_chat_count() 577 | monsize = await db.get_db_size() 578 | free = 536870912 - monsize 579 | monsize = get_size(monsize) 580 | free = get_size(free) 581 | await query.message.edit_text( 582 | text=script.STATUS_TXT.format(total, users, chats, monsize, free), 583 | reply_markup=reply_markup, 584 | parse_mode=enums.ParseMode.HTML 585 | ) 586 | elif query.data.startswith("setgs"): 587 | ident, set_type, status, grp_id = query.data.split("#") 588 | grpid = await active_connection(str(query.from_user.id)) 589 | 590 | if str(grp_id) != str(grpid): 591 | await query.message.edit("Your Active Connection Has Been Changed. Go To /settings.") 592 | return await query.answer('𝙿𝙻𝙴𝙰𝚂𝙴 𝚂𝙷𝙰𝚁𝙴 𝙰𝙽𝙳 𝚂𝚄𝙿𝙿𝙾𝚁𝚃') 593 | 594 | if status == "True": 595 | await save_group_settings(grpid, set_type, False) 596 | else: 597 | await save_group_settings(grpid, set_type, True) 598 | 599 | settings = await get_settings(grpid) 600 | 601 | if settings is not None: 602 | buttons = [ 603 | [ 604 | InlineKeyboardButton('𝐅𝐈𝐋𝐓𝐄𝐑 𝐁𝐔𝐓𝐓𝐎𝐍', 605 | callback_data=f'setgs#button#{settings["button"]}#{str(grp_id)}'), 606 | InlineKeyboardButton('𝐒𝐈𝐍𝐆𝐋𝐄' if settings["button"] else '𝐃𝐎𝐔𝐁𝐋𝐄', 607 | callback_data=f'setgs#button#{settings["button"]}#{str(grp_id)}') 608 | ], 609 | [ 610 | InlineKeyboardButton('𝐁𝐎𝐓 𝐏𝐌', callback_data=f'setgs#botpm#{settings["botpm"]}#{str(grp_id)}'), 611 | InlineKeyboardButton('✅ 𝐘𝐄𝐒' if settings["botpm"] else '❌ 𝐍𝐎', 612 | callback_data=f'setgs#botpm#{settings["botpm"]}#{str(grp_id)}') 613 | ], 614 | [ 615 | InlineKeyboardButton('𝐅𝐈𝐋𝐄 𝐒𝐄𝐂𝐔𝐑𝐄', 616 | callback_data=f'setgs#file_secure#{settings["file_secure"]}#{str(grp_id)}'), 617 | InlineKeyboardButton('✅ 𝐘𝐄𝐒' if settings["file_secure"] else '❌ 𝐍𝐎', 618 | callback_data=f'setgs#file_secure#{settings["file_secure"]}#{str(grp_id)}') 619 | ], 620 | [ 621 | InlineKeyboardButton('𝐈𝐌𝐃𝐁', callback_data=f'setgs#imdb#{settings["imdb"]}#{str(grp_id)}'), 622 | InlineKeyboardButton('✅ 𝐘𝐄𝐒' if settings["imdb"] else '❌ 𝐍𝐎', 623 | callback_data=f'setgs#imdb#{settings["imdb"]}#{str(grp_id)}') 624 | ], 625 | [ 626 | InlineKeyboardButton('𝐒𝐏𝐄𝐋𝐋 𝐂𝐇𝐄𝐂𝐊', 627 | callback_data=f'setgs#spell_check#{settings["spell_check"]}#{str(grp_id)}'), 628 | InlineKeyboardButton('✅ 𝐘𝐄𝐒' if settings["spell_check"] else '❌ 𝐍𝐎', 629 | callback_data=f'setgs#spell_check#{settings["spell_check"]}#{str(grp_id)}') 630 | ], 631 | [ 632 | InlineKeyboardButton('𝐖𝐄𝐋𝐂𝐎𝐌𝐄', callback_data=f'setgs#welcome#{settings["welcome"]}#{str(grp_id)}'), 633 | InlineKeyboardButton('✅ 𝐘𝐄𝐒' if settings["welcome"] else '❌ 𝐍𝐎', 634 | callback_data=f'setgs#welcome#{settings["welcome"]}#{str(grp_id)}') 635 | ] 636 | ] 637 | reply_markup = InlineKeyboardMarkup(buttons) 638 | await query.message.edit_reply_markup(reply_markup) 639 | await query.answer('𝙿𝙻𝙴𝙰𝚂𝙴 𝚂𝙷𝙰𝚁𝙴 𝙰𝙽𝙳 𝚂𝚄𝙿𝙿𝙾𝚁𝚃') 640 | 641 | 642 | async def auto_filter(client, msg, spoll=False): 643 | if not spoll: 644 | message = msg 645 | settings = await get_settings(message.chat.id) 646 | if message.text.startswith("/"): return # ignore commands 647 | if re.findall("((^\/|^,|^!|^\.|^[\U0001F600-\U000E007F]).*)", message.text): 648 | return 649 | if 2 < len(message.text) < 100: 650 | search = message.text 651 | files, offset, total_results = await get_search_results(search.lower(), offset=0, filter=True) 652 | if not files: 653 | if settings["spell_check"]: 654 | return await advantage_spell_chok(msg) 655 | else: 656 | return 657 | else: 658 | return 659 | else: 660 | settings = await get_settings(msg.message.chat.id) 661 | message = msg.message.reply_to_message # msg will be callback query 662 | search, files, offset, total_results = spoll 663 | pre = 'filep' if settings['file_secure'] else 'file' 664 | if settings["button"]: 665 | btn = [ 666 | [ 667 | InlineKeyboardButton( 668 | text=f"[{get_size(file.file_size)}] {file.file_name}", 669 | url=await get_shortlink(f"https://telegram.dog/{temp.U_NAME}?start=files_{file.file_id}") 670 | ), 671 | ] 672 | for file in files 673 | ] 674 | else: 675 | btn = [ 676 | [ 677 | InlineKeyboardButton( 678 | text=f"[{get_size(file.file_size)}] {file.file_name}", 679 | url=await get_shortlink(f"https://telegram.dog/{temp.U_NAME}?start=files_{file.file_id}") 680 | ), 681 | InlineKeyboardButton( 682 | text=f"[{get_size(file.file_size)}] {file.file_name}", 683 | url=await get_shortlink(f"https://telegram.dog/{temp.U_NAME}?start=files_{file.file_id}") 684 | ), 685 | ] 686 | for file in files 687 | ] 688 | 689 | btn.insert(0, 690 | [ 691 | InlineKeyboardButton(text="⚡ʜᴏᴡ ᴛᴏ ᴅᴏᴡɴʟᴏᴀᴅ⚡", url='https://telegram.me/LazyDeveloper') 692 | ] 693 | ) 694 | 695 | if offset != "": 696 | key = f"{message.chat.id}-{message.id}" 697 | BUTTONS[key] = search 698 | req = message.from_user.id if message.from_user else 0 699 | btn.append( 700 | [InlineKeyboardButton(text=f"🗓 1/{math.ceil(int(total_results) / 10)}", callback_data="pages"), 701 | InlineKeyboardButton(text="𝗡𝗲𝘅𝘁 ⏩", callback_data=f"next_{req}_{key}_{offset}")] 702 | ) 703 | else: 704 | btn.append( 705 | [InlineKeyboardButton(text="🗓 1/1", callback_data="pages")] 706 | ) 707 | imdb = await get_poster(search, file=(files[0]).file_name) if settings["imdb"] else None 708 | TEMPLATE = settings['template'] 709 | if imdb: 710 | cap = TEMPLATE.format( 711 | query=search, 712 | title=imdb['title'], 713 | votes=imdb['votes'], 714 | aka=imdb["aka"], 715 | seasons=imdb["seasons"], 716 | box_office=imdb['box_office'], 717 | localized_title=imdb['localized_title'], 718 | kind=imdb['kind'], 719 | imdb_id=imdb["imdb_id"], 720 | cast=imdb["cast"], 721 | runtime=imdb["runtime"], 722 | countries=imdb["countries"], 723 | certificates=imdb["certificates"], 724 | languages=imdb["languages"], 725 | director=imdb["director"], 726 | writer=imdb["writer"], 727 | producer=imdb["producer"], 728 | composer=imdb["composer"], 729 | cinematographer=imdb["cinematographer"], 730 | music_team=imdb["music_team"], 731 | distributors=imdb["distributors"], 732 | release_date=imdb['release_date'], 733 | year=imdb['year'], 734 | genres=imdb['genres'], 735 | poster=imdb['poster'], 736 | plot=imdb['plot'], 737 | rating=imdb['rating'], 738 | url=imdb['url'], 739 | **locals() 740 | ) 741 | else: 742 | cap = f"Rᴇǫᴜᴇsᴛᴇᴅ ᴍᴏᴠɪᴇ ɴᴀᴍᴇ : {search}\n\n\n😌 ɪꜰ ᴛʜᴇ ᴍᴏᴠɪᴇ ʏᴏᴜ ᴀʀᴇ ʟᴏᴏᴋɪɴɢ ꜰᴏʀ ɪs ɴᴏᴛ ᴀᴠᴀɪʟᴀʙʟᴇ ᴛʜᴇɴ ʟᴇᴀᴠᴇ ᴀ ᴍᴇssᴀɢᴇ ʙᴇʟᴏᴡ 😌 \n\nᴇxᴀᴍᴘʟᴇ : \n\nᴇɴᴛᴇʀ ʏᴏᴜʀ ᴍᴏᴠɪᴇ ɴᴀᴍᴇ (ʏᴇᴀʀ) ᴛᴀɢ @admin" 743 | if imdb and imdb.get('poster'): 744 | try: 745 | hehe = await message.reply_photo(photo=imdb.get('poster'), caption=cap[:1024], 746 | reply_markup=InlineKeyboardMarkup(btn)) 747 | if SELF_DELETE: 748 | await asyncio.sleep(SELF_DELETE_SECONDS) 749 | await hehe.delete() 750 | 751 | except (MediaEmpty, PhotoInvalidDimensions, WebpageMediaEmpty): 752 | pic = imdb.get('poster') 753 | poster = pic.replace('.jpg', "._V1_UX360.jpg") 754 | hmm = await message.reply_photo(photo=poster, caption=cap[:1024], reply_markup=InlineKeyboardMarkup(btn)) 755 | if SELF_DELETE: 756 | await asyncio.sleep(SELF_DELETE_SECONDS) 757 | await hmm.delete() 758 | except Exception as e: 759 | logger.exception(e) 760 | fek = await message.reply_text(cap, reply_markup=InlineKeyboardMarkup(btn)) 761 | if SELF_DELETE: 762 | await asyncio.sleep(SELF_DELETE_SECONDS) 763 | await fek.delete() 764 | else: 765 | fuk = await message.reply_text(cap, reply_markup=InlineKeyboardMarkup(btn)) 766 | if SELF_DELETE: 767 | await asyncio.sleep(SELF_DELETE_SECONDS) 768 | await fuk.delete() 769 | 770 | async def advantage_spell_chok(msg): 771 | query = re.sub( 772 | r"\b(pl(i|e)*?(s|z+|ease|se|ese|(e+)s(e)?)|((send|snd|giv(e)?|gib)(\sme)?)|movie(s)?|new|latest|br((o|u)h?)*|^h(e|a)?(l)*(o)*|mal(ayalam)?|t(h)?amil|file|that|find|und(o)*|kit(t(i|y)?)?o(w)?|thar(u)?(o)*w?|kittum(o)*|aya(k)*(um(o)*)?|full\smovie|any(one)|with\ssubtitle(s)?)", 773 | "", msg.text, flags=re.IGNORECASE) # plis contribute some common words 774 | query = query.strip() + " movie" 775 | g_s = await search_gagala(query) 776 | g_s += await search_gagala(msg.text) 777 | gs_parsed = [] 778 | if not g_s: 779 | k = await msg.reply("I couldn't find any movie in that name.") 780 | await asyncio.sleep(8) 781 | await k.delete() 782 | return 783 | regex = re.compile(r".*(imdb|wikipedia).*", re.IGNORECASE) # look for imdb / wiki results 784 | gs = list(filter(regex.match, g_s)) 785 | gs_parsed = [re.sub( 786 | r'\b(\-([a-zA-Z-\s])\-\simdb|(\-\s)?imdb|(\-\s)?wikipedia|\(|\)|\-|reviews|full|all|episode(s)?|film|movie|series)', 787 | '', i, flags=re.IGNORECASE) for i in gs] 788 | if not gs_parsed: 789 | reg = re.compile(r"watch(\s[a-zA-Z0-9_\s\-\(\)]*)*\|.*", 790 | re.IGNORECASE) # match something like Watch Niram | Amazon Prime 791 | for mv in g_s: 792 | match = reg.match(mv) 793 | if match: 794 | gs_parsed.append(match.group(1)) 795 | user = msg.from_user.id if msg.from_user else 0 796 | movielist = [] 797 | gs_parsed = list(dict.fromkeys(gs_parsed)) # removing duplicates https://stackoverflow.com/a/7961425 798 | if len(gs_parsed) > 3: 799 | gs_parsed = gs_parsed[:3] 800 | if gs_parsed: 801 | for mov in gs_parsed: 802 | imdb_s = await get_poster(mov.strip(), bulk=True) # searching each keyword in imdb 803 | if imdb_s: 804 | movielist += [movie.get('title') for movie in imdb_s] 805 | movielist += [(re.sub(r'(\-|\(|\)|_)', '', i, flags=re.IGNORECASE)).strip() for i in gs_parsed] 806 | movielist = list(dict.fromkeys(movielist)) # removing duplicates 807 | if not movielist: 808 | k = await msg.reply("I couldn't find anything related to that. Check your spelling") 809 | await asyncio.sleep(8) 810 | await k.delete() 811 | return 812 | SPELL_CHECK[msg.id] = movielist 813 | btn = [[ 814 | InlineKeyboardButton( 815 | text=movie.strip(), 816 | callback_data=f"spolling#{user}#{k}", 817 | ) 818 | ] for k, movie in enumerate(movielist)] 819 | btn.append([InlineKeyboardButton(text="Close", callback_data=f'spolling#{user}#close_spellcheck')]) 820 | await msg.reply("I couldn't find anything related to that\nDid you mean any one of these?", 821 | reply_markup=InlineKeyboardMarkup(btn)) 822 | 823 | 824 | async def manual_filters(client, message, text=False): 825 | group_id = message.chat.id 826 | name = text or message.text 827 | reply_id = message.reply_to_message.id if message.reply_to_message else message.id 828 | keywords = await get_filters(group_id) 829 | for keyword in reversed(sorted(keywords, key=len)): 830 | pattern = r"( |^|[^\w])" + re.escape(keyword) + r"( |$|[^\w])" 831 | if re.search(pattern, name, flags=re.IGNORECASE): 832 | reply_text, btn, alert, fileid = await find_filter(group_id, keyword) 833 | 834 | if reply_text: 835 | reply_text = reply_text.replace("\\n", "\n").replace("\\t", "\t") 836 | 837 | if btn is not None: 838 | try: 839 | if fileid == "None": 840 | if btn == "[]": 841 | await client.send_message( 842 | group_id, 843 | reply_text, 844 | disable_web_page_preview=True, 845 | reply_to_message_id=reply_id) 846 | else: 847 | button = eval(btn) 848 | await client.send_message( 849 | group_id, 850 | reply_text, 851 | disable_web_page_preview=True, 852 | reply_markup=InlineKeyboardMarkup(button), 853 | reply_to_message_id=reply_id 854 | ) 855 | elif btn == "[]": 856 | await client.send_cached_media( 857 | group_id, 858 | fileid, 859 | caption=reply_text or "", 860 | reply_to_message_id=reply_id 861 | ) 862 | else: 863 | button = eval(btn) 864 | await message.reply_cached_media( 865 | fileid, 866 | caption=reply_text or "", 867 | reply_markup=InlineKeyboardMarkup(button), 868 | reply_to_message_id=reply_id 869 | ) 870 | except Exception as e: 871 | logger.exception(e) 872 | break 873 | else: 874 | return False 875 | 876 | -------------------------------------------------------------------------------- /plugins/route.py: -------------------------------------------------------------------------------- 1 | #rymme 2 | 3 | 4 | 5 | 6 | 7 | 8 | from aiohttp import web 9 | 10 | routes = web.RouteTableDef() 11 | 12 | @routes.get("/", allow_head=True) 13 | async def root_route_handler(request): 14 | return web.json_response("BOT IS RUNNING -Telegram@LazyDeveloper") 15 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | git+https://github.com/Joelkb/cinemagoer 2 | pyrogram>=2.0.30 3 | tgcrypto 4 | pymongo[srv]==3.12.3 5 | motor==2.5.1 6 | marshmallow==3.14.1 7 | umongo==3.0.1 8 | requests 9 | bs4 10 | heroku3 11 | pynewtonmath 12 | pytz 13 | aiohttp 14 | -------------------------------------------------------------------------------- /runtime.txt: -------------------------------------------------------------------------------- 1 | python-3.10.8 2 | -------------------------------------------------------------------------------- /start.sh: -------------------------------------------------------------------------------- 1 | if [ -z $UPSTREAM_REPO ] 2 | then 3 | echo "Cloning main Repository" 4 | git clone https://github.com/LazyDeveloperr/LazyPrincessV2 /LazyPrincessV2 5 | else 6 | echo "Cloning Custom Repo from $UPSTREAM_REPO " 7 | git clone $UPSTREAM_REPO /LazyPrincessV2 8 | fi 9 | cd /LazyPrincessV2 10 | pip3 install -U -r requirements.txt 11 | echo "Starting Bot...." 12 | python3 bot.py 13 | -------------------------------------------------------------------------------- /utils.py: -------------------------------------------------------------------------------- 1 | import logging 2 | from pyrogram.errors import InputUserDeactivated, UserNotParticipant, FloodWait, UserIsBlocked, PeerIdInvalid 3 | from info import * 4 | from imdb import Cinemagoer 5 | import asyncio 6 | from pyrogram.types import Message, InlineKeyboardButton 7 | from pyrogram import enums 8 | from typing import Union 9 | import re 10 | import os 11 | from datetime import datetime 12 | from typing import List 13 | from database.users_chats_db import db 14 | from bs4 import BeautifulSoup 15 | import requests 16 | import aiohttp 17 | 18 | logger = logging.getLogger(__name__) 19 | logger.setLevel(logging.INFO) 20 | 21 | BTN_URL_REGEX = re.compile( 22 | r"(\[([^\[]+?)\]\((buttonurl|buttonalert):(?:/{0,2})(.+?)(:same)?\))" 23 | ) 24 | 25 | imdb = Cinemagoer() 26 | 27 | BANNED = {} 28 | SMART_OPEN = '“' 29 | SMART_CLOSE = '”' 30 | START_CHAR = ('\'', '"', SMART_OPEN) 31 | 32 | # temp db for banned 33 | class temp(object): 34 | BANNED_USERS = [] 35 | BANNED_CHATS = [] 36 | ME = None 37 | CURRENT=int(os.environ.get("SKIP", 2)) 38 | CANCEL = False 39 | MELCOW = {} 40 | U_NAME = None 41 | B_NAME = None 42 | SETTINGS = {} 43 | 44 | async def is_subscribed(bot, query): 45 | try: 46 | user = await bot.get_chat_member(AUTH_CHANNEL, query.from_user.id) 47 | except UserNotParticipant: 48 | pass 49 | except Exception as e: 50 | logger.exception(e) 51 | else: 52 | if user.status != 'kicked': 53 | return True 54 | 55 | return False 56 | 57 | async def get_poster(query, bulk=False, id=False, file=None): 58 | if not id: 59 | # https://t.me/GetTGLink/4183 60 | query = (query.strip()).lower() 61 | title = query 62 | year = re.findall(r'[1-2]\d{3}$', query, re.IGNORECASE) 63 | if year: 64 | year = list_to_str(year[:1]) 65 | title = (query.replace(year, "")).strip() 66 | elif file is not None: 67 | year = re.findall(r'[1-2]\d{3}', file, re.IGNORECASE) 68 | if year: 69 | year = list_to_str(year[:1]) 70 | else: 71 | year = None 72 | movieid = imdb.search_movie(title.lower(), results=10) 73 | if not movieid: 74 | return None 75 | if year: 76 | filtered=list(filter(lambda k: str(k.get('year')) == str(year), movieid)) 77 | if not filtered: 78 | filtered = movieid 79 | else: 80 | filtered = movieid 81 | movieid=list(filter(lambda k: k.get('kind') in ['movie', 'tv series'], filtered)) 82 | if not movieid: 83 | movieid = filtered 84 | if bulk: 85 | return movieid 86 | movieid = movieid[0].movieID 87 | else: 88 | movieid = query 89 | movie = imdb.get_movie(movieid) 90 | if movie.get("original air date"): 91 | date = movie["original air date"] 92 | elif movie.get("year"): 93 | date = movie.get("year") 94 | else: 95 | date = "N/A" 96 | plot = "" 97 | if not LONG_IMDB_DESCRIPTION: 98 | plot = movie.get('plot') 99 | if plot and len(plot) > 0: 100 | plot = plot[0] 101 | else: 102 | plot = movie.get('plot outline') 103 | if plot and len(plot) > 800: 104 | plot = plot[0:800] + "..." 105 | 106 | return { 107 | 'title': movie.get('title'), 108 | 'votes': movie.get('votes'), 109 | "aka": list_to_str(movie.get("akas")), 110 | "seasons": movie.get("number of seasons"), 111 | "box_office": movie.get('box office'), 112 | 'localized_title': movie.get('localized title'), 113 | 'kind': movie.get("kind"), 114 | "imdb_id": f"tt{movie.get('imdbID')}", 115 | "cast": list_to_str(movie.get("cast")), 116 | "runtime": list_to_str(movie.get("runtimes")), 117 | "countries": list_to_str(movie.get("countries")), 118 | "certificates": list_to_str(movie.get("certificates")), 119 | "languages": list_to_str(movie.get("languages")), 120 | "director": list_to_str(movie.get("director")), 121 | "writer":list_to_str(movie.get("writer")), 122 | "producer":list_to_str(movie.get("producer")), 123 | "composer":list_to_str(movie.get("composer")) , 124 | "cinematographer":list_to_str(movie.get("cinematographer")), 125 | "music_team": list_to_str(movie.get("music department")), 126 | "distributors": list_to_str(movie.get("distributors")), 127 | 'release_date': date, 128 | 'year': movie.get('year'), 129 | 'genres': list_to_str(movie.get("genres")), 130 | 'poster': movie.get('full-size cover url'), 131 | 'plot': plot, 132 | 'rating': str(movie.get("rating")), 133 | 'url':f'https://www.imdb.com/title/tt{movieid}' 134 | } 135 | # https://github.com/odysseusmax/animated-lamp/blob/2ef4730eb2b5f0596ed6d03e7b05243d93e3415b/bot/utils/broadcast.py#L37 136 | 137 | async def broadcast_messages(user_id, message): 138 | try: 139 | await message.copy(chat_id=user_id) 140 | return True, "Success" 141 | except FloodWait as e: 142 | await asyncio.sleep(e.x) 143 | return await broadcast_messages(user_id, message) 144 | except InputUserDeactivated: 145 | await db.delete_user(int(user_id)) 146 | logging.info(f"{user_id}-Removed from Database, since deleted account.") 147 | return False, "Deleted" 148 | except UserIsBlocked: 149 | logging.info(f"{user_id} -Blocked the bot.") 150 | return False, "Blocked" 151 | except PeerIdInvalid: 152 | await db.delete_user(int(user_id)) 153 | logging.info(f"{user_id} - PeerIdInvalid") 154 | return False, "Error" 155 | except Exception as e: 156 | return False, "Error" 157 | 158 | async def search_gagala(text): 159 | usr_agent = { 160 | 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) ' 161 | 'Chrome/61.0.3163.100 Safari/537.36' 162 | } 163 | text = text.replace(" ", '+') 164 | url = f'https://www.google.com/search?q={text}' 165 | response = requests.get(url, headers=usr_agent) 166 | response.raise_for_status() 167 | soup = BeautifulSoup(response.text, 'html.parser') 168 | titles = soup.find_all( 'h3' ) 169 | return [title.getText() for title in titles] 170 | 171 | 172 | async def get_settings(group_id): 173 | settings = temp.SETTINGS.get(group_id) 174 | if not settings: 175 | settings = await db.get_settings(group_id) 176 | temp.SETTINGS[group_id] = settings 177 | return settings 178 | 179 | async def save_group_settings(group_id, key, value): 180 | current = await get_settings(group_id) 181 | current[key] = value 182 | temp.SETTINGS[group_id] = current 183 | await db.update_settings(group_id, current) 184 | 185 | def get_size(size): 186 | """Get size in readable format""" 187 | 188 | units = ["Bytes", "KB", "MB", "GB", "TB", "PB", "EB"] 189 | size = float(size) 190 | i = 0 191 | while size >= 1024.0 and i < len(units): 192 | i += 1 193 | size /= 1024.0 194 | return "%.2f %s" % (size, units[i]) 195 | 196 | def split_list(l, n): 197 | for i in range(0, len(l), n): 198 | yield l[i:i + n] 199 | 200 | def get_file_id(msg: Message): 201 | if msg.media: 202 | for message_type in ( 203 | "photo", 204 | "animation", 205 | "audio", 206 | "document", 207 | "video", 208 | "video_note", 209 | "voice", 210 | "sticker" 211 | ): 212 | obj = getattr(msg, message_type) 213 | if obj: 214 | setattr(obj, "message_type", message_type) 215 | return obj 216 | 217 | def extract_user(message: Message) -> Union[int, str]: 218 | """extracts the user from a message""" 219 | # https://github.com/SpEcHiDe/PyroGramBot/blob/f30e2cca12002121bad1982f68cd0ff9814ce027/pyrobot/helper_functions/extract_user.py#L7 220 | user_id = None 221 | user_first_name = None 222 | if message.reply_to_message: 223 | user_id = message.reply_to_message.from_user.id 224 | user_first_name = message.reply_to_message.from_user.first_name 225 | 226 | elif len(message.command) > 1: 227 | if ( 228 | len(message.entities) > 1 and 229 | message.entities[1].type == enums.MessageEntityType.TEXT_MENTION 230 | ): 231 | 232 | required_entity = message.entities[1] 233 | user_id = required_entity.user.id 234 | user_first_name = required_entity.user.first_name 235 | else: 236 | user_id = message.command[1] 237 | # don't want to make a request -_- 238 | user_first_name = user_id 239 | try: 240 | user_id = int(user_id) 241 | except ValueError: 242 | pass 243 | else: 244 | user_id = message.from_user.id 245 | user_first_name = message.from_user.first_name 246 | return (user_id, user_first_name) 247 | 248 | def list_to_str(k): 249 | if not k: 250 | return "N/A" 251 | elif len(k) == 1: 252 | return str(k[0]) 253 | elif MAX_LIST_ELM: 254 | k = k[:int(MAX_LIST_ELM)] 255 | return ' '.join(f'{elem}, ' for elem in k) 256 | else: 257 | return ' '.join(f'{elem}, ' for elem in k) 258 | 259 | def last_online(from_user): 260 | time = "" 261 | if from_user.is_bot: 262 | time += "🤖 Bot :(" 263 | elif from_user.status == enums.UserStatus.RECENTLY: 264 | time += "Recently" 265 | elif from_user.status == enums.UserStatus.LAST_WEEK: 266 | time += "Within the last week" 267 | elif from_user.status == enums.UserStatus.LAST_MONTH: 268 | time += "Within the last month" 269 | elif from_user.status == enums.UserStatus.LONG_AGO: 270 | time += "A long time ago :(" 271 | elif from_user.status == enums.UserStatus.ONLINE: 272 | time += "Currently Online" 273 | elif from_user.status == enums.UserStatus.OFFLINE: 274 | time += from_user.last_online_date.strftime("%a, %d %b %Y, %H:%M:%S") 275 | return time 276 | 277 | 278 | def split_quotes(text: str) -> List: 279 | if not any(text.startswith(char) for char in START_CHAR): 280 | return text.split(None, 1) 281 | counter = 1 # ignore first char -> is some kind of quote 282 | while counter < len(text): 283 | if text[counter] == "\\": 284 | counter += 1 285 | elif text[counter] == text[0] or (text[0] == SMART_OPEN and text[counter] == SMART_CLOSE): 286 | break 287 | counter += 1 288 | else: 289 | return text.split(None, 1) 290 | 291 | # 1 to avoid starting quote, and counter is exclusive so avoids ending 292 | key = remove_escapes(text[1:counter].strip()) 293 | # index will be in range, or `else` would have been executed and returned 294 | rest = text[counter + 1:].strip() 295 | if not key: 296 | key = text[0] + text[0] 297 | return list(filter(None, [key, rest])) 298 | 299 | def parser(text, keyword): 300 | if "buttonalert" in text: 301 | text = (text.replace("\n", "\\n").replace("\t", "\\t")) 302 | buttons = [] 303 | note_data = "" 304 | prev = 0 305 | i = 0 306 | alerts = [] 307 | for match in BTN_URL_REGEX.finditer(text): 308 | # Check if btnurl is escaped 309 | n_escapes = 0 310 | to_check = match.start(1) - 1 311 | while to_check > 0 and text[to_check] == "\\": 312 | n_escapes += 1 313 | to_check -= 1 314 | 315 | # if even, not escaped -> create button 316 | if n_escapes % 2 == 0: 317 | note_data += text[prev:match.start(1)] 318 | prev = match.end(1) 319 | if match.group(3) == "buttonalert": 320 | # create a thruple with button label, url, and newline status 321 | if bool(match.group(5)) and buttons: 322 | buttons[-1].append(InlineKeyboardButton( 323 | text=match.group(2), 324 | callback_data=f"alertmessage:{i}:{keyword}" 325 | )) 326 | else: 327 | buttons.append([InlineKeyboardButton( 328 | text=match.group(2), 329 | callback_data=f"alertmessage:{i}:{keyword}" 330 | )]) 331 | i += 1 332 | alerts.append(match.group(4)) 333 | elif bool(match.group(5)) and buttons: 334 | buttons[-1].append(InlineKeyboardButton( 335 | text=match.group(2), 336 | url=match.group(4).replace(" ", "") 337 | )) 338 | else: 339 | buttons.append([InlineKeyboardButton( 340 | text=match.group(2), 341 | url=match.group(4).replace(" ", "") 342 | )]) 343 | 344 | else: 345 | note_data += text[prev:to_check] 346 | prev = match.start(1) - 1 347 | else: 348 | note_data += text[prev:] 349 | 350 | try: 351 | return note_data, buttons, alerts 352 | except: 353 | return note_data, buttons, None 354 | 355 | def remove_escapes(text: str) -> str: 356 | res = "" 357 | is_escaped = False 358 | for counter in range(len(text)): 359 | if is_escaped: 360 | res += text[counter] 361 | is_escaped = False 362 | elif text[counter] == "\\": 363 | is_escaped = True 364 | else: 365 | res += text[counter] 366 | return res 367 | 368 | 369 | def humanbytes(size): 370 | if not size: 371 | return "" 372 | power = 2**10 373 | n = 0 374 | Dic_powerN = {0: ' ', 1: 'Ki', 2: 'Mi', 3: 'Gi', 4: 'Ti'} 375 | while size > power: 376 | size /= power 377 | n += 1 378 | return str(round(size, 2)) + " " + Dic_powerN[n] + 'B' 379 | 380 | async def get_shortlink(link): 381 | https = link.split(":")[0] 382 | if "http" == https: 383 | https = "https" 384 | link = link.replace("http", https) 385 | 386 | url = f'https://api.shareus.in/shortLink' 387 | params = {'token': URL_SHORTNER_WEBSITE_API, 388 | 'link': link, 389 | 'format': 'json' 390 | } 391 | 392 | try: 393 | async with aiohttp.ClientSession() as session: 394 | async with session.get(url, params=params, raise_for_status=True, ssl=False) as response: 395 | data = await response.json(content_type='text/html') 396 | if data["status"] == "success": 397 | return data['shortlink'] 398 | else: 399 | logger.error(f"Error: {data['message']}") 400 | return f'https://api.shareus.in/directLink?token={URL_SHORTNER_WEBSITE_API}&link={link}' 401 | 402 | except Exception as e: 403 | logger.error(e) 404 | return f'https://api.shareus.in/directLink?token={URL_SHORTNER_WEBSITE_API}&link={link}' 405 | --------------------------------------------------------------------------------