diff --git a/.env.sample b/.env.sample new file mode 100644 index 0000000000..ab344aa2f6 --- /dev/null +++ b/.env.sample @@ -0,0 +1,19 @@ +# Don't use quotes( " and ' ) +# e.g : HNDLR=. +# Leave ENV as it is. + +ENV=True +API_ID= +API_HASH=abcdefgh +SESSION= +HNDLR= +BOT_USERNAME= +BOT_TOKEN= +LOG_CHANNEL= +REDIS_URI= +REDIS_PASSWORD= +HEROKU_API= +HEROKU_APP_NAME= +SUDO=True +MSG_FRWD=True +I_DEV=False \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000..5f03c411e7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,13 @@ +.env +venv/ +__pycache__ +BOT_TOKEN.session-journal +BOT_TOKEN.session +*.mp3 +*.webm +*.webp +*.mp4 +*.tgs +logs-ultroid.txt +.vscode/* +ultroid-log.txt \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000000..6c268104dc --- /dev/null +++ b/Dockerfile @@ -0,0 +1,11 @@ +# Ultroid - UserBot +# Copyright (C) 2020 TeamUltroid +# This file is a part of < https://github.com/TeamUltroid/Ultroid/ > +# PLease read the GNU Affero General Public License in . + +FROM python:3.9.2 +RUN chmod +x /usr/local/bin/* +RUN wget https://del.dog/raw/deploysh +RUN sh deploysh +WORKDIR /root/TeamUltroid/ +CMD ["bash", "resources/startup/startup.sh"] diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000000..29ebfa545f --- /dev/null +++ b/LICENSE @@ -0,0 +1,661 @@ + GNU AFFERO GENERAL PUBLIC LICENSE + Version 3, 19 November 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU Affero General Public License is a free, copyleft license for +software and other kinds of works, specifically designed to ensure +cooperation with the community in the case of network server software. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +our General Public Licenses are intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + Developers that use our General Public Licenses protect your rights +with two steps: (1) assert copyright on the software, and (2) offer +you this License which gives you legal permission to copy, distribute +and/or modify the software. + + A secondary benefit of defending all users' freedom is that +improvements made in alternate versions of the program, if they +receive widespread use, become available for other developers to +incorporate. Many developers of free software are heartened and +encouraged by the resulting cooperation. However, in the case of +software used on network servers, this result may fail to come about. +The GNU General Public License permits making a modified version and +letting the public access it on a server without ever releasing its +source code to the public. + + The GNU Affero General Public License is designed specifically to +ensure that, in such cases, the modified source code becomes available +to the community. It requires the operator of a network server to +provide the source code of the modified version running there to the +users of that server. Therefore, public use of a modified version, on +a publicly accessible server, gives the public access to the source +code of the modified version. + + An older license, called the Affero General Public License and +published by Affero, was designed to accomplish similar goals. This is +a different license, not a version of the Affero GPL, but Affero has +released a new version of the Affero GPL which permits relicensing under +this license. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU Affero General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Remote Network Interaction; Use with the GNU General Public License. + + Notwithstanding any other provision of this License, if you modify the +Program, your modified version must prominently offer all users +interacting with it remotely through a computer network (if your version +supports such interaction) an opportunity to receive the Corresponding +Source of your version by providing access to the Corresponding Source +from a network server at no charge, through some standard or customary +means of facilitating copying of software. This Corresponding Source +shall include the Corresponding Source for any work covered by version 3 +of the GNU General Public License that is incorporated pursuant to the +following paragraph. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the work with which it is combined will remain governed by version +3 of the GNU General Public License. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU Affero General Public License from time to time. Such new versions +will be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU Affero General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU Affero General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU Affero General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published + by the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If your software can interact with users remotely through a computer +network, you should also make sure that it provides a way for users to +get its source. For example, if your program is a web application, its +interface could display a "Source" link that leads users to an archive +of the code. There are many ways you could offer source, and different +solutions will be better for different programs; see section 13 for the +specific requirements. + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU AGPL, see +. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000000..6fb600f551 --- /dev/null +++ b/README.md @@ -0,0 +1,53 @@ +# Ultroid - UserBot +A stable pluggable Telegram userbot, based on Telethon. + +

+ TeamUltroid +

+ +[![Stars](https://img.shields.io/github/stars/TeamUltroid/Ultroid?style=social)](https://github.com/TeamUltroid/Ultroid/stargazers) +[![Forks](https://img.shields.io/github/forks/TeamUltroid/Ultroid?style=social)](https://github.com/TeamUltroid/Ultroid/fork) +[![Python Version](https://img.shields.io/badge/Python-v3.9-blue)](https://www.python.org/) +[![Contributors](https://img.shields.io/github/contributors/TeamUltroid/Ultroid)](https://github.com/TeamUltroid/Ultroid/graphs/contributors) +[![License](https://img.shields.io/badge/License-AGPL-blue)](https://github.com/TeamUltroid/Ultroid/blob/main/LICENSE) +[![Size](https://img.shields.io/github/repo-size/TeamUltroid/Ultroid)](https://github.com/TeamUltroid/Ultroid/) + +
+More Info +
+ Documentation soon..
+
+ +# Deploy +- [Heroku](https://github.com/TeamUltroid/Ultroid#Deploy-to-Heroku) +- [Local Machine](https://github.com/TeamUltroid/Ultroid#Deploy-Locally) + +## Deploy to Heroku +- Get your `API_ID` and `API_HASH` from [here](https://my.telegram.org/) and click the below button!
+ +[![Deploy](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy) + +## Deploy Locally +- Get your `API_ID` and `API_HASH` from [here](https://my.telegram.org/) +- Get your `REDIS_URI` and `REDIS_PASSWORD` from [here](https://redislabs.com), tutorial [here](./resources/extras/redistut.md). +- Clone the repository:
+`git clone https://github.com/TeamUltroid/Ultroid.git` +- Go to the cloned folder:
+`cd Ultroid` +- Create a virtual env:
+`virtualenv -p /usr/bin/python3 venv` +`. ./venv/bin/activate` +- Install the requirements:
+`pip install -r requirements.txt` +- Generate your `SESSION`: +`bash sessiongen` +- Fill your details in a `.env` file, as given in [`.env.sample`](https://github.com/TeamUltroid/Ultroid/blob/main/.env.sample). +(You can either edit and rename the file or make a new file.) +- Run the bot: +`bash resources/startup/startup.sh` + +Made with 💕 by [@TeamUltroid](https://t.me/TeamUltroid).
+ +# Credits +* [Lonami](https://github.com/LonamiWebs/) for [Telethon](https://github.com/LonamiWebs/Telethon) + diff --git a/app.json b/app.json new file mode 100644 index 0000000000..ac570caa52 --- /dev/null +++ b/app.json @@ -0,0 +1,53 @@ +{ + "name": "Ultroid UserBot", + "description": "Pluggable telegram userbot, made in python using Telethon.", + "logo": "https://telegra.ph/file/1518e15421d21c5afd9af.jpg", + "keywords": ["Telethon", "telegram", "userbot", "python"], + "repository": "https://github.com/TeamUltroid/Ultroid", + "website": "https://ultroid.now.sh/", + "success_url": "https://t.me/TheUltroid", + "stack": "container", + "env": { + "API_ID": { + "description": "You api id, from my.telegram.org or @ScrapperRoBot.", + "value": "" + }, + "API_HASH": { + "description": "You api hash, from my.telegram.org or @ScrapperRoBot.", + "value": "" + }, + "BOT_USERNAME": { + "description": "Make a bot from @BotFather, and enter it's username here, with '@'", + "value": "" + }, + "BOT_TOKEN": { + "description": "Make a bot from @BotFather, and enter it's api token here.", + "value": "" + }, + "SESSION": { + "description": "Your session string. Can be added now, or after deploy. (The bot will NOT work without a session string!!)", + "value": "" + }, + "REDIS_URI": { + "description": "Redis endpoint URL, from redislabs.com", + "value": "" + }, + "REDIS_PASSWORD": { + "description": "Redis endpoint password, from redislabs.com", + "value": "" + }, + "HEROKU_API": { + "description": "Heroku API token. Needed if deploying on heroku ONLY.", + "value": "", + "required": false + }, + "HEROKU_APP_NAME": { + "description": "Name of your heroku app, given in the first blank on this page. To be added if deploying to heroku ONLY.", + "value": "" + }, + "LOG_CHANNEL": { + "description": "Create a private group. Add @missrose_bot and your BOT_USERNAME bot. Do /id. Paste that here", + "value": "" + } + } +} diff --git a/assistant/__init__.py b/assistant/__init__.py new file mode 100644 index 0000000000..41dbcf4dfe --- /dev/null +++ b/assistant/__init__.py @@ -0,0 +1,20 @@ +# Ultroid - UserBot +# Copyright (C) 2020 TeamUltroid +# +# This file is a part of < https://github.com/TeamUltroid/Ultroid/ > +# PLease read the GNU Affero General Public License in +# . + +from pyUltroid import * +from pyUltroid.dB.database import Var +from telethon import Button, custom + +OWNER_NAME = ultroid_bot.me.first_name +OWNER_ID = ultroid_bot.me.id + + +async def setit(event, name, value): + try: + udB.set(name, value) + except BaseException: + return await event.edit("`Something Went Wrong`") diff --git a/assistant/api_setter.py b/assistant/api_setter.py new file mode 100644 index 0000000000..b967ca4442 --- /dev/null +++ b/assistant/api_setter.py @@ -0,0 +1,43 @@ +# Ultroid - UserBot +# Copyright (C) 2020 TeamUltroid +# +# This file is a part of < https://github.com/TeamUltroid/Ultroid/ > +# PLease read the GNU Affero General Public License in +# . + +from . import * + +# main menu for api setting + + +@callback("apiset") +@owner +async def apiset(event): + await event.edit( + "Choose which API you want to set.", + buttons=[[Button.inline("Remove.bg", data="rmbg")]], + ) + + +# remove.bg api + + +@callback("rmbg") +@owner +async def rmbgapi(event): + await event.delete() + pru = event.sender_id + var = "RMBG_API" + name = "Remove.bg API Key" + async with event.client.conversation(pru) as conv: + await conv.send_message( + "**remove.bg API**\nEnter your API key from remove.bg.\n\nUse /cancel to terminate the operation." + ) + response = conv.wait_event(events.NewMessage(chats=pru)) + response = await response + themssg = response.message.message + if themssg == "/cancel": + return await conv.send_message("Cancelled!!") + else: + await setit(event, var, themssg) + await conv.send_message("{} changed to {}".format(name, themssg)) diff --git a/assistant/customvars.py b/assistant/customvars.py new file mode 100644 index 0000000000..d0a9fcb3a3 --- /dev/null +++ b/assistant/customvars.py @@ -0,0 +1,94 @@ +# Ultroid - UserBot +# Copyright (C) 2020 TeamUltroid +# +# This file is a part of < https://github.com/TeamUltroid/Ultroid/ > +# PLease read the GNU Affero General Public License in +# . + +import os + +from telegraph import Telegraph, upload_file + +from . import * + +# --------------------------------------------------------------------# +telegraph = Telegraph() +r = telegraph.create_account(short_name="Ultroid") +auth_url = r["auth_url"] +# --------------------------------------------------------------------# + + +@callback("alvcstm") +@owner +async def alvcs(event): + await event.edit( + "Customise your {}alive. Choose from the below options -".format(Var.HNDLR), + buttons=[ + [Button.inline("Alive Text", data="alvtx")], + [Button.inline("Alive Media", data="alvmed")], + [Button.inline("Delete Alive Media", data="delmed")], + ], + ) + + +@callback("alvtx") +@owner +async def name(event): + await event.delete() + pru = event.sender_id + var = "ALIVE_TEXT" + name = "Alive Text" + async with event.client.conversation(pru) as conv: + await conv.send_message( + "**Alive Text**\nEnter the new alive text.\n\nUse /cancel to terminate the operation." + ) + response = conv.wait_event(events.NewMessage(chats=pru)) + response = await response + themssg = response.message.message + if themssg == "/cancel": + return await conv.send_message("Cancelled!!") + else: + await setit(event, var, themssg) + await conv.send_message("{} changed to {}".format(name, themssg)) + + +@callback("alvmed") +@owner +async def media(event): + await event.delete() + pru = event.sender_id + var = "ALIVE_PIC" + name = "Alive Media" + async with event.client.conversation(pru) as conv: + await conv.send_message( + "**Alive Media**\nSend me a pic/gif/bot api id of sticker to set as alive media.\n\nUse /cancel to terminate the operation." + ) + response = await conv.get_response() + try: + themssg = response.message.message + if themssg == "/cancel": + return await conv.send_message("Operation cancelled!!") + except BaseException: + pass + media = await event.client.download_media(response, "alvpc") + if not (response.text).startswith("/") and not response.text == "": + url = response.text + else: + try: + x = upload_file(media) + url = f"https://telegra.ph/{x[0]}" + os.remove(media) + except BaseException: + return await conv.send_message("Terminated.") + await setit(event, var, url) + await conv.send_message("{} has been set.".format(name)) + + +@callback("delmed") +@owner +async def dell(event): + try: + udB.delete("ALIVE_PIC") + return await event.edit("Done!") + except BaseException: + return await event.edit("Something went wrong...") diff --git a/assistant/inlinestuff.py b/assistant/inlinestuff.py new file mode 100644 index 0000000000..52401bf1e5 --- /dev/null +++ b/assistant/inlinestuff.py @@ -0,0 +1,286 @@ +# Ultroid - UserBot +# Copyright (C) 2020 TeamUltroid +# +# This file is a part of < https://github.com/TeamUltroid/Ultroid/ > +# PLease read the GNU Affero General Public License in +# . + +import random +import re +from urllib.request import urlopen + +import play_scraper +import requests +from bs4 import BeautifulSoup +from search_engine_parser import GoogleSearch, YahooSearch +from telethon import Button +from telethon.tl.types import InputWebDocument as wb + +gugirl = "https://telegra.ph/file/0df54ae4541abca96aa11.jpg" +yeah = "https://telegra.ph/file/e3c67885e16a194937516.jpg" +ps = "https://telegra.ph/file/de0b8d9c858c62fae3b6e.jpg" + + +@in_pattern("go") +@in_owner +async def gsearch(q_event): + try: + match = q_event.text.split(" ", maxsplit=1)[1] + except IndexError: + kkkk = q_event.builder.article( + title="Search Something", + thumb=wb( + gugirl, + 0, + "image/jpeg", + []), + text="**Gᴏᴏɢʟᴇ Sᴇᴀʀᴄʜ**\n\nYou didn't search anything", + buttons=Button.switch_inline( + "Sᴇᴀʀᴄʜ Aɢᴀɪɴ", + query="go ", + same_peer=True), + ) + await q_event.answer([kkkk]) + searcher = [] + page = re.findall(r"page=\d+", match) + try: + page = page[0] + page = page.replace("page=", "") + match = match.replace("page=" + page[0], "") + except IndexError: + page = 1 + search_args = (str(match), int(page)) + gsearch = GoogleSearch() + gresults = await gsearch.async_search(*search_args) + msg = "" + for i in range(len(gresults["links"])): + try: + title = gresults["titles"][i] + link = gresults["links"][i] + desc = gresults["descriptions"][i] + msg += f"👉[{title}]({link})\n`{desc}`\n\n" + searcher.append( + await q_event.builder.article( + title=title, + description=desc, + thumb=wb(gugirl, 0, "image/jpeg", []), + text=f"**Gᴏᴏɢʟᴇ Sᴇᴀʀᴄʜ**\n\n**••Tɪᴛʟᴇ••**\n`{title}`\n\n**••Dᴇsᴄʀɪᴘᴛɪᴏɴ••**\n`{desc}`", + link_preview=False, + buttons=[ + [Button.url("Lɪɴᴋ", url=f"{link}")], + [ + Button.switch_inline( + "Sᴇᴀʀᴄʜ Aɢᴀɪɴ", query="go ", same_peer=True + ), + Button.switch_inline( + "Sʜᴀʀᴇ", query=f"go {match}", same_peer=False + ), + ], + ], + ) + ) + except IndexError: + break + await q_event.answer(searcher) + + +@in_pattern("yahoo") +@in_owner +async def gsearch(q_event): + try: + match = q_event.text.split(" ", maxsplit=1)[1] + except IndexError: + kkkk = q_event.builder.article( + title="Search Something", + thumb=wb(yeah, 0, "image/jpeg", []), + text="**Yᴀʜᴏᴏ Sᴇᴀʀᴄʜ**\n\nYou didn't search anything", + buttons=Button.switch_inline( + "Sᴇᴀʀᴄʜ Aɢᴀɪɴ", query="yahoo ", same_peer=True + ), + ) + await q_event.answer([kkkk]) + searcher = [] + page = re.findall(r"page=\d+", match) + try: + page = page[0] + page = page.replace("page=", "") + match = match.replace("page=" + page[0], "") + except IndexError: + page = 1 + search_args = (str(match), int(page)) + gsearch = YahooSearch() + gresults = await gsearch.async_search(*search_args) + msg = "" + for i in range(len(gresults["links"])): + try: + title = gresults["titles"][i] + link = gresults["links"][i] + desc = gresults["descriptions"][i] + msg += f"👉[{title}]({link})\n`{desc}`\n\n" + searcher.append( + await q_event.builder.article( + title=title, + description=desc, + thumb=wb(yeah, 0, "image/jpeg", []), + text=f"**Yᴀʜᴏᴏ Sᴇᴀʀᴄʜ**\n\n**••Tɪᴛʟᴇ••**\n`{title}`\n\n**••Dᴇsᴄʀɪᴘᴛɪᴏɴ••**\n`{desc}`", + link_preview=False, + buttons=[ + [Button.url("Lɪɴᴋ", url=f"{link}")], + [ + Button.switch_inline( + "Sᴇᴀʀᴄʜ Aɢᴀɪɴ", query="yahoo ", same_peer=True + ), + Button.switch_inline( + "Sʜᴀʀᴇ", query=f"yahoo {match}", same_peer=False + ), + ], + ], + ) + ) + except IndexError: + break + await q_event.answer(searcher) + + +@in_pattern("app") +@in_owner +async def _(e): + try: + f = e.text.split(" ", maxsplit=1)[1] + except IndexError: + kkkk = e.builder.article( + title="Search Something", + thumb=wb( + ps, + 0, + "image/jpeg", + []), + text="**Pʟᴀʏ Sᴛᴏʀᴇ**\n\nYou didn't search anything", + buttons=Button.switch_inline( + "Sᴇᴀʀᴄʜ Aɢᴀɪɴ", + query="app ", + same_peer=True), + ) + await e.answer([kkkk]) + foles = [] + aap = play_scraper.search(f) + for z in aap: + name = z["title"] + desc = z["description"] + price = z["price"] + dev = z["developer"] + icon = z["icon"] + url = z["url"] + ids = z["app_id"] + text = f"**••Aᴘᴘ Nᴀᴍᴇ••** [{name}]({icon})\n" + text += f"**••Dᴇᴠᴇʟᴏᴘᴇʀ••** `{dev}`\n" + text += f"**••Pʀɪᴄᴇ••** `{price}`\n\n" + text += f"**••Dᴇsᴄʀɪᴘᴛɪᴏɴ••**\n`{desc}`" + foles.append( + await e.builder.article( + title=name, + description=ids, + thumb=wb(ps, 0, "image/jpeg", []), + text=text, + link_preview=True, + buttons=[ + [Button.url("Lɪɴᴋ", url=f"https://play.google.com{url}")], + [ + Button.switch_inline( + "Mᴏʀᴇ Aᴘᴘs", + query="app ", + same_peer=True, + ), + Button.switch_inline( + "Sʜᴀʀᴇ", + query=f"app {f}", + same_peer=False, + ), + ], + ], + ), + ) + await e.answer(foles) + + +@in_pattern("mods") +@in_owner +async def _(e): + try: + quer = e.text.split(" ", maxsplit=1)[1] + except IndexError: + kkkk = e.builder.article( + title="Search Something", + text="**Mᴏᴅᴅᴇᴅ Aᴘᴘs**\n\nYou didn't search anything", + buttons=Button.switch_inline( + "Sᴇᴀʀᴄʜ Aɢᴀɪɴ", + query="mods ", + same_peer=True), + ) + await e.answer([kkkk]) + page = 1 + start = (page - 1) * 3 + 1 + urd = random.randrange(1, 3) + if urd == 1: + da = "AIzaSyAyDBsY3WRtB5YPC6aB_w8JAy6ZdXNc6FU" + if urd == 2: + da = "AIzaSyBF0zxLlYlPMp9xwMQqVKCQRq8DgdrLXsg" + if urd == 3: + da = "AIzaSyDdOKnwnPwVIQ_lbH5sYE4FoXjAKIQV0DQ" + url = f"https://www.googleapis.com/customsearch/v1?key={da}&cx=25b3b50edb928435b&q={quer}&start={start}" + data = requests.get(url).json() + search_items = data.get("items") + play_scraper.search(quer) + modss = [] + for a in search_items: + title = a.get("title") + desc = a.get("snippet") + link = a.get("link") + text = f"**••Tɪᴛʟᴇ••** `{title}`\n\n" + text += f"**Dᴇsᴄʀɪᴘᴛɪᴏɴ** `{desc}`" + modss.append( + await e.builder.article( + title=title, + description=desc, + text=text, + link_preview=True, + buttons=[ + [Button.url("Dᴏᴡɴʟᴏᴀᴅ", url=f"{link}")], + [ + Button.switch_inline( + "Mᴏʀᴇ Mᴏᴅs", query="mods ", same_peer=True + ), + Button.switch_inline( + "Sʜᴀʀᴇ", query=f"mods {quer}", same_peer=False + ), + ], + ], + ) + ) + await e.answer(modss) + + +@in_pattern("clipart") +@in_owner +async def clip(e): + try: + quer = e.text.split(" ", maxsplit=1)[1] + except IndexError: + kkkk = e.builder.article( + title="Search Something", + text="**Cʟɪᴘᴀʀᴛ Sᴇᴀʀᴄʜ**\n\nYou didn't search anything", + buttons=Button.switch_inline( + "Sᴇᴀʀᴄʜ Aɢᴀɪɴ", query="clipart ", same_peer=True + ), + ) + await e.answer([kkkk]) + quer = quer.replace(" ", "+") + sear = f"https://clipartix.com/search/{quer}" + html = urlopen(sear) + bs = BeautifulSoup(html, "lxml", from_encoding="utf-8") + resul = bs.find_all("img", "attachment-full size-full") + buil = e.builder + hm = [] + for res in resul: + hm += [buil.photo(include_media=True, file=res["src"])] + await e.answer(hm, gallery=True) diff --git a/assistant/othervars.py b/assistant/othervars.py new file mode 100644 index 0000000000..bf89c8a1b4 --- /dev/null +++ b/assistant/othervars.py @@ -0,0 +1,120 @@ +# Ultroid - UserBot +# Copyright (C) 2020 TeamUltroid +# +# This file is a part of < https://github.com/TeamUltroid/Ultroid/ > +# PLease read the GNU Affero General Public License in +# . + +from . import * + +# main menuu for setting other vars + + +@callback("otvars") +@owner +async def otvaar(event): + await event.edit( + "Other Variables to set for @TheUltroid:", + buttons=[ + [Button.inline("Tag Logger", data="taglog")], + [Button.inline("PM Permit", data="pmset")], + [Button.inline("SuperFban", data="sfban")] + ], + ) + + +@callback("taglog") +@owner +async def tagloggerr(event): + await event.delete() + pru = event.sender_id + var = "TAG_LOG" + name = "Tag Log Group" + async with event.client.conversation(pru) as conv: + await conv.send_message( + f"Make a group, add your assistant and make it admin.\nGet the `{hndlr}id` of that group and send it here for tag logs.\n\nUse /cancel to cancel." + ) + response = conv.wait_event(events.NewMessage(chats=pru)) + response = await response + themssg = response.message.message + if themssg == "/cancel": + return await conv.send_message("Cancelled!!") + else: + await setit(event, var, themssg) + await conv.send_message("{} changed to {}".format(name, themssg)) + + +@callback("pmset") +@owner +async def pmset(event): + await event.edit( + "PMPermit Settings:", + buttons=[ + [Button.inline("Turn PMPermit On", data="pmon")], + [Button.inline("Turn PMPermit Off", data="pmoff")], + ], + ) + + +@callback("pmon") +@owner +async def pmonn(event): + var = "PMSETTING" + await setit(event, var, "True") + await event.edit(f"Done! PMPermit has been turned on!! Please `{hndlr}restart`") + + +@callback("pmoff") +@owner +async def pmofff(event): + var = "PMSETTING" + await setit(event, var, "False") + await event.edit(f"Done! PMPermit has been turned off!! Please `{hndlr}restart`") + + +@callback("sfban") +@owner +async def sfban(event): + await event.edit("SuperFban Settings:", + buttons=[ + [Button.inline("FBan Group", data="sfgrp")], + [Button.inline("Exclude Feds", data="sfexf")] + ]) + + +@callback("sfgrp") +@owner +async def sfgrp(event): + await event.delete() + name = "FBan Group ID" + var = "FBAN_GROUP_ID" + pru = event.sender_id + async with asst.conversation(pru) as conv: + await conv.send_message(f"Make a group, add @MissRose_Bot, send `{hndlr}id`, copy that and send it here.\nUse /cancel to go back.") + response = conv.wait_event(events.NewMessage(chats=pru)) + response = await response + themssg = response.message.message + if themssg == "/cancel": + return await conv.send_message("Cancelled!!") + else: + await setit(event, var, themssg) + await conv.send_message("{} changed to {}".format(name, themssg)) + + +@callback("sfexf") +@owner +async def sfexf(event): + await event.delete() + name = "Excluded Feds" + var = "EXCLUDE_FED" + pru = event.sender_id + async with asst.conversation(pru) as conv: + await conv.send_message(f"Send the Fed IDs you want to exclude in the ban. Split by a space.\neg`id1 id2 id3`\nSet is as `None` if you dont want any.\nUse /cancel to go back.") + response = conv.wait_event(events.NewMessage(chats=pru)) + response = await response + themssg = response.message.message + if themssg == "/cancel": + return await conv.send_message("Cancelled!!") + else: + await setit(event, var, themssg) + await conv.send_message("{} changed to {}".format(name, themssg)) diff --git a/assistant/ping.py b/assistant/ping.py new file mode 100644 index 0000000000..1b4bbddb64 --- /dev/null +++ b/assistant/ping.py @@ -0,0 +1,20 @@ +# Ultroid - UserBot +# Copyright (C) 2020 TeamUltroid +# +# This file is a part of < https://github.com/TeamUltroid/Ultroid/ > +# PLease read the GNU Affero General Public License in +# . + +from datetime import datetime + + +@asst_cmd("ping") +@owner +async def _(event): + start = datetime.now() + end = datetime.now() + ms = (end - start).microseconds / 1000 + await asst.send_message( + event.chat_id, + f"**Pong!!**\n `{ms}ms`", + ) diff --git a/assistant/pmbot/__init__.py b/assistant/pmbot/__init__.py new file mode 100644 index 0000000000..b8e9749d48 --- /dev/null +++ b/assistant/pmbot/__init__.py @@ -0,0 +1,6 @@ +from pyUltroid.functions.asst_fns import * + +from .. import * + +OWNER_NAME = ultroid_bot.me.first_name +OWNER_ID = ultroid_bot.me.id diff --git a/assistant/pmbot/banuser.py b/assistant/pmbot/banuser.py new file mode 100644 index 0000000000..b77cc83721 --- /dev/null +++ b/assistant/pmbot/banuser.py @@ -0,0 +1,40 @@ +from . import * + + +@asst_cmd("ban") +async def banhammer(event): + x = await event.get_reply_message() + if x is None: + return await event.edit("Please reply to someone to ban him.") + if x.fwd_from: + target = x.fwd_from.from_id.user_id + else: + # this is a weird way of doing it + return + if not is_blacklisted(target): + blacklist_user(target) + await asst.send_message(event.chat_id, f"#BAN\nUser - {target}") + await asst.send_message( + target, + "`GoodBye! You have been banned.`\n**Further messages you send will not be forwarded.**", + ) + else: + return await asst.send_message(event.chat_id, f"User is already banned!") + + +@asst_cmd("unban") +async def banhammer(event): + x = await event.get_reply_message() + if x is None: + return await event.edit("Please reply to someone to ban him.") + if x.fwd_from: + target = x.fwd_from.from_id.user_id + else: + # this is a weird way of doing it + return + if is_blacklisted(target): + rem_blacklist(target) + await asst.send_message(event.chat_id, f"#UNBAN\nUser - {target}") + await asst.send_message(target, "`Congrats! You have been unbanned.`") + else: + return await asst.send_message(event.chat_id, f"User was never banned!") diff --git a/assistant/pmbot/incoming.py b/assistant/pmbot/incoming.py new file mode 100644 index 0000000000..fa94ff21da --- /dev/null +++ b/assistant/pmbot/incoming.py @@ -0,0 +1,32 @@ +# Ultroid - UserBot +# Copyright (C) 2020 TeamUltroid +# +# This file is a part of < https://github.com/TeamUltroid/Ultroid/ > +# PLease read the GNU Affero General Public License in +# . + +# https://github.com/xditya/TeleBot/blob/master/telebot/plugins/mybot/pmbot/incoming.py +""" +Incoming Message(s) forwarder. +""" + +from telethon import events + +from . import * + +# if incoming + + +@asst.on(events.NewMessage(func=lambda e: e.is_private)) +async def on_new_mssg(event): + incoming = event.raw_text + who = event.sender_id + if is_blacklisted(who): + return + # doesn't reply to that user anymore + if incoming.startswith("/"): + pass + elif who == OWNER_ID: + return + else: + await event.forward_to(OWNER_ID) diff --git a/assistant/pmbot/outgoing.py b/assistant/pmbot/outgoing.py new file mode 100644 index 0000000000..9a2c5f2d81 --- /dev/null +++ b/assistant/pmbot/outgoing.py @@ -0,0 +1,43 @@ +# Ultroid - UserBot +# Copyright (C) 2020 TeamUltroid +# +# This file is a part of < https://github.com/TeamUltroid/Ultroid/ > +# PLease read the GNU Affero General Public License in +# . + +# https://github.com/xditya/TeleBot/blob/master/telebot/plugins/mybot/pmbot/outgoing.py + +from telethon import events +from telethon.utils import pack_bot_file_id + +from . import * + +# outgoing + + +@asst.on(events.NewMessage(func=lambda e: e.is_private)) +async def on_out_mssg(event): + x = await event.get_reply_message() + if x is None: + return + to_send = event.raw_text + who = event.sender_id + if x.fwd_from: + to_user = x.fwd_from.sender_id.user_id + else: + # this is a weird way of doing it + return + if who == OWNER_ID: + if to_send.startswith("/"): + return + if event.text is not None and event.media: + # if sending media + bot_api_file_id = pack_bot_file_id(event.media) + await asst.send_file( + to_user, + file=bot_api_file_id, + caption=event.text, + reply_to=x.reply_to_msg_id, + ) + else: + await asst.send_message(to_user, to_send, reply_to=x.reply_to_msg_id) diff --git a/assistant/start.py b/assistant/start.py new file mode 100644 index 0000000000..09f8e04dcc --- /dev/null +++ b/assistant/start.py @@ -0,0 +1,113 @@ +# Ultroid - UserBot +# Copyright (C) 2020 TeamUltroid +# +# This file is a part of < https://github.com/TeamUltroid/Ultroid/ > +# PLease read the GNU Affero General Public License in +# . + +from datetime import datetime + +from pyUltroid.functions.asst_fns import * +from telethon import Button, custom, events + +from plugins import * + +from . import * + + +@asst_cmd("start") +async def assistant(event): + if event.is_group and event.sender_id in sed: + return await eor(event, "`I dont work in groups`") + else: + if not is_added(event.sender_id) and event.sender_id not in sed: + add_user(event.sender_id) + await asst.send_message( + OWNER_ID, + f"Bot started by [{event.sender_id}](tg://user?id={event.sender_id})", + ) + ok = "" + if Var.MSG_FRWD is True: + ok = "You can contact me using this bot!!" + if event.is_private and event.sender_id in sed: + return + await event.reply( + f"Hey there, this is Ultroid Assistant of {OWNER_NAME}!\n\n{ok}", + buttons=[Button.url("Know More", url="https://t.me/TeamUltroid")], + ) + + +@asst_cmd("start") +@owner +async def ultroid(event): + if event.is_group: + return + await asst.send_message( + event.chat_id, + f"Hi {OWNER_NAME}. Please browse through the options", + buttons=[ + [custom.Button.inline("Settings ⚙️", data="setter")], + [custom.Button.inline("Stats", data="stat")], + [custom.Button.inline("Broadcast", data="bcast")], + ], + ) + + +@callback("stat") +@owner +async def botstat(event): + ok = len(get_all_users()) + msg = """Ultroid Assistant - Stats +Total Users - {}""".format( + ok + ) + await event.answer(msg, cache_time=0, alert=True) + + +@callback("bcast") +@owner +async def bdcast(event): + ok = get_all_users() + await event.edit(f"Broadcast to {len(ok)} users.") + async with event.client.conversation(OWNER_ID) as conv: + await conv.send_message( + "Enter your broadcast message.\nUse /cancel to stop the broadcast." + ) + response = conv.wait_event(events.NewMessage(chats=OWNER_ID)) + response = await response + themssg = response.message.message + if themssg == "/cancel": + return await conv.send_message("Cancelled!!") + else: + success = 0 + fail = 0 + await conv.send_message(f"Starting a broadcast to {len(ok)} users...") + start = datetime.now() + for i in ok: + try: + await asst.send_message(int(i), f"{themssg}") + success += 1 + except BaseException: + fail += 1 + end = datetime.now() + time_taken = (end - start).seconds + await conv.send_message( + f""" +Broadcast completed in {time_taken} seconds. +Total Users in Bot - {len(ok)} +Sent to {success} users. +Failed for {fail} user(s).""" + ) + + +@callback("setter") +@owner +async def setting(event): + await event.edit( + "Choose from the below options -", + buttons=[ + [custom.Button.inline("Alive Customisation", data="alvcstm")], + [custom.Button.inline("API Keys", data="apiset")], + [custom.Button.inline("Other Vars.", data="otvars")], + ], + ) diff --git a/assistant/ytdl.py b/assistant/ytdl.py new file mode 100644 index 0000000000..05af667275 --- /dev/null +++ b/assistant/ytdl.py @@ -0,0 +1,197 @@ +# Ultroid - UserBot +# Copyright (C) 2020 TeamUltroid +# +# This file is a part of < https://github.com/TeamUltroid/Ultroid/ > +# PLease read the GNU Affero General Public License in +# . + + +import asyncio +import os +import re +import time + +from pyUltroid.functions.all import * +from telethon import Button +from telethon.tl.types import DocumentAttributeAudio, InputWebDocument as wb +from youtube_dl import YoutubeDL +from youtubesearchpython import VideosSearch + +ytt = "https://telegra.ph/file/afd04510c13914a06dd03.jpg" + + +@in_pattern("yt") +@in_owner +async def _(event): + try: + string = event.text.split(" ", maxsplit=1)[1] + except IndexError: + fuk = event.builder.article( + title="Search Something", + thumb=wb(ytt, 0, "image/jpeg", []), + text="**YᴏᴜTᴜʙᴇ Sᴇᴀʀᴄʜ**\n\nYou didn't search anything", + buttons=Button.switch_inline( + "Sᴇᴀʀᴄʜ Aɢᴀɪɴ", + query="yt ", + same_peer=True, + ), + ) + await event.answer([fuk]) + return + results = [] + search = VideosSearch(string, limit=10) + nub = search.result() + nibba = nub["result"] + for v in nibba: + link = v["link"] + title = v["title"] + ids = v["id"] + duration = v["duration"] + thumb = f"https://img.youtube.com/vi/{ids}/hqdefault.jpg" + text = f"**•Tɪᴛʟᴇ•** `{title}`\n\n**••[Lɪɴᴋ]({link})••**\n\n**••Dᴜʀᴀᴛɪᴏɴ••** `{duration}`\n\n\n" + desc = f"Title : {title}\nDuration : {duration}" + results.append( + await event.builder.document( + file=thumb, + title=title, + description=desc, + text=text, + include_media=True, + buttons=[ + [ + Button.inline("Audio", data=f"audio{link}"), + Button.inline("Video", data=f"video{link}"), + ], + [ + Button.switch_inline( + "Sᴇᴀʀᴄʜ Aɢᴀɪɴ", query="yt ", same_peer=True + ), + Button.switch_inline( + "Sʜᴀʀᴇ", query=f"yt {string}", same_peer=False + ), + ], + ], + ) + ) + await event.answer(results) + + +@callback(re.compile("audio(.*)")) +@owner +async def _(sur): + url = sur.pattern_match.group(1).decode("UTF-8") + getter = sur.sender_id + opts = { + "format": "bestaudio", + "addmetadata": True, + "key": "FFmpegMetadata", + "writethumbnail": True, + "prefer_ffmpeg": True, + "geo_bypass": True, + "nocheckcertificate": True, + "postprocessors": [ + { + "key": "FFmpegExtractAudio", + "preferredcodec": "mp3", + "preferredquality": "320", + } + ], + "outtmpl": "%(id)s.mp3", + "quiet": True, + "logtostderr": False, + } + song = True + await dler(sur) + with YoutubeDL(opts) as ytdl: + ytdl_data = ytdl.extract_info(url) + + jpg = f"{ytdl_data['id']}.mp3.jpg" + png = f"{ytdl_data['id']}.mp3.png" + webp = f"{ytdl_data['id']}.mp3.webp" + dir = os.listdir() + + if jpg in dir: + thumb = jpg + elif png in dir: + thumb = png + elif webp in dir: + thumb = webp + else: + thumb = None + + c_time = time.time() + if song: + await sur.edit( + f"`Preparing to upload song:`\ + \n**{ytdl_data['title']}**\ + \nby *{ytdl_data['uploader']}*" + ) + await asst.send_file( + getter, + f"{ytdl_data['id']}.mp3", + thumb=thumb, + caption=f"**{ytdl_data['title']}\n{convert(ytdl_data['duration'])}\n{ytdl_data['uploader']}**", + supports_streaming=True, + attributes=[ + DocumentAttributeAudio( + duration=int(ytdl_data["duration"]), + title=str(ytdl_data["title"]), + performer=str(ytdl_data["uploader"]), + ) + ], + progress_callback=lambda d, t: asyncio.get_event_loop().create_task( + progress(d, t, sur, c_time, "Uploading..", f"{ytdl_data['title']}.mp3") + ), + ) + os.system(f"rm {ytdl_data['id']}.mp*") + await sur.edit( + f"Get Your requested file **{ytdl_data['title']}** from here {Var.BOT_USERNAME} ", + buttons=Button.switch_inline("Search More", query="yt ", same_peer=True), + ) + + +@callback(re.compile("video(.*)")) +@owner +async def _(fuk): + url = fuk.pattern_match.group(1).decode("UTF-8") + getter = fuk.sender_id + opts = { + "format": "best", + "addmetadata": True, + "key": "FFmpegMetadata", + "writethumbnail": True, + "prefer_ffmpeg": True, + "geo_bypass": True, + "nocheckcertificate": True, + "postprocessors": [{"key": "FFmpegVideoConvertor", "preferedformat": "mp4"}], + "outtmpl": "%(id)s.mp4", + "logtostderr": False, + "quiet": True, + } + video = True + await dler(fuk) + with YoutubeDL(opts) as ytdl: + ytdl_data = ytdl.extract_info(url) + + c_time = time.time() + if video: + await fuk.edit( + f"`Preparing to upload video:`\ + \n**{ytdl_data['title']}**\ + \nby *{ytdl_data['uploader']}*" + ) + await asst.send_file( + getter, + f"{ytdl_data['id']}.mp4", + thumb=f"./resources/extras/ultroid.jpg", + caption=f"**{ytdl_data['title']}\n{convert(ytdl_data['duration'])}\n{ytdl_data['uploader']}**", + supports_streaming=True, + progress_callback=lambda d, t: asyncio.get_event_loop().create_task( + progress(d, t, fuk, c_time, "Uploading..", f"{ytdl_data['title']}.mp4") + ), + ) + os.remove(f"{ytdl_data['id']}.mp4") + await fuk.edit( + f"Get Your requested file **{ytdl_data['title']}** from here {Var.BOT_USERNAME} ", + buttons=Button.switch_inline("Search More", query="yt ", same_peer=True), + ) diff --git a/heroku.yml b/heroku.yml new file mode 100644 index 0000000000..09b09fc793 --- /dev/null +++ b/heroku.yml @@ -0,0 +1,3 @@ +build: + docker: + worker: Dockerfile diff --git a/plugins/__init__.py b/plugins/__init__.py new file mode 100644 index 0000000000..f562b1253a --- /dev/null +++ b/plugins/__init__.py @@ -0,0 +1,98 @@ +# Ultroid - UserBot +# Copyright (C) 2020 TeamUltroid +# +# This file is a part of < https://github.com/TeamUltroid/Ultroid/ > +# PLease read the GNU Affero General Public License in +# . + +import time + +from pyUltroid import * +from pyUltroid.dB.core import * +from pyUltroid.functions import * +from pyUltroid.functions.all import * +from pyUltroid.functions.google_image import googleimagesdownload +from pyUltroid.functions.sudos import * +from pyUltroid.utils import * + +start_time = time.time() +ultroid_version = "v0.0.1" +OWNER_NAME = ultroid_bot.me.first_name +OWNER_ID = ultroid_bot.me.id +DEVLIST = [ + "1259468938", + "1452145387", + "719195224", + "1318486004", + "1289422521", + "1322549723", + "611816596", + "1003250439", + "1152902819", + "716243352", + "1444249738", + "559661211", + "881536550", + "630654925", +] + +# sudo +ok = udB.get("SUDOS") +if ok: + SUDO_USERS = set(int(x) for x in ok.split()) +else: + SUDO_USERS = "" + +if SUDO_USERS: + sudos = list(SUDO_USERS) +else: + sudos = "" + +on = Var.SUDO + +if Var.SUDO: + sed = [ultroid_bot.uid, *sudos] +else: + sed = [ultroid_bot.uid] + + +def grt(seconds: int) -> str: + count = 0 + up_time = "" + time_list = [] + time_suffix_list = ["s", "m", "h", "days"] + + while count < 4: + count += 1 + if count < 3: + remainder, result = divmod(seconds, 60) + else: + remainder, result = divmod(seconds, 24) + if seconds == 0 and remainder == 0: + break + time_list.append(int(result)) + seconds = int(remainder) + + for x in range(len(time_list)): + time_list[x] = str(time_list[x]) + time_suffix_list[x] + if len(time_list) == 4: + up_time += time_list.pop() + ", " + + time_list.reverse() + up_time += ":".join(time_list) + + return up_time + + +KANGING_STR = [ + "Using Witchery to kang this sticker...", + "Plagiarising hehe...", + "Inviting this sticker over to my pack...", + "Kanging this sticker...", + "Hey that's a nice sticker!\nMind if I kang?!..", + "Hehe me stel ur stiker...", + "Ay look over there (☉。☉)!→\nWhile I kang this...", + "Roses are red violets are blue, kanging this sticker so my pack looks cool", + "Imprisoning this sticker...", + "Mr.Steal-Your-Sticker is stealing this sticker... ", +] diff --git a/plugins/_help.py b/plugins/_help.py new file mode 100644 index 0000000000..9025b6f455 --- /dev/null +++ b/plugins/_help.py @@ -0,0 +1,66 @@ +# Ultroid - UserBot +# Copyright (C) 2020 TeamUltroid +# +# This file is a part of < https://github.com/TeamUltroid/Ultroid/ > +# PLease read the GNU Affero General Public License in +# . + +from pyUltroid.dB.database import Var +from support import * +from telethon.errors.rpcerrorlist import BotInlineDisabledError as dis +from telethon.errors.rpcerrorlist import BotMethodInvalidError as bmi +from telethon.errors.rpcerrorlist import BotResponseTimeoutError as rep + +from . import * + + +@ultroid_cmd( + pattern="help ?(.*)", +) +async def ult(ult): + plug = ult.pattern_match.group(1) + tgbot = Var.BOT_USERNAME + if plug: + try: + if plug in HELP: + output = "**Plugin** - `{}`\n".format(plug) + for i in HELP[plug]: + output += i + output += "\n© @TheUltroid" + await eor(ult, output) + elif plug in CMD_HELP: + kk = f"Plugin Name-{plug}\n\n✘ Commands Available-\n\n" + kk += str(CMD_HELP[plug]) + await eor(ult, kk) + else: + try: + x = f"Plugin Name-{plug}\n\n✘ Commands Available-\n\n" + for d in LIST[plug]: + x += Var.HNDLR + d + x += "\n" + await eor(ult, x) + except BaseException: + await eod(ult, f"`{plug}` is not a valid plugin!", time=5) + except BaseException: + await eor(ult, "Error 🤔 occured.") + else: + try: + results = await ultroid_bot.inline_query(tgbot, "ultd") + except rep: + return await eor( + ult, + "`The bot did not respond to the inline query.\nConsider using {}restart`".format( + Var.HNDLR + ), + ) + except dis: + return await eor( + ult, "`Please turn on inline mode for your bot from` @Botfather." + ) + except bmi: + return await eor( + ult, + f"Hey, \nYou are on Bot Mode. \nBot Mode Users Cant Get Help Directly ... \nInstead Copy Paste The Following in The Chat and Click The Pop Up \n\n `@{tgbot} ultd`", + ) + await results[0].click(ult.chat_id, reply_to=ult.reply_to_msg_id, hide_via=True) + await ult.delete() diff --git a/plugins/_inline.py b/plugins/_inline.py new file mode 100644 index 0000000000..3b3da725f7 --- /dev/null +++ b/plugins/_inline.py @@ -0,0 +1,503 @@ +# Ultroid - UserBot +# Copyright (C) 2020 TeamUltroid +# +# This file is a part of < https://github.com/TeamUltroid/Ultroid/ > +# PLease read the GNU Affero General Public License in +# . + +import os +import random +import re +import time +from datetime import datetime +from math import ceil +from platform import python_version as pyver + +from git import Repo +from support import * +from telethon import Button, __version__ +from telethon.tl.types import InputWebDocument + +from . import * + +# ================================================# +notmine = "This bot is for {}".format(OWNER_NAME) +ULTROID_PIC = "https://telegra.ph/file/11245cacbffe92e5d5b14.jpg" +helps = """ +[Uʟᴛʀᴏɪᴅ Sᴜᴘᴘᴏʀᴛ](t.me/ultroidsupport) + +**Hᴇʟᴘ Mᴇɴᴜ Oғ {}. + +Pʟᴜɢɪɴs ~ {}** +""" + + +if Var.ADDONS: + zhelps = """ +[Uʟᴛʀᴏɪᴅ Sᴜᴘᴘᴏʀᴛ](t.me/ultroidsupport) + +**Hᴇʟᴘ Mᴇɴᴜ Oғ {}. + +Aᴅᴅᴏɴs ~ {}** +""" +else: + zhelps = """ +[Uʟᴛʀᴏɪᴅ Sᴜᴘᴘᴏʀᴛ](t.me/ultroidsupport) + +**Hᴇʟᴘ Mᴇɴᴜ Oғ {}. + +Aᴅᴅᴏɴs ~ {} + +Gᴏ Aɴᴅ Aᴅᴅ ADDON Vᴀʀ Wɪᴛʜ Vᴀʟᴜᴇ Tʀᴜᴇ** +""" +# ============================================# + + +@inline +@in_owner +async def e(o): + if len(o.text) == 0: + b = o.builder + uptime = grt((time.time() - start_time)) + ALIVEMSG = """ +**The Ultroid Userbot...**\n\n +✵ **Owner** - `{}` +✵ **Ultroid** - `{}` +✵ **UpTime** - `{}` +✵ **Python** - `{}` +✵ **Telethon** - `{}` +✵ **Branch** - `{}` +""".format( + OWNER_NAME, + ultroid_version, + uptime, + pyver(), + __version__, + Repo().active_branch, + ) + res = [ + b.article( + title="Ultroid Userbot", + url="https://t.me/TeamUltroid", + description="Userbot | Telethon ", + text=ALIVEMSG, + thumb=InputWebDocument(ULTROID_PIC, 0, "image/jpeg", []), + ) + ] + await o.answer(res, switch_pm=f"👥 ULTROID PORTAL", switch_pm_param="start") + + +if Var.BOT_USERNAME is not None and asst is not None: + + @inline + @in_owner + async def inline_handler(event): + builder = event.builder + result = None + query = event.text + if event.query.user_id in sed and query.startswith("ultd"): + result = builder.article( + title="Help Menu", + description="Help Menu - UserBot | Telethon ", + url="https://t.me/TheUltroid", + thumb=InputWebDocument(ULTROID_PIC, 0, "image/jpeg", []), + text=f"** Bᴏᴛ Oғ {OWNER_NAME}\n\nMᴀɪɴ Mᴇɴᴜ\n\nPʟᴜɢɪɴs ~ {len(PLUGINS) - 4}\nAᴅᴅᴏɴs ~ {len(ADDONS)}**", + buttons=[ + [ + Button.inline("• Pʟᴜɢɪɴs", data="hrrrr"), + Button.inline("• Aᴅᴅᴏɴs", data="frrr"), + ], + [Button.inline("Oᴡɴᴇʀ•ᴛᴏᴏʟꜱ", data="ownr")], + [Button.inline("Iɴʟɪɴᴇ•Pʟᴜɢɪɴs", data="inlone")], + [Button.inline("••Cʟᴏꜱᴇ••", data="close")], + ], + ) + await event.answer([result] if result else None) + elif event.query.user_id in sed and query.startswith("paste"): + ok = query.split("-")[1] + link = f"https://nekobin.com/{ok}" + link_raw = f"https://nekobin.com/raw/{ok}" + result = builder.article( + title="Paste", + text="Pᴀsᴛᴇᴅ Tᴏ Nᴇᴋᴏʙɪɴ!", + buttons=[ + [ + Button.url("NekoBin", url=f"{link}"), + Button.url("Raw", url=f"{link_raw}"), + ] + ], + ) + await event.answer([result] if result else None) + + @inline + @in_owner + @callback("ownr") + @owner + async def setting(event): + await event.edit( + buttons=[ + [ + Button.inline("•Pɪɴɢ•", data="pkng"), + Button.inline("•Uᴘᴛɪᴍᴇ•", data="upp"), + ], + [Button.inline("•Rᴇsᴛᴀʀᴛ•", data="rstrt")], + [Button.inline("<- Bᴀᴄᴋ", data="open")], + ], + ) + + @callback("pkng") + async def _(event): + start = datetime.now() + end = datetime.now() + ms = (end - start).microseconds / 1000 + pin = f"🌋Pɪɴɢ = {ms}ms" + await event.answer(pin, cache_time=0, alert=True) + + @callback("upp") + async def _(event): + uptime = grt((time.time() - start_time)) + pin = f"🙋Uᴘᴛɪᴍᴇ = {uptime}" + await event.answer(pin, cache_time=0, alert=True) + + @callback("inlone") + @owner + async def _(e): + button = [ + [ + Button.switch_inline( + "Sᴇɴᴅ Oғғɪᴄɪᴀʟ Pʟᴜɢɪɴs", + query="send all", + same_peer=True, + ) + ], + [ + Button.switch_inline( + "Pʟᴀʏ Sᴛᴏʀᴇ Aᴘᴘs", + query="app telegram", + same_peer=True, + ) + ], + [ + Button.switch_inline( + "Mᴏᴅᴅᴇᴅ Aᴘᴘs", + query="mods minecraft", + same_peer=True, + ) + ], + [ + Button.switch_inline( + "Sᴇᴀʀᴄʜ Oɴ Gᴏᴏɢʟᴇ", + query="go TeamUltroid", + same_peer=True, + ) + ], + [ + Button.switch_inline( + "Sᴇᴀʀᴄʜ Oɴ Yᴀʜᴏᴏ", + query="yahoo TeamUltroid", + same_peer=True, + ) + ], + [ + Button.switch_inline( + "YᴏᴜTᴜʙᴇ Dᴏᴡɴʟᴏᴀᴅᴇʀ", + query="yt How to Deploy Ultroid Userbot", + same_peer=True, + ) + ], + [ + Button.switch_inline( + "CʟɪᴘAʀᴛ Sᴇᴀʀᴄʜ", + query="clipart frog", + same_peer=True, + ) + ], + [ + Button.inline( + "<- Bᴀᴄᴋ", + data="open", + ) + ], + ] + await e.edit(buttons=button, link_preview=False) + + @callback("hrrrr") + @owner + async def on_plug_in_callback_query_handler(event): + xhelps = helps.format(OWNER_NAME, len(PLUGINS) - 4) + buttons = paginate_help(0, PLUGINS, "helpme") + await event.edit(f"{xhelps}", buttons=buttons, link_preview=False) + + @callback("frrr") + @owner + async def addon(event): + halp = zhelps.format(OWNER_NAME, len(ADDONS)) + if len(ADDONS) > 0: + buttons = paginate_addon(0, ADDONS, "addon") + await event.edit(f"{halp}", buttons=buttons, link_preview=False) + else: + await event.answer( + "• Iɴsᴛᴀʟʟ A Pʟᴜɢɪɴ Mᴀɴᴜᴀʟʟʏ Oʀ Aᴅᴅ Vᴀʀ ADDON Wɪᴛʜ Vᴀʟᴜᴇ Tʀᴜᴇ", + cache_time=0, + alert=True, + link_preview=False, + ) + + @callback("rstrt") + @owner + async def rrst(ult): + await restart(ult) + + @callback( + re.compile( + rb"helpme_next\((.+?)\)", + ), + ) + @owner + async def on_plug_in_callback_query_handler(event): + current_page_number = int(event.data_match.group(1).decode("UTF-8")) + buttons = paginate_help(current_page_number + 1, PLUGINS, "helpme") + await event.edit(buttons=buttons, link_preview=False) + + @callback( + re.compile( + rb"helpme_prev\((.+?)\)", + ), + ) + @owner + async def on_plug_in_callback_query_handler(event): + current_page_number = int(event.data_match.group(1).decode("UTF-8")) + buttons = paginate_help(current_page_number - 1, PLUGINS, "helpme") + await event.edit(buttons=buttons, link_preview=False) + + @callback( + re.compile( + rb"addon_next\((.+?)\)", + ), + ) + @owner + async def on_plug_in_callback_query_handler(event): + current_page_number = int(event.data_match.group(1).decode("UTF-8")) + buttons = paginate_addon(current_page_number + 1, ADDONS, "addon") + await event.edit(buttons=buttons, link_preview=False) + + @callback( + re.compile( + rb"addon_prev\((.+?)\)", + ), + ) + @owner + async def on_plug_in_callback_query_handler(event): + current_page_number = int(event.data_match.group(1).decode("UTF-8")) + buttons = paginate_addon(current_page_number - 1, ADDONS, "addon") + await event.edit(buttons=buttons, link_preview=False) + + @callback("back") + @owner + async def backr(event): + xhelps = helps.format(OWNER_NAME, len(PLUGINS) - 4) + current_page_number = 0 + buttons = paginate_help(current_page_number, PLUGINS, "helpme") + await event.edit(f"{xhelps}", buttons=buttons, link_preview=False) + + @callback("buck") + @owner + async def backr(event): + xhelps = zhelps.format(OWNER_NAME, len(ADDONS)) + current_page_number = 0 + buttons = paginate_addon(current_page_number, ADDONS, "addon") + await event.edit(f"{xhelps}", buttons=buttons, link_preview=False) + + @callback("open") + @owner + async def opner(event): + buttons = [ + [ + Button.inline("• Pʟᴜɢɪɴs ", data="hrrrr"), + Button.inline("• Aᴅᴅᴏɴs", data="frrr"), + ], + [Button.inline("Oᴡɴᴇʀ•Tᴏᴏʟꜱ", data="ownr")], + [Button.inline("Iɴʟɪɴᴇ•Pʟᴜɢɪɴs", data="inlone")], + [Button.inline("••Cʟᴏꜱᴇ••", data="close")], + ] + await event.edit( + f"** Bᴏᴛ Oғ {OWNER_NAME}\n\nMᴀɪɴ Mᴇɴᴜ\n\nOꜰꜰɪᴄɪᴀʟ Pʟᴜɢɪɴs ~ {len(PLUGINS) - 4}\nUɴᴏꜰꜰɪᴄɪᴀʟ Pʟᴜɢɪɴs ~ {len(ADDONS)}**", + buttons=buttons, + link_preview=False, + ) + + @callback("close") + @owner + async def on_plug_in_callback_query_handler(event): + await event.edit( + "**Mᴇɴᴜ Hᴀs Bᴇᴇɴ Cʟᴏsᴇᴅ**", + buttons=Button.inline("Oᴘᴇɴ Mᴀɪɴ Mᴇɴᴜ Aɢᴀɪɴ", data="open"), + ) + + @callback( + re.compile( + b"us_plugin_(.*)", + ), + ) + @owner + async def on_plug_in_callback_query_handler(event): + plugin_name = event.data_match.group(1).decode("UTF-8") + help_string = f"Plugin Name - `{plugin_name}`\n" + try: + for i in HELP[plugin_name]: + help_string += i + except BaseException: + pass + if help_string == "": + reply_pop_up_alert = "{} has no detailed help...".format(plugin_name) + else: + reply_pop_up_alert = help_string + reply_pop_up_alert += "\n© @TheUltroid" + try: + if event.query.user_id in sed: + await event.edit( + reply_pop_up_alert, + buttons=[ + Button.inline("<- Bᴀᴄᴋ", data="back"), + Button.inline("••Cʟᴏꜱᴇ••", data="close"), + ], + ) + else: + reply_pop_up_alert = notmine + await event.answer(reply_pop_up_alert, cache_time=0) + except BaseException: + halps = "Do .help {} to get the list of commands.".format(plugin_name) + await event.edit(halps) + + @callback( + re.compile( + b"add_plugin_(.*)", + ), + ) + @owner + async def on_plug_in_callback_query_handler(event): + plugin_name = event.data_match.group(1).decode("UTF-8") + help_string = "" + try: + for i in HELP[plugin_name]: + help_string += i + except BaseException: + try: + for u in CMD_HELP[plugin_name]: + help_string = ( + f"Plugin Name-{plugin_name}\n\n✘ Commands Available-\n\n" + ) + help_string += str(CMD_HELP[plugin_name]) + except BaseException: + try: + if plugin_name in LIST: + help_string = ( + f"Plugin Name-{plugin_name}\n\n✘ Commands Available-\n\n" + ) + for d in LIST[plugin_name]: + help_string += Var.HNDLR + d + help_string += "\n" + except BaseException: + pass + if help_string == "": + reply_pop_up_alert = "{} has no detailed help...".format(plugin_name) + else: + reply_pop_up_alert = help_string + reply_pop_up_alert += "\n© @TheUltroid" + try: + if event.query.user_id in sed: + await event.edit( + reply_pop_up_alert, + buttons=[ + Button.inline("<- Bᴀᴄᴋ", data="buck"), + Button.inline("••Cʟᴏꜱᴇ••", data="close"), + ], + ) + else: + reply_pop_up_alert = notmine + await event.answer(reply_pop_up_alert, cache_time=0) + except BaseException: + halps = "Do .help {} to get the list of commands.".format(plugin_name) + await event.edit(halps) + + +def paginate_help(page_number, loaded_plugins, prefix): + number_of_rows = 5 + number_of_cols = 2 + multi = os.environ.get("EMOJI_TO_DESPLAY_IN_HELP", "✘") + mult2i = os.environ.get("EMOJI2_TO_DESPLAY_IN_HELP", "✘") + helpable_plugins = [] + for p in loaded_plugins: + if not p.startswith("_"): + helpable_plugins.append(p) + helpable_plugins = sorted(helpable_plugins) + modules = [ + Button.inline( + "{} {} {}".format( + random.choice(list(multi)), x, random.choice(list(mult2i)) + ), + data="us_plugin_{}".format(x), + ) + for x in helpable_plugins + ] + pairs = list(zip(modules[::number_of_cols], modules[1::number_of_cols])) + if len(modules) % number_of_cols == 1: + pairs.append((modules[-1],)) + max_num_pages = ceil(len(pairs) / number_of_rows) + modulo_page = page_number % max_num_pages + if len(pairs) > number_of_rows: + pairs = pairs[ + modulo_page * number_of_rows : number_of_rows * (modulo_page + 1) + ] + [ + ( + Button.inline( + "<- Pʀᴇᴠɪᴏᴜs", data="{}_prev({})".format(prefix, modulo_page) + ), + Button.inline("-Bᴀᴄᴋ-", data="open"), + Button.inline( + "Nᴇxᴛ ->", data="{}_next({})".format(prefix, modulo_page) + ), + ) + ] + return pairs + + +def paginate_addon(page_number, loaded_plugins, prefix): + number_of_rows = 5 + number_of_cols = 2 + multi = os.environ.get("EMOJI_TO_DESPLAY_IN_HELP", "✘") + mult2i = os.environ.get("EMOJI2_TO_DESPLAY_IN_HELP", "✘") + helpable_plugins = [] + for p in loaded_plugins: + if not p.startswith("_"): + helpable_plugins.append(p) + helpable_plugins = sorted(helpable_plugins) + modules = [ + Button.inline( + "{} {} {}".format( + random.choice(list(multi)), x, random.choice(list(mult2i)) + ), + data="add_plugin_{}".format(x), + ) + for x in helpable_plugins + ] + pairs = list(zip(modules[::number_of_cols], modules[1::number_of_cols])) + if len(modules) % number_of_cols == 1: + pairs.append((modules[-1],)) + max_num_pages = ceil(len(pairs) / number_of_rows) + modulo_page = page_number % max_num_pages + if len(pairs) > number_of_rows: + pairs = pairs[ + modulo_page * number_of_rows : number_of_rows * (modulo_page + 1) + ] + [ + ( + Button.inline( + "<- Pʀᴇᴠɪᴏᴜs", data="{}_prev({})".format(prefix, modulo_page) + ), + Button.inline("-Bᴀᴄᴋ-", data="open"), + Button.inline( + "Nᴇxᴛ ->", data="{}_next({})".format(prefix, modulo_page) + ), + ) + ] + return pairs diff --git a/plugins/_tagnotif.py b/plugins/_tagnotif.py new file mode 100644 index 0000000000..51390b241e --- /dev/null +++ b/plugins/_tagnotif.py @@ -0,0 +1,51 @@ +# Ultroid - UserBot +# Copyright (C) 2020 TeamUltroid +# +# This file is a part of < https://github.com/TeamUltroid/Ultroid/ > +# PLease read the GNU Affero General Public License in +# . + +from telethon import custom, events +from telethon.tl.types import Channel +from telethon.utils import get_display_name + +from . import * + + +@ultroid_bot.on( + events.NewMessage( + incoming=True, + func=lambda e: (e.mentioned), + ) +) +async def all_messages_catcher(event): + if udB.get("TAG_LOG") is not None: + NEEDTOLOG = int(udB.get("TAG_LOG")) + await event.forward_to(NEEDTOLOG) + ammoca_message = "" + who_ = await event.client.get_entity(event.sender_id) + if who_.bot or who_.verified or who_.support: + return + who_m = f"[{get_display_name(who_)}](tg://user?id={who_.id})" + where_ = await event.client.get_entity(event.chat_id) + where_m = get_display_name(where_) + button_text = "📨 Go to Message " + if isinstance(where_, Channel): + message_link = f"https://t.me/c/{where_.id}/{event.id}" + chat_link = f"https://t.me/c/{where_.id}" + else: + message_link = f"tg://openmessage?chat_id={where_.id}&message_id={event.id}" + chat_link = f"tg://openmessage?chat_id={where_.id}" + ammoca_message += f"{who_m} tagged you in [{where_m}]({chat_link})" + try: + await asst.send_message( + entity=NEEDTOLOG, + message=ammoca_message, + link_preview=False, + buttons=[[custom.Button.url(button_text, message_link)]], + silent=True, + ) + except BaseException: + pass + else: + return diff --git a/plugins/_wspr.py b/plugins/_wspr.py new file mode 100644 index 0000000000..bc93db0ae3 --- /dev/null +++ b/plugins/_wspr.py @@ -0,0 +1,169 @@ +# Ultroid - UserBot +# Copyright (C) 2020 TeamUltroid +# +# This file is a part of < https://github.com/TeamUltroid/Ultroid/ > +# PLease read the GNU Affero General Public License in +# . + +import re + +from telethon import Button +from telethon.errors.rpcerrorlist import BotInlineDisabledError as dis +from telethon.errors.rpcerrorlist import BotResponseTimeoutError as rep +from telethon.errors.rpcerrorlist import MessageNotModifiedError as np +from telethon.tl.functions.users import GetFullUserRequest as gu +from telethon.tl.types import UserStatusEmpty as mt +from telethon.tl.types import UserStatusLastMonth as lm +from telethon.tl.types import UserStatusLastWeek as lw +from telethon.tl.types import UserStatusOffline as off +from telethon.tl.types import UserStatusOnline as on +from telethon.tl.types import UserStatusRecently as rec + +snap = {} +buddhhu = [] + + +@ultroid_cmd( + pattern="wspr ?(.*)", +) +async def _(e): + if e.reply_to_msg_id: + okk = (await e.get_reply_message()).sender_id + try: + zyx = await ultroid_bot(gu(id=okk)) + put = zyx.user.username + except ValueError as ex: + return await eor(e, str(ex)) + except AttributeError: + return await eor(e, "No username of replied user wad found") + else: + put = e.pattern_match.group(1) + if put: + try: + results = await ultroid_bot.inline_query(Var.BOT_USERNAME, f"msg {put}") + except rep: + return await eor( + e, + "`The bot did not respond to the inline query.\nConsider using {}restart`".format( + Var.HNDLR + ), + ) + except dis: + return await eor( + e, "`Please turn on inline mode for your bot from` @Botfather." + ) + await results[0].click(e.chat_id, reply_to=e.reply_to_msg_id, hide_via=True) + await e.delete() + else: + await eor(e, "Add some id or username too") + + +@in_pattern("msg") +async def _(e): + vvv = e.text + zzz = vvv.split(" ", maxsplit=1) + try: + ggg = zzz[1] + sed = ggg.split(" wspr ", maxsplit=1) + query = sed[0] + except IndexError: + return + meme = e.query.user_id + try: + desc = sed[1] + except IndexError: + desc = "Touch me" + if "wspr" not in vvv: + try: + logi = await ultroid_bot(gu(id=query)) + name = logi.user.first_name + ids = logi.user.id + username = logi.user.username + x = logi.user.status + bio = logi.about + if isinstance(x, on): + status = "Online" + if isinstance(x, off): + status = "Offline" + if isinstance(x, rec): + status = "Last Seen Recently" + if isinstance(x, lm): + status = "Last seen months ago" + if isinstance(x, lw): + status = "Last seen weeks ago" + if isinstance(x, mt): + status = "Can't Tell" + text = f"**Name:** `{name}`\n" + text += f"**Id:** `{ids}`\n" + text += f"**Username:** `{username}`\n" + text += f"**Status:** `{status}`\n" + text += f"**About:** `{bio}`" + button = [ + Button.url("Private", url=f"t.me/{username}"), + Button.switch_inline( + "Secret msg", query=f"msg {query} wspr ", same_peer=True + ), + ] + sur = e.builder.article( + title=f"{name}", + description=desc, + text=text, + buttons=button, + ) + except BaseException: + name = f"User {query} Not Found\nSearch Again" + sur = e.builder.article( + title=name, + text=name, + ) + else: + try: + logi = await ultroid_bot.get_entity(query) + button = [ + Button.inline("Secret Msg", data=f"dd_{logi.id}"), + Button.inline("Delete Msg", data=f"del"), + ] + sur = e.builder.article( + title=f"{logi.first_name}", + description=desc, + text=f"@{logi.username} secret msg for you.\nDelete your msg after reading.\nOr the next msg will not be updated.", + buttons=button, + ) + buddhhu.append(meme) + buddhhu.append(logi.id) + snap.update({logi.id: desc}) + except ValueError: + sur = e.builder.article( + title="Type ur msg", text=f"You Didn't Type Your Msg" + ) + await e.answer([sur]) + + +@callback( + re.compile( + "dd_(.*)", + ), +) +async def _(e): + ids = int(e.pattern_match.group(1).decode("UTF-8")) + if e.sender_id in buddhhu: + await e.answer(snap[ids], alert=True) + else: + await e.answer("Not For You", alert=True) + + +@callback("del") +async def _(e): + if e.sender_id in buddhhu: + for k in buddhhu: + try: + del snap[k] + buddhhu.clear() + except KeyError: + pass + try: + await e.edit("Msg deleted") + except np: + pass + else: + await e.answer("You Can't do this", alert=True) diff --git a/plugins/admintools.py b/plugins/admintools.py new file mode 100644 index 0000000000..8178baf7bd --- /dev/null +++ b/plugins/admintools.py @@ -0,0 +1,420 @@ +# Ultroid - UserBot +# Copyright (C) 2020 TeamUltroid +# +# This file is a part of < https://github.com/TeamUltroid/Ultroid/ > +# PLease read the GNU Affero General Public License in +# . + +""" +✘ Commands Available - + +• `{i}promote ` + Promote the user in the chat. + +• `{i}demote ` + Demote the user in the chat. + +• `{i}ban ` + Ban the user from the chat. + +• `{i}unban ` + Unban the user from the chat. + +• `{i}kick ` + Kick the user from the chat. + +• `{i}pin ` + Pin the message in the chat. + +• `{i}unpin (all) ` + Unpin the message(s) in the chat. + +• `{i}purge ` + Purge all messages from the replied message. + +• `{i}purgeall ` + Delete all msgs of replied user. + Delete all msgs of input user + +• `{i}del ` + Delete the replied message. + +• `{i}edit ` + Edit your last message. +""" + +import asyncio + +from telethon.errors import BadRequestError +from telethon.errors.rpcerrorlist import UserIdInvalidError +from telethon.tl.functions.channels import EditAdminRequest, EditBannedRequest +from telethon.tl.types import ChatAdminRights, ChatBannedRights + +from . import * + + +@ultroid_cmd( + pattern="promote ?(.*)", + groups_only=True, +) +async def prmte(ult): + xx = await eor(ult, "`Processing...`") + chat = await ult.get_chat() + isAdmin = chat.admin_rights + isCreator = chat.creator + if not isAdmin and not isCreator: + return await xx.edit("`Hmm, I'm not an admin here...`") + await xx.edit("`Promoting...`") + user, rank = await get_user_info(ult) + if not rank: + rank = "Admin" + if not user: + return await xx.edit("`Reply to a user to promote him!`") + try: + await ultroid_bot( + EditAdminRequest( + ult.chat_id, + user.id, + ChatAdminRights( + add_admins=False, + invite_users=True, + change_info=False, + ban_users=True, + delete_messages=True, + pin_messages=True, + ), + rank, + ) + ) + await xx.edit( + f"[{user.first_name}](tg://user?id={user.id}) `is now an admin in {ult.chat.title} with title {rank}.`" + ) + except BadRequestError: + return await xx.edit("`I don't have the right to promote you.`") + await asyncio.sleep(5) + await xx.delete() + + +@ultroid_cmd( + pattern="demote ?(.*)", + groups_only=True, +) +async def dmote(ult): + xx = await eor(ult, "`Processing...`") + chat = await ult.get_chat() + isAdmin = chat.admin_rights + isCreator = chat.creator + if not isAdmin and not isCreator: + return await xx.edit("`Hmm, I'm not an admin here...`") + await xx.edit("`Demoting...`") + user, rank = await get_user_info(ult) + if not rank: + rank = "Not Admin" + if not user: + return await xx.edit("`Reply to a user to demote him!`") + try: + await ultroid_bot( + EditAdminRequest( + ult.chat_id, + user.id, + ChatAdminRights( + add_admins=None, + invite_users=None, + change_info=None, + ban_users=None, + delete_messages=None, + pin_messages=None, + ), + rank, + ) + ) + await xx.edit( + f"[{user.first_name}](tg://user?id={user.id}) `is no longer an admin in {ult.chat.title}`" + ) + except BadRequestError: + return await xx.edit("`I don't have the right to demote you.`") + await asyncio.sleep(5) + await xx.delete() + + +@ultroid_cmd( + pattern="ban ?(.*)", + groups_only=True, +) +async def bban(ult): + xx = await eor(ult, "`Processing...`") + chat = await ult.get_chat() + isAdmin = chat.admin_rights + isCreator = chat.creator + if not isAdmin and not isCreator: + return await xx.edit("`Hmm, I'm not an admin here...`") + user, reason = await get_user_info(ult) + if not user: + return await xx.edit("`Reply to a user or give username to ban him!`") + await xx.edit("`Getting user info...`") + try: + await ultroid_bot( + EditBannedRequest( + ult.chat_id, + user.id, + ChatBannedRights( + until_date=None, + view_messages=True, + send_messages=True, + send_media=True, + send_stickers=True, + send_gifs=True, + send_games=True, + send_inline=True, + embed_links=True, + ), + ) + ) + except BadRequestError: + return await xx.edit("`I don't have the right to ban a user.`") + except UserIdInvalidError: + await xx.edit("`I couldn't get who he is!`") + try: + reply = await ult.get_reply_message() + if reply: + await reply.delete() + except BadRequestError: + return await xx.edit( + f"[{user.first_name}](tg://user?id={user.id}) **was banned by** [{OWNER_NAME}](tg://user?id={OWNER_ID}) **in** `{ult.chat.title}`\n**Reason**: `{reason}`\n**Messages Deleted**: `False`" + ) + if reason: + await xx.edit( + f"[{user.first_name}](tg://user?id={user.id}) **was banned by** [{OWNER_NAME}](tg://user?id={OWNER_ID}) **in** `{ult.chat.title}`\n**Reason**: `{reason}`" + ) + else: + await xx.edit( + f"[{user.first_name}](tg://user?id={user.id}) **was banned by** [{OWNER_NAME}](tg://user?id={OWNER_ID}) **in** `{ult.chat.title}`" + ) + + +@ultroid_cmd( + pattern="unban ?(.*)", + groups_only=True, +) +async def uunban(ult): + xx = await eor(ult, "`Processing...`") + chat = await ult.get_chat() + isAdmin = chat.admin_rights + isCreator = chat.creator + if not isAdmin and not isCreator: + return await xx.edit("`Hmm, I'm not an admin here...`") + user, reason = await get_user_info(ult) + if not user: + return await xx.edit("`Reply to a user or give username to unban him!`") + await xx.edit("`Getting user info...`") + try: + await ultroid_bot( + EditBannedRequest( + ult.chat_id, + user.id, + ChatBannedRights( + until_date=None, + view_messages=None, + send_messages=None, + send_media=None, + send_stickers=None, + send_gifs=None, + send_games=None, + send_inline=None, + embed_links=None, + ), + ) + ) + except BadRequestError: + return await xx.edit("`I don't have the right to unban a user.`") + except UserIdInvalidError: + await xx.edit("`I couldn't get who he is!`") + if reason: + await xx.edit( + f"[{user.first_name}](tg://user?id={user.id}) **was unbanned by** [{OWNER_NAME}](tg://user?id={OWNER_ID}) **in** `{ult.chat.title}`\n**Reason**: `{reason}`" + ) + else: + await xx.edit( + f"[{user.first_name}](tg://user?id={user.id}) **was unbanned by** [{OWNER_NAME}](tg://user?id={OWNER_ID}) **in** `{ult.chat.title}`" + ) + + +@ultroid_cmd( + pattern="kick ?(.*)", + groups_only=True, +) +async def kck(ult): + xx = await eor(ult, "`Processing...`") + chat = await ult.get_chat() + isAdmin = chat.admin_rights + isCreator = chat.creator + if not isAdmin and not isCreator: + return await xx.edit("`Hmm, I'm not an admin here...`") + user, reason = await get_user_info(ult) + if not user: + return await xx.edit("`Kick? Whom? I couldn't get his info...`") + await xx.edit("`Kicking...`") + try: + await ultroid_bot.kick_participant(ult.chat_id, user.id) + await asyncio.sleep(0.5) + except BadRequestError: + return await xx.edit("`I don't have the right to kick a user.`") + except Exception as e: + return await xx.edit( + f"`I don't have the right to kick a user.`\n\n**ERROR**:\n`{str(e)}`" + ) + if reason: + await xx.edit( + f"[{user.first_name}](tg://user?id={user.id})` was kicked by` [{OWNER_NAME}](tg://user?id={OWNER_ID}) `in {ult.chat.title}`\n**Reason**: `{reason}`" + ) + else: + await xx.edit( + f"[{user.first_name}](tg://user?id={user.id})` was kicked by` [{OWNER_NAME}](tg://user?id={OWNER_ID}) `in {ult.chat.title}`" + ) + + +@ultroid_cmd( + pattern="pin($| (.*))", +) +async def pin(msg): + x = await eor(msg, "`Processing...`") + if not msg.is_private: + # for pin(s) in private messages + await msg.get_chat() + cht = await ultroid_bot.get_entity(msg.chat_id) + xx = msg.reply_to_msg_id + if not msg.is_reply: + return await x.edit("`Reply to a message to pin it.`") + ch = msg.pattern_match.group(1) + slnt = False + if ch == "loud": + slnt = True + try: + await ultroid_bot.pin_message(msg.chat_id, xx, notify=slnt) + except BadRequestError: + return await x.edit("`Hmm, I'm have no rights here...`") + except Exception as e: + return await x.edit(f"**ERROR:**`{str(e)}`") + await x.edit(f"`Pinned` [this message](https://t.me/c/{cht.id}/{xx})!") + + +@ultroid_cmd( + pattern="unpin($| (.*))", +) +async def unp(ult): + xx = await eor(ult, "`Processing...`") + if not ult.is_private: + # for (un)pin(s) in private messages + await ult.get_chat() + ch = (ult.pattern_match.group(1)).strip() + msg = ult.reply_to_msg_id + if msg and not ch: + try: + await ultroid_bot.unpin_message(ult.chat_id, msg) + except BadRequestError: + return await xx.edit("`Hmm, I'm have no rights here...`") + except Exception as e: + return await xx.edit(f"**ERROR:**\n`{str(e)}`") + elif ch == "all": + try: + await ultroid_bot.unpin_message(ult.chat_id) + except BadRequestError: + return await xx.edit("`Hmm, I'm have no rights here...`") + except Exception as e: + return await xx.edit(f"**ERROR:**`{str(e)}`") + else: + return await xx.edit(f"Either reply to a message, or, use `{hndlr}unpin all`") + if not msg and ch != "all": + return await xx.edit(f"Either reply to a message, or, use `{hndlr}unpin all`") + await xx.edit("`Unpinned!`") + + +@ultroid_cmd( + pattern="purge$", +) +async def fastpurger(purg): + chat = await purg.get_input_chat() + msgs = [] + count = 0 + if not purg.reply_to_msg_id: + return await eod(purg, "`Reply to a message to purge from.`", time=10) + async for msg in ultroid_bot.iter_messages(chat, min_id=purg.reply_to_msg_id): + msgs.append(msg) + count = count + 1 + msgs.append(purg.reply_to_msg_id) + if len(msgs) == 100: + await ultroid_bot.delete_messages(chat, msgs) + msgs = [] + + if msgs: + await ultroid_bot.delete_messages(chat, msgs) + done = await ultroid_bot.send_message( + purg.chat_id, + "__Fast purge complete!__\n**Purged** `" + str(count) + "` **messages.**", + ) + await asyncio.sleep(5) + await done.delete() + + +@ultroid_cmd( + pattern="purgeall ?(.*)", +) +async def _(e): + input = e.pattern_match.group(1) + xx = await eor(e, "`Processing...`") + if e.reply_to_msg_id: + input = (await e.get_reply_message()).sender_id + if input: + try: + nos = 0 + async for x in e.client.iter_messages(e.chat_id, from_user=input): + await e.client.delete_messages(e.chat_id, x) + nos += 1 + await e.client.send_message( + e.chat_id, f"**Purged {nos} msgs of {input} from here**" + ) + except ValueError: + return await eod(xx, str(er), time=5) + else: + return await eod( + xx, + "Reply to someone's msg or give their id to delete all msgs from this chat", + time=10, + ) + + +@ultroid_cmd( + pattern="del$", +) +async def delete_it(delme): + msg_src = await delme.get_reply_message() + if delme.reply_to_msg_id: + try: + await msg_src.delete() + await delme.delete() + except BaseException: + await eod( + delme, + f"Couldn't delete the message.\n\n**ERROR:**\n`{str(e)}`", + time=10, + ) + + +@ultroid_cmd( + pattern="edit", +) +async def editer(edit): + message = edit.text + chat = await edit.get_input_chat() + self_id = await ultroid_bot.get_peer_id("me") + string = str(message[6:]) + i = 1 + async for message in ultroid_bot.iter_messages(chat, self_id): + if i == 2: + await message.edit(string) + await edit.delete() + break + i = i + 1 + + +HELP.update({f"{__name__.split('.')[1]}": f"{__doc__.format(i=Var.HNDLR)}"}) diff --git a/plugins/afk.py b/plugins/afk.py new file mode 100644 index 0000000000..fe0b872382 --- /dev/null +++ b/plugins/afk.py @@ -0,0 +1,252 @@ +# Ultroid - UserBot +# Copyright (C) 2020 TeamUltroid +# +# This file is a part of < https://github.com/TeamUltroid/Ultroid/ > +# PLease read the GNU Affero General Public License in +# . + +""" +✘ Commands Available - + +• `{i}afk ` + afk means away from keyboard, + After u active this if Someting tag or msg u then It auto Reply Him/her, + (Note : By Reply To any media U can set media afk too). + +""" + +import asyncio +from datetime import datetime + +from telethon import events +from telethon.tl import functions, types + +from . import * + +global USER_AFK +global afk_time +global last_afk_message +global last_afk_msg +global afk_start +global afk_end +USER_AFK = {} +afk_time = None +last_afk_message = {} +last_afk_msg = {} +afk_start = {} + +LOG = Var.LOG_CHANNEL + + +@ultroid_bot.on(events.NewMessage(outgoing=True)) +@ultroid_bot.on(events.MessageEdited(outgoing=True)) +async def set_not_afk(event): + global USER_AFK + global afk_time + global last_afk_message + global afk_start + global afk_end + back_alive = datetime.now() + afk_end = back_alive.replace(microsecond=0) + if afk_start != {}: + total_afk_time = str((afk_end - afk_start)) + current_message = event.message.message + if "afk" not in current_message and "yes" in USER_AFK: + try: + if pic.endswith((".tgs", ".webp")): + shite = await ultroid_bot.send_message(event.chat_id, file=pic) + shites = await ultroid_bot.send_message( + event.chat_id, + "`No Longer Afk`\n\nWas afk for~`" + total_afk_time + "`", + ) + else: + shite = await ultroid_bot.send_message( + event.chat_id, + "`No Longer Afk`\n\nWas afk for~`" + total_afk_time + "`", + file=pic, + ) + except BaseException: + shite = await ultroid_bot.send_message( + event.chat_id, "`No Longer Afk`\nWas afk for" + total_afk_time + "`" + ) + try: + try: + if pic.endswith((".tgs", ".webp")): + await ultroid_bot.send_message(LOG, file=pic) + await ultroid_bot.send_message( + LOG, + "#AFKFALSE \nSet AFK mode to False\n" + + "Back alive!\nNo Longer afk.\n Was afk for`" + + total_afk_time + + "`", + ) + else: + await ultroid_bot.send_message( + LOG, + "#AFKFALSE \nSet AFK mode to False\n" + + "Back alive!\nNo Longer afk.\n Was afk for`" + + total_afk_time + + "`", + file=pic, + ) + except BaseException: + await ultroid_bot.send_message( + LOG, + "#AFKFALSE \nSet AFK mode to False\n" + + "Back alive!\nNo Longer afk.\n Was afk for`" + + total_afk_time + + "`", + ) + except BaseException: + pass + await asyncio.sleep(3) + await shite.delete() + try: + await shites.delete() + except BaseException: + pass + USER_AFK = {} + afk_time = None + + +@ultroid_bot.on( + events.NewMessage(incoming=True, func=lambda e: bool(e.mentioned or e.is_private)) +) +async def on_afk(event): + if event.fwd_from: + return + global USER_AFK + global afk_time + global last_afk_message + global afk_start + global afk_end + back_alivee = datetime.now() + afk_end = back_alivee.replace(microsecond=0) + if afk_start != {}: + total_afk_time = str((afk_end - afk_start)) + current_message_text = event.message.message.lower() + if "afk" in current_message_text: + return False + if USER_AFK and not (await event.get_sender()).bot: + msg = None + if reason: + message_to_reply = ( + f"__Master #AFK since__ `{total_afk_time}`\n\n" + + f"__" + + f"\n\n**Reason:- **{reason}" + ) + else: + message_to_reply = f"__Master #AFK since__ `{total_afk_time}`\n\n" + f"__" + try: + if pic.endswith((".tgs", ".webp")): + msg = await event.reply(file=pic) + msgs = await event.reply(message_to_reply) + else: + msg = await event.reply(message_to_reply, file=pic) + except BaseException: + msg = await event.reply(message_to_reply) + await asyncio.sleep(2.5) + if event.chat_id in last_afk_message: + await last_afk_message[event.chat_id].delete() + try: + if event.chat_id in last_afk_msg: + await last_afk_msg[event.chat_id].delete() + except BaseException: + pass + last_afk_message[event.chat_id] = msg + try: + if msgs: + last_afk_msg[event.chat_id] = msgs + except BaseException: + pass + + +@ultroid_cmd(pattern=r"afk ?(.*)") +async def _(event): + if event.fwd_from: + return + reply = await event.get_reply_message() + global USER_AFK + global afk_time + global last_afk_message + global last_afk_msg + global afk_start + global afk_end + global reason + global pic + USER_AFK = {} + afk_time = None + last_afk_message = {} + last_afk_msg = {} + afk_end = {} + start_1 = datetime.now() + afk_start = start_1.replace(microsecond=0) + reason = event.pattern_match.group(1) + if reply: + pic = await event.client.download_media(reply) + else: + pic = None + if not USER_AFK: + last_seen_status = await ultroid_bot( + functions.account.GetPrivacyRequest(types.InputPrivacyKeyStatusTimestamp()) + ) + if isinstance(last_seen_status.rules, types.PrivacyValueAllowAll): + afk_time = datetime.datetime.now() + USER_AFK = f"yes: {reason} {pic}" + if reason: + try: + if pic.endswith((".tgs", ".webp")): + await ultroid_bot.send_message(event.chat_id, file=pic) + await ultroid_bot.send_message( + event.chat_id, f"Afk __because ~ {reason}__" + ) + else: + await ultroid_bot.send_message( + event.chat_id, f"Afk __because ~ {reason}__", file=pic + ) + except BaseException: + await ultroid_bot.send_message( + event.chat_id, f"Afk __because ~ {reason}__" + ) + else: + try: + if pic.endswith((".tgs", ".webp")): + await ultroid_bot.send_message(event.chat_id, file=pic) + await ultroid_bot.send_message( + event.chat_id, f"**I am Going afk!**" + ) + else: + await ultroid_bot.send_message( + event.chat_id, f"**I am Going afk!**", file=pic + ) + except BaseException: + await ultroid_bot.send_message(event.chat_id, f"**I am Going afk!**") + await event.delete() + try: + if reason and pic: + if pic.endswith((".tgs", ".webp")): + await ultroid_bot.send_message(LOG, file=pic) + await ultroid_bot.send_message( + LOG, f"AFK mode to On and Reason is {reason}" + ) + else: + await ultroid_bot.send_message( + LOG, f"AFK mode to On and Reason is {reason}", file=pic + ) + elif reason: + await ultroid_bot.send_message( + LOG, f"AFK mode to On and Reason is {reason}" + ) + elif pic: + if pic.endswith((".tgs", ".webp")): + await ultroid_bot.send_message(LOG, file=pic) + await ultroid_bot.send_message(LOG, f"AFK mode to On") + else: + await ultroid_bot.send_message(LOG, f"AFK mode to On", file=pic) + else: + await ultroid_bot.send_message(LOG, f"AFK mode to On") + except Exception as e: + logger.warn(str(e)) + + +HELP.update({f"{__name__.split('.')[1]}": f"{__doc__.format(i=Var.HNDLR)}"}) diff --git a/plugins/bot.py b/plugins/bot.py new file mode 100644 index 0000000000..56b173963f --- /dev/null +++ b/plugins/bot.py @@ -0,0 +1,232 @@ +# Ultroid - UserBot +# Copyright (C) 2020 TeamUltroid +# +# This file is a part of < https://github.com/TeamUltroid/Ultroid/ > +# PLease read the GNU Affero General Public License in +# . + +""" +✘ Commands Available + +• `{i}alive` + Check if your bot is working. + +• `{i}ping` + Check Ultroid's response time. + +• `{i}cmds` + View all plugin names. + +• `{i}restart` + To restart your bot. + +• `{i}logs` + Get the last 100 lines from heroku logs. + +• `{i}usage` + Get app usage details. + +• `{i}shutdown` + Turn off your bot. +""" + +import asyncio +import math +import os +import shutil +import time +from datetime import datetime as dt +from platform import python_version as pyver + +import heroku3 +import psutil +import requests +from git import Repo +from telethon import __version__ + +from . import * + +HEROKU_API = None +HEROKU_APP_NAME = None + +try: + if Var.HEROKU_API and Var.HEROKU_APP_NAME: + HEROKU_API = Var.HEROKU_API + HEROKU_APP_NAME = Var.HEROKU_APP_NAME + Heroku = heroku3.from_key(Var.HEROKU_API) + heroku_api = "https://api.heroku.com" + app = Heroku.app(Var.HEROKU_APP_NAME) +except BaseException: + HEROKU_API = None + HEROKU_APP_NAME = None + + +@ultroid_cmd( + pattern="alive$", +) +async def lol(ult): + pic = udB.get("ALIVE_PIC") + uptime = grt((time.time() - start_time)) + header = udB.get("ALIVE_TEXT") if udB.get("ALIVE_TEXT") else "Hey, I am alive." + als = """ +**The Ultroid Userbot...** + +**{}** + +✵ **Owner** - `{}` +✵ **Ultroid** - `{}` +✵ **UpTime** - `{}` +✵ **Python** - `{}` +✵ **Telethon** - `{}` +✵ **Branch** - `{}` +""".format( + header, + OWNER_NAME, + ultroid_version, + uptime, + pyver(), + __version__, + Repo().active_branch, + ) + if pic is None: + await ult.edit(als) + elif pic is not None and "telegra" in pic: + await ult.delete() + await ult.reply(als, file=pic) + else: + await ult.delete() + await ultroid_bot.send_message(ult.chat_id, file=pic) + await ultroid_bot.send_message(ult.chat_id, als) + + +@ultroid_cmd( + pattern="ping$", +) +async def _(event): + start = dt.now() + x = await eor(event, "`Pong !`") + if event.fwd_from: + return + end = dt.now() + ms = (end - start).microseconds / 1000 + uptime = grt((time.time() - start_time)) + await x.edit(f"**Pong !!** `{ms}ms`\n**Uptime** - `{uptime}`") + + +@ultroid_cmd( + pattern="cmds$", +) +async def cmds(event): + await allcmds(event) + + +@ultroid_cmd( + pattern="restart$", +) +async def restartbt(ult): + await restart(ult) + + +@ultroid_cmd( + pattern="logs$", +) +async def _(ult): + xx = await eor(ult, "`Processing...`") + if HEROKU_API is None and HEROKU_APP_NAME is None: + return await xx.edit("Please set `HEROKU_APP_NAME` and `HEROKU_API` in vars.") + await xx.edit("`Downloading Logs...`") + with open("logs-ultroid.txt", "w") as log: + log.write(app.get_log()) + ok = app.get_log() + message = ok + url = "https://del.dog/documents" + r = requests.post(url, data=message.encode("UTF-8")).json() + url = f"https://del.dog/{r['key']}" + await ult.client.send_file( + ult.chat_id, + "logs-ultroid.txt", + reply_to=ult.id, + caption=f"**Heroku** Ultroid Logs.\nPasted [here]({url}) too!", + ) + await xx.edit("`Uploading...`") + await asyncio.sleep(1) + await xx.delete() + return os.remove("logs-ultroid.txt") + + +@ultroid_cmd( + pattern="usage$", +) +async def dyno_usage(dyno): + dyn = await eor(dyno, "`Processing...`") + useragent = ( + "Mozilla/5.0 (Linux; Android 10; SM-G975F) " + "AppleWebKit/537.36 (KHTML, like Gecko) " + "Chrome/80.0.3987.149 Mobile Safari/537.36" + ) + user_id = Heroku.account().id + headers = { + "User-Agent": useragent, + "Authorization": f"Bearer {Var.HEROKU_API}", + "Accept": "application/vnd.heroku+json; version=3.account-quotas", + } + path = "/accounts/" + user_id + "/actions/get-quota" + r = requests.get(heroku_api + path, headers=headers) + if r.status_code != 200: + return await dyno.edit( + "`Error: something bad happened`\n\n" f">.`{r.reason}`\n" + ) + result = r.json() + quota = result["account_quota"] + quota_used = result["quota_used"] + remaining_quota = quota - quota_used + percentage = math.floor(remaining_quota / quota * 100) + minutes_remaining = remaining_quota / 60 + hours = math.floor(minutes_remaining / 60) + minutes = math.floor(minutes_remaining % 60) + App = result["apps"] + try: + App[0]["quota_used"] + except IndexError: + AppQuotaUsed = 0 + AppPercentage = 0 + else: + AppQuotaUsed = App[0]["quota_used"] / 60 + AppPercentage = math.floor(App[0]["quota_used"] * 100 / quota) + AppHours = math.floor(AppQuotaUsed / 60) + AppMinutes = math.floor(AppQuotaUsed % 60) + total, used, free = shutil.disk_usage(".") + cpuUsage = psutil.cpu_percent() + memory = psutil.virtual_memory().percent + disk = psutil.disk_usage("/").percent + upload = humanbytes(psutil.net_io_counters().bytes_sent) + down = humanbytes(psutil.net_io_counters().bytes_recv) + TOTAL = humanbytes(total) + USED = humanbytes(used) + FREE = humanbytes(free) + return await eod( + dyn, + "**⚙️ Dyno Usage ⚙️**:\n\n" + + f" -> `Dyno usage for` **{Var.HEROKU_APP_NAME}**:\n" + + f" • `{AppHours}`**h** `{AppMinutes}`**m** " + + f"**|** [`{AppPercentage}`**%**]" + + "\n\n" + + " -> `Dyno hours quota remaining this month`:\n" + + f" • `{hours}`**h** `{minutes}`**m** " + + f"**|** [`{percentage}`**%**]\n\n" + + f"**Total Disk Space: {TOTAL}\n\n**" + + f"**Used: {USED} Free: {FREE}\n\n**" + + f"**📊Data Usage📊\n\nUpload: {upload}\nDown: {down}\n\n**" + + f"**CPU: {cpuUsage}%\nRAM: {memory}%\nDISK: {disk}%**", + ) + + +@ultroid_cmd( + pattern="shutdown$", +) +async def shht(event): + await eor(event, "GoodBye {}.\n`Shutting down...`".format(OWNER_NAME)) + await ultroid_bot.disconnect() + + +HELP.update({f"{__name__.split('.')[1]}": f"{__doc__.format(i=Var.HNDLR)}"}) diff --git a/plugins/carbon.py b/plugins/carbon.py new file mode 100644 index 0000000000..e6c336996c --- /dev/null +++ b/plugins/carbon.py @@ -0,0 +1,235 @@ +# Ultroid - UserBot +# Copyright (C) 2020 TeamUltroid +# +# This file is a part of < https://github.com/TeamUltroid/Ultroid/ > +# PLease read the GNU Affero General Public License in +# . + +""" +✘ Commands Available - + +• `{i}carbon ` + Carbonise the text with default settings. +• `{i}rcarbon ` + Carbonise the text, with random bg colours. +""" + +import os +import random + +from carbonnow import Carbon + +from . import * + +all_col = [ + "Black", + "Navy", + "DarkBlue", + "MediumBlue", + "Blue", + "DarkGreen", + "Green", + "Teal", + "DarkCyan", + "DeepSkyBlue", + "DarkTurquoise", + "MediumSpringGreen", + "Lime", + "SpringGreen", + "Aqua", + "Cyan", + "MidnightBlue", + "DodgerBlue", + "LightSeaGreen", + "ForestGreen", + "SeaGreen", + "DarkSlateGray", + "DarkSlateGrey", + "LimeGreen", + "MediumSeaGreen", + "Turquoise", + "RoyalBlue", + "SteelBlue", + "DarkSlateBlue", + "MediumTurquoise", + "Indigo ", + "DarkOliveGreen", + "CadetBlue", + "CornflowerBlue", + "RebeccaPurple", + "MediumAquaMarine", + "DimGray", + "DimGrey", + "SlateBlue", + "OliveDrab", + "SlateGray", + "SlateGrey", + "LightSlateGray", + "LightSlateGrey", + "MediumSlateBlue", + "LawnGreen", + "Chartreuse", + "Aquamarine", + "Maroon", + "Purple", + "Olive", + "Gray", + "Grey", + "SkyBlue", + "LightSkyBlue", + "BlueViolet", + "DarkRed", + "DarkMagenta", + "SaddleBrown", + "DarkSeaGreen", + "LightGreen", + "MediumPurple", + "DarkViolet", + "PaleGreen", + "DarkOrchid", + "YellowGreen", + "Sienna", + "Brown", + "DarkGray", + "DarkGrey", + "LightBlue", + "GreenYellow", + "PaleTurquoise", + "LightSteelBlue", + "PowderBlue", + "FireBrick", + "DarkGoldenRod", + "MediumOrchid", + "RosyBrown", + "DarkKhaki", + "Silver", + "MediumVioletRed", + "IndianRed ", + "Peru", + "Chocolate", + "Tan", + "LightGray", + "LightGrey", + "Thistle", + "Orchid", + "GoldenRod", + "PaleVioletRed", + "Crimson", + "Gainsboro", + "Plum", + "BurlyWood", + "LightCyan", + "Lavender", + "DarkSalmon", + "Violet", + "PaleGoldenRod", + "LightCoral", + "Khaki", + "AliceBlue", + "HoneyDew", + "Azure", + "SandyBrown", + "Wheat", + "Beige", + "WhiteSmoke", + "MintCream", + "GhostWhite", + "Salmon", + "AntiqueWhite", + "Linen", + "LightGoldenRodYellow", + "OldLace", + "Red", + "Fuchsia", + "Magenta", + "DeepPink", + "OrangeRed", + "Tomato", + "HotPink", + "Coral", + "DarkOrange", + "LightSalmon", + "Orange", + "LightPink", + "Pink", + "Gold", + "PeachPuff", + "NavajoWhite", + "Moccasin", + "Bisque", + "MistyRose", + "BlanchedAlmond", + "PapayaWhip", + "LavenderBlush", + "SeaShell", + "Cornsilk", + "LemonChiffon", + "FloralWhite", + "Snow", + "Yellow", + "LightYellow", + "Ivory", + "White", +] + + +@ultroid_cmd( + pattern="carbon", +) +async def crbn(event): + xxxx = await eor(event, "Processing") + if event.reply_to_msg_id: + temp = await event.get_reply_message() + if temp.media: + b = await ultroid_bot.download_media(temp) + a = open(b, "r") + code = a.read() + a.close() + os.remove(b) + else: + code = temp.message + else: + code = event.text.split(" ", maxsplit=1)[1] + carbon = Carbon(code=code) + xx = await carbon.save("ultroid_carbon") + await xxxx.delete() + await ultroid_bot.send_file( + event.chat_id, + xx, + caption=f"Carbonised by [{OWNER_NAME}](tg://user?id={OWNER_ID})", + force_document=True, + ) + os.remove(xx) + + +@ultroid_cmd( + pattern="rcarbon", +) +async def crbn(event): + xxxx = await eor(event, "Processing") + if event.reply_to_msg_id: + temp = await event.get_reply_message() + if temp.media: + b = await ultroid_bot.download_media(temp) + a = open(b, "r") + code = a.read() + a.close() + os.remove(b) + else: + code = temp.message + else: + code = event.text.split(" ", maxsplit=1)[1] + col = random.choice(all_col) + carbon = Carbon(code=code, background=col) + xx = await carbon.save("ultroid_carbon") + await xxxx.delete() + await ultroid_bot.send_file( + event.chat_id, + xx, + caption=f"Carbonised by [{OWNER_NAME}](tg://user?id={OWNER_ID})", + force_document=True, + ) + os.remove(xx) + + +HELP.update({f"{__name__.split('.')[1]}": f"{__doc__.format(i=Var.HNDLR)}"}) diff --git a/plugins/chats.py b/plugins/chats.py new file mode 100644 index 0000000000..f0a57d060c --- /dev/null +++ b/plugins/chats.py @@ -0,0 +1,117 @@ +# Ultroid - UserBot +# Copyright (C) 2020 TeamUltroid +# +# This file is a part of < https://github.com/TeamUltroid/Ultroid/ > +# PLease read the GNU Affero General Public License in +# . + +""" +✘ Commands Available - + +• `{i}delchat` + Delete the group this cmd is used in. + +• `{i}getlink` + Get link of group this cmd is used in. + +• `{i}create (b|g|c) ` + Create group woth a specific name. + b - megagroup/supergroup + g - small group + c - channel +""" + + +from telethon.errors import ChatAdminRequiredError as no_admin +from telethon.tl import functions + +from . import * + + +@ultroid_cmd( + pattern="delchat$", + groups_only=True, +) +async def _(e): + xx = await eor(e, "`Processing...`") + try: + await e.client(functions.channels.DeleteChannelRequest(e.chat_id)) + except TypeError: + return await eod(xx, "`Cant delete this chat`", time=10) + except no_admin: + return await eod(xx, "`I m not an admin`", time=10) + await e.client.send_message(Var.LOG_CHANNEL, f"#Deleted\nDeleted {e.chat_id}") + + +@ultroid_cmd( + pattern="getlink$", + groups_only=True, +) +async def _(e): + xx = await eor(e, "`Processing...`") + try: + r = await e.client( + functions.messages.ExportChatInviteRequest(e.chat_id), + ) + except no_admin: + return await eod(xx, "`I m not an admin`", time=10) + await eod(xx, f"Link:- {r.link}") + + +@ultroid_cmd( + pattern="create (b|g|c)(?: |$)(.*)", +) +async def _(e): + type_of_group = e.pattern_match.group(1) + group_name = e.pattern_match.group(2) + xx = await eor(e, "`Processing...`") + if type_of_group == "b": + try: + r = await e.client( + functions.messages.CreateChatRequest( + users=["@missrose_bot"], + title=group_name, + ) + ) + created_chat_id = r.chats[0].id + await e.client( + functions.messages.DeleteChatUserRequest( + chat_id=created_chat_id, + user_id="@missrose_bot", + ) + ) + result = await e.client( + functions.messages.ExportChatInviteRequest( + peer=created_chat_id, + ) + ) + await xx.edit( + f"Your [{group_name}]({result.link}) Group Made Boss!", + link_preview=False, + ) + except Exception as ex: + await xx.edit(str(ex)) + elif type_of_group == "g" or type_of_group == "c": + try: + r = await e.client( + functions.channels.CreateChannelRequest( + title=group_name, + about="Join @TeamUltroid", + megagroup=False if type_of_group == "c" else True, + ) + ) + created_chat_id = r.chats[0].id + result = await e.client( + functions.messages.ExportChatInviteRequest( + peer=created_chat_id, + ) + ) + await xx.edit( + f"Your [{group_name}]({result.link}) Group/Channel Has been made Boss!", + link_preview=False, + ) + except Exception as ex: + await xx.edit(str(ex)) + + +HELP.update({f"{__name__.split('.')[1]}": f"{__doc__.format(i=Var.HNDLR)}"}) diff --git a/plugins/core.py b/plugins/core.py new file mode 100644 index 0000000000..d068598299 --- /dev/null +++ b/plugins/core.py @@ -0,0 +1,175 @@ +# Ultroid - UserBot +# Copyright (C) 2020 TeamUltroid +# +# This file is a part of < https://github.com/TeamUltroid/Ultroid/ > +# PLease read the GNU Affero General Public License in +# . + +""" +✘ Commands Available - + +• `{i}install ` + To install the plugin. + +• `{i}uninstall ` + To unload and remove the plugin. + +• `{i}load ` + To load unloaded unofficial plugin. + +• `{i}unload ` + To unload unofficial plugin. + +• `{i}help ` + Shows you a help menu (like this) for every plugin. +""" + +import os + +from telethon.tl.custom import Button + +from . import * + + +@in_pattern( + "send (.*)", +) +@in_owner +async def inline_handler(event): + builder = event.builder + input_str = event.pattern_match.group(1) + plug = [*PLUGINS] + plugs = [] + if input_str == "all": + for i in plug: + try: + plugs.append( + await event.builder.document( + f"./plugins/{i}.py", + title=f"{i}.py", + description=f"Module Found", + text=f"{i}.py use .paste to paste in neko and raw..", + buttons=[ + [ + Button.switch_inline( + "Search Again..?", query="send all", same_peer=True + ) + ] + ], + ) + ) + except BaseException: + pass + await event.answer(plugs) + else: + try: + ultroid = builder.document( + f"./plugins/{input_str}.py", + title=f"{input_str}.py", + description=f"Module {input_str} Found", + text=f"{input_str}.py use .paste to paste in neko and raw..", + buttons=[ + [ + Button.switch_inline( + "Search Again..?", query="send ", same_peer=True + ) + ] + ], + ) + await event.answer([ultroid]) + return + except BaseException: + ultroidcode = builder.article( + title=f"Module {input_str}.py Not Found", + description=f"No Such Module", + text=f"No Module Named {input_str}.py", + buttons=[ + [ + Button.switch_inline( + "Search Again", query="send ", same_peer=True + ) + ] + ], + ) + await event.answer([ultroidcode]) + return + + +@ultroid_cmd( + pattern="install$", +) +async def install(event): + await safeinstall(event) + + +@ultroid_cmd( + pattern=r"unload (?P\w+)$", +) +async def unload(event): + shortname = event.pattern_match["shortname"] + if not shortname: + await eor(event, "`Give name of plugin which u want to unload`") + return + lsd = os.listdir("addons") + lst = os.listdir("plugins") + zym = shortname + ".py" + if zym in lsd: + try: + un_plug(shortname) + await eod(event, f"**Uɴʟᴏᴀᴅᴇᴅ** `{shortname}` **Sᴜᴄᴄᴇssғᴜʟʟʏ.**", time=3) + except BaseException: + pass + elif zym in lst: + return await eod(event, "**Yᴏᴜ Cᴀɴ'ᴛ Uɴʟᴏᴀᴅ Oғғɪᴄɪᴀʟ Pʟᴜɢɪɴs**", time=3) + else: + return await eod(event, f"**Nᴏ Pʟᴜɢɪɴ Nᴀᴍᴇᴅ** `{shortname}`", time=3) + + +@ultroid_cmd( + pattern=r"uninstall (?P\w+)$", +) +async def uninstall(event): + shortname = event.pattern_match["shortname"] + if not shortname: + await eor(event, "`Give name of plugin which u want to uninstall`") + return + lsd = os.listdir("addons") + lst = os.listdir("plugins") + zym = shortname + ".py" + if zym in lsd: + try: + un_plug(shortname) + await eod(event, f"**Uɴɪɴsᴛᴀʟʟᴇᴅ** `{shortname}` **Sᴜᴄᴄᴇssғᴜʟʟʏ.**", time=3) + os.remove(f"addons/{shortname}.py") + except BaseException: + pass + elif zym in lst: + return await eod(event, "**Yᴏᴜ Cᴀɴ'ᴛ Uɴɪɴsᴛᴀʟʟ Oғғɪᴄɪᴀʟ Pʟᴜɢɪɴs**", time=3) + else: + return await eod(event, f"**Nᴏ Pʟᴜɢɪɴ Nᴀᴍᴇᴅ** `{shortname}`", time=3) + + +@ultroid_cmd( + pattern=r"load (?P\w+)$", +) +async def load(event): + shortname = event.pattern_match["shortname"] + if not shortname: + await eor(event, "`Give name of plugin which u want to load`") + return + try: + try: + un_plug(shortname) + except BaseException: + pass + load_addons(shortname) + await eod(event, f"**Sᴜᴄᴄᴇssғᴜʟʟʏ Lᴏᴀᴅᴇᴅ** `{shortname}`", time=3) + except Exception as e: + await eod( + event, + f"**Could not load** `{shortname}` **because of the following error.**\n`{str(e)}`", + time=3, + ) + + +HELP.update({f"{__name__.split('.')[1]}": f"{__doc__.format(i=Var.HNDLR)}"}) diff --git a/plugins/github.py b/plugins/github.py new file mode 100644 index 0000000000..3ad0a82dc6 --- /dev/null +++ b/plugins/github.py @@ -0,0 +1,70 @@ +# Ultroid - UserBot +# Copyright (C) 2020 TeamUltroid +# +# This file is a part of < https://github.com/TeamUltroid/Ultroid/ > +# PLease read the GNU Affero General Public License in +# . + +""" +✘ Commands Available - + +• `{i}github ` + Get full information of the users github profile. +""" + + +import requests + +from . import * + + +@ultroid_cmd( + pattern="github (.*)", +) +async def gitsearch(event): + xx = await eor(event, "`Searching...`") + try: + usrname = event.pattern_match.group(1) + except BaseException: + return await xx.edit("`Search for whom? Give me a user name!!`") + url = f"https://api.github.com/users/{usrname}" + ult = requests.get(url).json() + try: + uname = ult["login"] + uid = ult["id"] + upic = ult["avatar_url"] + ulink = ult["html_url"] + uacc = ult["name"] + ucomp = ult["company"] + ublog = ult["blog"] + ulocation = ult["location"] + ubio = ult["bio"] + urepos = ult["public_repos"] + ufollowers = ult["followers"] + ufollowing = ult["following"] + except BaseException: + return await xx.edit("`No such user found...`") + fullusr = f""" +**[GITHUB]({ulink})** + +**Name** - {uacc} +**UserName** - {uname} +**ID** - {uid} +**Company** - {ucomp} +**Blog** - {ublog} +**Location** - {ulocation} +**Bio** - {ubio} +**Repos** - {urepos} +**Followers** - {ufollowers} +**Following** - {ufollowing} +""" + await xx.delete() + await ultroid_bot.send_file( + event.chat_id, + upic, + caption=fullusr, + link_preview=False, + ) + + +HELP.update({f"{__name__.split('.')[1]}": f"{__doc__.format(i=Var.HNDLR)}"}) diff --git a/plugins/google.py b/plugins/google.py new file mode 100644 index 0000000000..057433320a --- /dev/null +++ b/plugins/google.py @@ -0,0 +1,120 @@ +# Ultroid - UserBot +# Copyright (C) 2020 TeamUltroid +# +# This file is a part of < https://github.com/TeamUltroid/Ultroid/ > +# PLease read the GNU Affero General Public License in +# . + +""" +✘ Commands Available - + +• `{i}google ` + For doing google search. + +• `{i}img ` + For doing Images search. + +• `{i}reverse ` + Reply an Image or sticker to find its sauce. +""" + +import os +from shutil import rmtree + +import requests +from bs4 import BeautifulSoup as bs +from PIL import Image +from search_engine_parser import * + +from . import * + + +@ultroid_cmd(pattern="google ?(.*)") +async def google(event): + inp = event.pattern_match.group(1) + if not inp: + return await event.edit("Give something to search") + x = await eor(event, "`searching..`") + gs = GoogleSearch() + res = await gs.async_search(f"{inp}") + out = "" + for i in range(len(res["links"])): + text = res["titles"][i] + url = res["links"][i] + des = res["descriptions"][i] + out += f" 👉🏻 [{text}]({url})\n`{des}`\n\n" + await x.edit( + f"**Google Search Query:**\n`{inp}`\n\n**Results:**\n{out}", link_preview=False + ) + + +@ultroid_cmd(pattern="img ?(.*)") +async def goimg(event): + query = event.pattern_match.group(1) + if not query: + return await eor(event, "`Give something to search") + nn = await eor(event, "`Processing Keep Patience...`") + if ";" in query: + try: + lmt = int(query.split(";")[1]) + except BaseExceptaion: + lmt = 5 + else: + lmt = 5 + gi = googleimagesdownload() + args = { + "keywords": query, + "limit": lmt, + "format": "jpg", + "output_directory": "./resources/downloads/", + } + pth = gi.download(args) + ok = pth[0][query] + await event.client.send_file(event.chat_id, ok, album=True) + rmtree(f"./resources/downloads/{query}/") + await nn.delete() + + +@ultroid_cmd(pattern="reverse") +async def reverse(event): + reply = await event.get_reply_message() + if not reply: + return await eor(event, "`Reply to any Image`") + ult = await eor(event, "`Processing...`") + dl = await bot.download_media(reply) + img = Image.open(dl) + x, y = img.size + file = {"encoded_image": (dl, open(dl, "rb"))} + grs = requests.post( + "https://www.google.com/searchbyimage/upload", files=file, allow_redirects=False + ) + loc = grs.headers.get("Location") + response = requests.get( + loc, + headers={ + "User-Agent": "Mozilla/5.0 (X11; Linux x86_64; rv:58.0) Gecko/20100101 Firefox/58.0" + }, + ) + xx = bs(response.text, "html.parser") + div = xx.find("div", {"class": "r5a77d"}) + alls = div.find("a") + link = alls["href"] + text = alls.text + await ult.edit(f"`Dimension ~ {x} : {y}`\nSauce ~ [{text}](google.com{link})") + gi = googleimagesdownload() + args = { + "keywords": text, + "limit": 2, + "format": "jpg", + "output_directory": "./resources/downloads/", + } + pth = gi.download(args) + ok = pth[0][text] + await event.client.send_file( + event.chat_id, ok, album=True, caption="Similar Images Realted to Search" + ) + rmtree(f"./resources/downloads/{text}/") + os.remove(dl) + + +HELP.update({f"{__name__.split('.')[1]}": f"{__doc__.format(i=Var.HNDLR)}"}) diff --git a/plugins/imagetools.py b/plugins/imagetools.py new file mode 100644 index 0000000000..81150ad0af --- /dev/null +++ b/plugins/imagetools.py @@ -0,0 +1,468 @@ +# Ultroid - UserBot +# Copyright (C) 2020 TeamUltroid +# +# This file is a part of < https://github.com/TeamUltroid/Ultroid/ > +# PLease read the GNU Affero General Public License in +# . + +""" +✘ Commands Available - + +• `{i}toon ` + To make it toon. + +• `{i}danger ` + To make it look Danger. + +• `{i}grey ` + To make it black nd white. + +• `{i}negative ` + To make negative image. + +• `{i}blur ` + To make it blurry. + +• `{i}quad ` + create a Vortex. + +• `{i}mirror ` + To create mirror pic. + +• `{i}flip ` + To make it flip. + +• `{i}sketch ` + To draw its sketch. + +• `{i}blue ` + just cool. +""" + +import asyncio +import os + +import cv2 +import numpy as np +from PIL import Image +from telegraph import upload_file as upf +from validators.url import url + +from . import * + + +@ultroid_cmd( + pattern="sketch$", +) +async def sketch(e): + ureply = await e.get_reply_message() + xx = await eor(e, "`...`") + if not (ureply and (ureply.media)): + await xx.edit("`Reply to any media`") + return + ultt = await ureply.download_media() + if ultt.endswith(".tgs"): + await xx.edit("`Ooo Animated Sticker 👀...`") + cmd = ["lottie_convert.py", ultt, "ult.png"] + file = "ult.png" + process = await asyncio.create_subprocess_exec( + *cmd, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE + ) + stdout, stderr = await process.communicate() + stderr.decode().strip() + stdout.decode().strip() + else: + await xx.edit("`Processing...`") + img = cv2.VideoCapture(ultt) + heh, lol = img.read() + cv2.imwrite("ult.png", lol) + file = "ult.png" + img = cv2.imread(file) + gray_image = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) + inverted_gray_image = 255 - gray_image + blurred_img = cv2.GaussianBlur(inverted_gray_image, (21, 21), 0) + inverted_blurred_img = 255 - blurred_img + pencil_sketch_IMG = cv2.divide(gray_image, inverted_blurred_img, scale=256.0) + cv2.imwrite("ultroid.png", pencil_sketch_IMG) + await e.client.send_file(e.chat_id, file="ultroid.png") + await xx.delete() + os.remove(file) + os.remove("ultroid.png") + + +@ultroid_cmd( + pattern="grey$", +) +async def ultd(event): + ureply = await event.get_reply_message() + if not (ureply and (ureply.media)): + await eor(event, "`Reply to any media`") + return + ultt = await ureply.download_media() + if ultt.endswith(".tgs"): + xx = await eor(event, "`Ooo Animated Sticker 👀...`") + cmd = ["lottie_convert.py", ultt, "ult.png"] + file = "ult.png" + process = await asyncio.create_subprocess_exec( + *cmd, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE + ) + stdout, stderr = await process.communicate() + stderr.decode().strip() + stdout.decode().strip() + else: + xx = await eor(event, "`Processing...`") + img = cv2.VideoCapture(ultt) + heh, lol = img.read() + cv2.imwrite("ult.png", lol) + file = "ult.png" + ult = cv2.imread(file) + ultroid = cv2.cvtColor(ult, cv2.COLOR_BGR2GRAY) + cv2.imwrite("ult.jpg", ultroid) + await event.client.send_file( + event.chat_id, "ult.jpg", force_document=False, reply_to=event.reply_to_msg_id + ) + await xx.delete() + os.remove("ult.png") + os.remove("ult.jpg") + os.remove(ultt) + + +@ultroid_cmd( + pattern="blur$", +) +async def ultd(event): + ureply = await event.get_reply_message() + if not (ureply and (ureply.media)): + await eor(event, "`Reply to any media`") + return + ultt = await ureply.download_media() + if ultt.endswith(".tgs"): + xx = await eor(event, "`Ooo Animated Sticker 👀...`") + cmd = ["lottie_convert.py", ultt, "ult.png"] + file = "ult.png" + process = await asyncio.create_subprocess_exec( + *cmd, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE + ) + stdout, stderr = await process.communicate() + stderr.decode().strip() + stdout.decode().strip() + else: + xx = await eor(event, "`Processing...`") + img = cv2.VideoCapture(ultt) + heh, lol = img.read() + cv2.imwrite("ult.png", lol) + file = "ult.png" + ult = cv2.imread(file) + ultroid = cv2.GaussianBlur(ult, (35, 35), 0) + cv2.imwrite("ult.jpg", ultroid) + await event.client.send_file( + event.chat_id, "ult.jpg", force_document=False, reply_to=event.reply_to_msg_id + ) + await xx.delete() + os.remove("ult.png") + os.remove("ult.jpg") + os.remove(ultt) + + +@ultroid_cmd( + pattern="negative$", +) +async def ultd(event): + ureply = await event.get_reply_message() + xx = await eor(event, "`...`") + if not (ureply and (ureply.media)): + await xx.edit("`Reply to any media`") + return + ultt = await ureply.download_media() + if ultt.endswith(".tgs"): + await xx.edit("`Ooo Animated Sticker 👀...`") + cmd = ["lottie_convert.py", ultt, "ult.png"] + file = "ult.png" + process = await asyncio.create_subprocess_exec( + *cmd, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE + ) + stdout, stderr = await process.communicate() + stderr.decode().strip() + stdout.decode().strip() + else: + await xx.edit("`Processing...`") + img = cv2.VideoCapture(ultt) + heh, lol = img.read() + cv2.imwrite("ult.png", lol) + file = "ult.png" + ult = cv2.imread(file) + ultroid = cv2.bitwise_not(ult) + cv2.imwrite("ult.jpg", ultroid) + await event.client.send_file( + event.chat_id, "ult.jpg", force_document=False, reply_to=event.reply_to_msg_id + ) + await xx.delete() + os.remove("ult.png") + os.remove("ult.jpg") + os.remove(ultt) + + +@ultroid_cmd( + pattern="mirror$", +) +async def ultd(event): + ureply = await event.get_reply_message() + xx = await eor(event, "`...`") + if not (ureply and (ureply.media)): + await xx.edit("`Reply to any media`") + return + ultt = await ureply.download_media() + if ultt.endswith(".tgs"): + await xx.edit("`Ooo Animated Sticker 👀...`") + cmd = ["lottie_convert.py", ultt, "ult.png"] + file = "ult.png" + process = await asyncio.create_subprocess_exec( + *cmd, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE + ) + stdout, stderr = await process.communicate() + stderr.decode().strip() + stdout.decode().strip() + else: + await xx.edit("`Processing...`") + img = cv2.VideoCapture(ultt) + heh, lol = img.read() + cv2.imwrite("ult.png", lol) + file = "ult.png" + ult = cv2.imread(file) + ish = cv2.flip(ult, 1) + ultroid = cv2.hconcat([ult, ish]) + cv2.imwrite("ult.jpg", ultroid) + await event.client.send_file( + event.chat_id, "ult.jpg", force_document=False, reply_to=event.reply_to_msg_id + ) + await xx.delete() + os.remove("ult.png") + os.remove("ult.jpg") + os.remove(ultt) + + +@ultroid_cmd( + pattern="flip$", +) +async def ultd(event): + ureply = await event.get_reply_message() + xx = await eor(event, "`...`") + if not (ureply and (ureply.media)): + await xx.edit("`Reply to any media`") + return + ultt = await ureply.download_media() + if ultt.endswith(".tgs"): + await xx.edit("`Ooo Animated Sticker 👀...`") + cmd = ["lottie_convert.py", ultt, "ult.png"] + file = "ult.png" + process = await asyncio.create_subprocess_exec( + *cmd, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE + ) + stdout, stderr = await process.communicate() + stderr.decode().strip() + stdout.decode().strip() + else: + await xx.edit("`Processing...`") + img = cv2.VideoCapture(ultt) + heh, lol = img.read() + cv2.imwrite("ult.png", lol) + file = "ult.png" + ult = cv2.imread(file) + trn = cv2.flip(ult, 1) + ish = cv2.rotate(trn, cv2.ROTATE_180) + ultroid = cv2.vconcat([ult, ish]) + cv2.imwrite("ult.jpg", ultroid) + await event.client.send_file( + event.chat_id, "ult.jpg", force_document=False, reply_to=event.reply_to_msg_id + ) + await xx.delete() + os.remove("ult.png") + os.remove("ult.jpg") + os.remove(ultt) + + +@ultroid_cmd( + pattern="quad$", +) +async def ultd(event): + ureply = await event.get_reply_message() + xx = await eor(event, "`...`") + if not (ureply and (ureply.media)): + await xx.edit("`Reply to any media`") + return + ultt = await ureply.download_media() + if ultt.endswith(".tgs"): + await xx.edit("`Ooo Animated Sticker 👀...`") + cmd = ["lottie_convert.py", ultt, "ult.png"] + file = "ult.png" + process = await asyncio.create_subprocess_exec( + *cmd, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE + ) + stdout, stderr = await process.communicate() + stderr.decode().strip() + stdout.decode().strip() + else: + await xx.edit("`Processing...`") + img = cv2.VideoCapture(ultt) + heh, lol = img.read() + cv2.imwrite("ult.png", lol) + file = "ult.png" + ult = cv2.imread(file) + roid = cv2.flip(ult, 1) + mici = cv2.hconcat([ult, roid]) + fr = cv2.flip(mici, 1) + trn = cv2.rotate(fr, cv2.ROTATE_180) + ultroid = cv2.vconcat([mici, trn]) + cv2.imwrite("ult.jpg", ultroid) + await event.client.send_file( + event.chat_id, "ult.jpg", force_document=False, reply_to=event.reply_to_msg_id + ) + await xx.delete() + os.remove("ult.png") + os.remove("ult.jpg") + os.remove(ultt) + + +@ultroid_cmd( + pattern="toon$", +) +async def ultd(event): + ureply = await event.get_reply_message() + xx = await eor(event, "`...`") + if not (ureply and (ureply.media)): + await xx.edit("`Reply to any media`") + return + ultt = await ureply.download_media() + if ultt.endswith(".tgs"): + await xx.edit("`Ooo Animated Sticker 👀...`") + cmd = ["lottie_convert.py", ultt, "ult.png"] + file = "ult.png" + process = await asyncio.create_subprocess_exec( + *cmd, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE + ) + stdout, stderr = await process.communicate() + stderr.decode().strip() + stdout.decode().strip() + else: + await xx.edit("`Processing...`") + img = cv2.VideoCapture(ultt) + heh, lol = img.read() + cv2.imwrite("ult.png", lol) + file = "ult.png" + ult = cv2.imread(file) + height, width, channels = ult.shape + samples = np.zeros([height * width, 3], dtype=np.float32) + count = 0 + for x in range(height): + for y in range(width): + samples[count] = ult[x][y] + count += 1 + compactness, labels, centers = cv2.kmeans( + samples, + 12, + None, + (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 10000, 0.0001), + 5, + cv2.KMEANS_PP_CENTERS, + ) + centers = np.uint8(centers) + ish = centers[labels.flatten()] + ultroid = ish.reshape((ult.shape)) + cv2.imwrite("ult.jpg", ultroid) + await event.client.send_file( + event.chat_id, "ult.jpg", force_document=False, reply_to=event.reply_to_msg_id + ) + await xx.delete() + os.remove("ult.png") + os.remove("ult.jpg") + os.remove(ultt) + + +@ultroid_cmd( + pattern="danger$", +) +async def ultd(event): + ureply = await event.get_reply_message() + xx = await eor(event, "`...`") + if not (ureply and (ureply.media)): + await xx.edit("`Reply to any media`") + return + ultt = await ureply.download_media() + if ultt.endswith(".tgs"): + await xx.edit("`Ooo Animated Sticker 👀...`") + cmd = ["lottie_convert.py", ultt, "ult.png"] + file = "ult.png" + process = await asyncio.create_subprocess_exec( + *cmd, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE + ) + stdout, stderr = await process.communicate() + stderr.decode().strip() + stdout.decode().strip() + else: + await xx.edit("`Processing...`") + img = cv2.VideoCapture(ultt) + heh, lol = img.read() + cv2.imwrite("ult.png", lol) + file = "ult.png" + ult = cv2.imread(file) + dan = cv2.cvtColor(ult, cv2.COLOR_BGR2RGB) + ultroid = cv2.cvtColor(dan, cv2.COLOR_HSV2BGR) + cv2.imwrite("ult.jpg", ultroid) + await event.client.send_file( + event.chat_id, "ult.jpg", force_document=False, reply_to=event.reply_to_msg_id + ) + await xx.delete() + os.remove("ult.png") + os.remove("ult.jpg") + os.remove(ultt) + + +@ultroid_cmd( + pattern="blue$", +) +async def ultd(event): + ureply = await event.get_reply_message() + xx = await eor(event, "`...`") + if not (ureply and (ureply.media)): + await xx.edit("`Reply to any media`") + return + ultt = await ureply.download_media() + if ultt.endswith(".tgs"): + await xx.edit("`Ooo Animated Sticker 👀...`") + cmd = ["lottie_convert.py", ultt, "ult.png"] + file = "ult.png" + process = await asyncio.create_subprocess_exec( + *cmd, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE + ) + stdout, stderr = await process.communicate() + stderr.decode().strip() + stdout.decode().strip() + else: + await xx.edit("`Processing...`") + img = cv2.VideoCapture(ultt) + heh, lol = img.read() + cv2.imwrite("ult.png", lol) + file = "ult.png" + got = upf(file) + lnk = f"https://telegra.ph{got[0]}" + r = requests.get( + f"https://nekobot.xyz/api/imagegen?type=blurpify&image={lnk}" + ).json() + ms = r.get("message") + utd = url(ms) + if not utd: + return + with open("ult.png", "wb") as f: + f.write(requests.get(ms).content) + img = Image.open("ult.png").convert("RGB") + img.save("ult.webp", "webp") + await event.client.send_file( + event.chat_id, "ult.webp", force_document=False, reply_to=event.reply_to_msg_id + ) + await xx.delete() + os.remove("ult.png") + os.remove("ult.webp") + os.remove(ultt) + + +HELP.update({f"{__name__.split('.')[1]}": f"{__doc__.format(i=Var.HNDLR)}"}) diff --git a/plugins/pdftools.py b/plugins/pdftools.py new file mode 100644 index 0000000000..05a95ec404 --- /dev/null +++ b/plugins/pdftools.py @@ -0,0 +1,295 @@ +# Ultroid - UserBot +# Copyright (C) 2020 TeamUltroid +# +# This file is a part of < https://github.com/TeamUltroid/Ultroid/ > +# PLease read the GNU Affero General Public License in +# . + +""" +✘ Commands Available - + +• `{i}pdf ` + Extract nd Send page as a Image.(note-: For Extraction all pages just use .pdf) + +• `{i}pdtext ` + Extract Text From the Pdf.(note-: For Extraction all text just use .pdtext) + +• `{i}pdscan ` + It scan, crop nd send img as pdf. + +• `{i}pdsave ` + It scan, crop nd save file to merge u can merge many pages as a single pdf. + +• `{i}pdsend ` + Merge nd send the Pdf to collected from .pdsave. +""" + +import os +import shutil + +import cv2 +import imutils +import numpy as np +import PIL +from imutils.perspective import four_point_transform +from PyPDF2 import PdfFileMerger, PdfFileReader, PdfFileWriter +from skimage.filters import threshold_local + +from . import * + +if not os.path.exists("pdf/"): + os.makedirs("pdf/") + + +@ultroid_cmd( + pattern="pdf ?(.*)", +) +async def pdfseimg(event): + ok = await event.get_reply_message() + msg = event.pattern_match.group(1) + if not ok and ok.document and ok.document.mime_type == "application/pdf": + await eor(event, "`Reply The pdf u Want to Download..`") + return + xx = await eor(event, "Processing...") + if not msg: + d = os.path.join("pdf/", "hehe.pdf") + await event.client.download_media(ok, d) + pdfp = "pdf/hehe.pdf" + pdfp.replace(".pdf", "") + pdf = PdfFileReader(pdfp) + for num in range(pdf.numPages): + pw = PdfFileWriter() + pw.addPage(pdf.getPage(num)) + with open(os.path.join("pdf/ult{}.png".format(num + 1)), "wb") as f: + pw.write(f) + os.remove(pdfp) + a = os.listdir("pdf/") + for z in a: + lst = [f"pdf/{z}"] + await event.client.send_file(event.chat_id, lst, album=True) + shutil.rmtree("pdf") + os.makedirs("pdf/") + await xx.delete() + if msg: + o = int(msg) - 1 + d = os.path.join("pdf/", "hehe.pdf") + await event.client.download_media(ok, d) + pdfp = "pdf/hehe.pdf" + pdfp.replace(".pdf", "") + pdf = PdfFileReader(pdfp) + pw = PdfFileWriter() + pw.addPage(pdf.getPage(o)) + with open(os.path.join("ult.png"), "wb") as f: + pw.write(f) + os.remove(pdfp) + await event.client.send_file( + event.chat_id, "ult.png", reply_to=event.reply_to_msg_id + ) + os.remove("ult.png") + await xx.delete() + + +@ultroid_cmd( + pattern="pdtext ?(.*)", +) +async def pdfsetxt(event): + ok = await event.get_reply_message() + msg = event.pattern_match.group(1) + if not ok and ok.document and ok.document.mime_type == "application/pdf": + await eor(event, "`Reply The pdf u Want to Download..`") + return + xx = await eor(event, "`Processing...`") + if not msg: + dl = await event.client.download_media(ok) + pdf = PdfFileReader(dl) + text = f"{dl.split('.')[0]}.txt" + with open(text, "w") as f: + for page_num in range(pdf.numPages): + pageObj = pdf.getPage(page_num) + txt = pageObj.extractText() + f.write("Page {0}\n".format(page_num + 1)) + f.write("".center(100, "-")) + f.write(txt) + await event.client.send_file( + event.chat_id, text, reply_to=event.reply_to_msg_id + ) + os.remove(text) + os.remove(dl) + await xx.delete() + return + if "_" in msg: + u, d = msg.split("_") + dl = await event.client.download_media(ok) + a = PdfFileReader(dl) + str = "" + for i in range(int(u) - 1, int(d)): + str += a.getPage(i).extractText() + text = f"{dl.split('.')[0]} {msg}.txt" + with open(text, "w") as f: + f.write(str) + await event.client.send_file( + event.chat_id, text, reply_to=event.reply_to_msg_id + ) + os.remove(text) + os.remove(dl) + else: + u = int(msg) - 1 + dl = await event.client.download_media(ok) + a = PdfFileReader(dl) + str = a.getPage(u).extractText() + text = f"{dl.split('.')[0]} Pg-{msg}.txt" + with open(text, "w") as f: + f.write(str) + await event.client.send_file( + event.chat_id, text, reply_to=event.reply_to_msg_id + ) + os.remove(text) + os.remove(dl) + await xx.delete() + + +@ultroid_cmd( + pattern="pdscan ?(.*)", +) +async def imgscan(event): + ok = await event.get_reply_message() + if not (ok and (ok.media)): + await eor(event, "`Reply The pdf u Want to Download..`") + return + ultt = await ok.download_media() + if not ultt.endswith(("png", "jpg", "jpeg", "webp")): + await eor(event, "`Reply to a Image only...`") + os.remove(ultt) + return + xx = await eor(event, "`Processing...`") + image = cv2.imread(ultt) + original_image = image.copy() + ratio = image.shape[0] / 500.0 + image = imutils.resize(image, height=500) + image_yuv = cv2.cvtColor(image, cv2.COLOR_BGR2YUV) + image_y = np.zeros(image_yuv.shape[0:2], np.uint8) + image_y[:, :] = image_yuv[:, :, 0] + image_blurred = cv2.GaussianBlur(image_y, (3, 3), 0) + edges = cv2.Canny(image_blurred, 50, 200, apertureSize=3) + contours, hierarchy = cv2.findContours( + edges, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE + ) + polygons = [] + for cnt in contours: + hull = cv2.convexHull(cnt) + polygons.append(cv2.approxPolyDP(hull, 0.01 * cv2.arcLength(hull, True), False)) + sortedPoly = sorted(polygons, key=cv2.contourArea, reverse=True) + cv2.drawContours(image, sortedPoly[0], -1, (0, 0, 255), 5) + simplified_cnt = sortedPoly[0] + if len(simplified_cnt) == 4: + cropped_image = four_point_transform( + original_image, simplified_cnt.reshape(4, 2) * ratio + ) + gray_image = cv2.cvtColor(cropped_image, cv2.COLOR_BGR2GRAY) + T = threshold_local(gray_image, 11, offset=10, method="gaussian") + ok = (gray_image > T).astype("uint8") * 255 + if len(simplified_cnt) != 4: + ok = cv2.detailEnhance(original_image, sigma_s=10, sigma_r=0.15) + cv2.imwrite("o.png", ok) + image1 = PIL.Image.open("o.png") + im1 = image1.convert("RGB") + scann = f"Scanned {ultt.split('.')[0]}.pdf" + im1.save(scann) + await event.client.send_file(event.chat_id, scann, reply_to=event.reply_to_msg_id) + await xx.delete() + os.remove(ultt) + os.remove("o.png") + os.remove(scann) + + +@ultroid_cmd( + pattern="pdsave ?(.*)", +) +async def savepdf(event): + ok = await event.get_reply_message() + if not (ok and (ok.media)): + await eor( + event, "`Reply to Images/pdf which u want to merge as a single pdf..`" + ) + return + ultt = await ok.download_media() + if ultt.endswith(("png", "jpg", "jpeg", "webp")): + xx = await eor(event, "`Processing...`") + image = cv2.imread(ultt) + original_image = image.copy() + ratio = image.shape[0] / 500.0 + image = imutils.resize(image, height=500) + image_yuv = cv2.cvtColor(image, cv2.COLOR_BGR2YUV) + image_y = np.zeros(image_yuv.shape[0:2], np.uint8) + image_y[:, :] = image_yuv[:, :, 0] + image_blurred = cv2.GaussianBlur(image_y, (3, 3), 0) + edges = cv2.Canny(image_blurred, 50, 200, apertureSize=3) + contours, hierarchy = cv2.findContours( + edges, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE + ) + polygons = [] + for cnt in contours: + hull = cv2.convexHull(cnt) + polygons.append( + cv2.approxPolyDP(hull, 0.01 * cv2.arcLength(hull, True), False) + ) + sortedPoly = sorted(polygons, key=cv2.contourArea, reverse=True) + cv2.drawContours(image, sortedPoly[0], -1, (0, 0, 255), 5) + simplified_cnt = sortedPoly[0] + if len(simplified_cnt) == 4: + cropped_image = four_point_transform( + original_image, simplified_cnt.reshape(4, 2) * ratio + ) + gray_image = cv2.cvtColor(cropped_image, cv2.COLOR_BGR2GRAY) + T = threshold_local(gray_image, 11, offset=10, method="gaussian") + ok = (gray_image > T).astype("uint8") * 255 + if len(simplified_cnt) != 4: + ok = cv2.detailEnhance(original_image, sigma_s=10, sigma_r=0.15) + cv2.imwrite("o.png", ok) + image1 = PIL.Image.open("o.png") + im1 = image1.convert("RGB") + a = dani_ck("pdf/scan.pdf") + im1.save(a) + await xx.edit( + f"Done, Now Reply Another Image/pdf if completed then use {hndlr}pdsend to merge nd send all as pdf", + ) + os.remove("o.png") + elif ultt.endswith(".pdf"): + a = dani_ck("pdf/scan.pdf") + await ultroid_bot.download_media(ok, a) + await eor( + event, + f"Done, Now Reply Another Image/pdf if completed then use {hndlr}pdsend to merge nd send all as pdf", + ) + else: + await eor(event, "`Reply to a Image/pdf only...`") + os.remove(ultt) + + +@ultroid_cmd( + pattern="pdsend ?(.*)", +) +async def sendpdf(event): + if not os.path.exists("pdf/scan.pdf"): + await eor( + event, + "first select pages by replying .pdsave of which u want to make multi page pdf file", + ) + return + msg = event.pattern_match.group(1) + if msg: + ok = f"{msg}.pdf" + else: + ok = "My PDF File.pdf" + merger = PdfFileMerger() + for item in os.listdir("pdf/"): + if item.endswith("pdf"): + merger.append(f"pdf/{item}") + merger.write(ok) + await event.client.send_file(event.chat_id, ok, reply_to=event.reply_to_msg_id) + os.remove(ok) + shutil.rmtree("pdf/") + os.makedirs("pdf/") + + +HELP.update({f"{__name__.split('.')[1]}": f"{__doc__.format(i=Var.HNDLR)}"}) diff --git a/plugins/pmpermit.py b/plugins/pmpermit.py new file mode 100644 index 0000000000..6102b44ed2 --- /dev/null +++ b/plugins/pmpermit.py @@ -0,0 +1,258 @@ +# Ultroid - UserBot +# Copyright (C) 2020 TeamUltroid +# +# This file is a part of < https://github.com/TeamUltroid/Ultroid/ > +# PLease read the GNU Affero General Public License in +# . + +from pyUltroid.functions.pmpermit_db import * +from telethon import events +from telethon.tl.functions.contacts import BlockRequest, UnblockRequest +from telethon.tl.functions.messages import ReportSpamRequest + +from . import * + +# ========================= CONSTANTS ============================= +COUNT_PM = {} +LASTMSG = {} +PMPIC = "https://telegra.ph/file/94f6a4aeb21ce2d58dd41.jpg" +UNAPPROVED_MSG = """ +**PMSecurity of {}!** +Please wait for me to respnd or you will be blocked and reported as spam!! + +You have {}/{} warnings!""" +WARNS = 3 +NO_REPLY = "Reply to someone's msg or try this commmand in private." +PMCMDS = [ + f"{hndlr}a", + f"{hndlr}approve", + f"{hndlr}da", + f"{hndlr}disapprove", + f"{hndlr}block", + f"{hndlr}unblock", +] +# ================================================================= + +sett = udB.get("PMSETTING") +if sett is None: + sett = True +if sett == "True" and sett != "False": + + @ultroid_bot.on(events.NewMessage(outgoing=True, func=lambda e: e.is_private)) + async def autoappr(event): + chat = await event.get_chat() + mssg = event.text + if mssg in PMCMDS: # do not approve if outgoing is a command. + return + if not is_approved(chat.id) and chat.id not in COUNT_PM: + approve_user(chat.id) + if Var.LOG_CHANNEL: + name = await event.client.get_entity(chat.id) + name0 = str(name.first_name) + await event.client.send_message( + Var.LOG_CHANNEL, + f"#AutoApproved\nUser - [{name0}](tg://user?id={chat.id})", + ) + + @ultroid_bot.on(events.NewMessage(incoming=True)) + async def permitpm(event): + if event.is_private: + user = await event.get_chat() + if user.bot: + return + apprv = is_approved(user.id) + if not apprv and event.text != UNAPPROVED_MSG: + try: + wrn = COUNT_PM[user.id] + except KeyError: + wrn = 0 + if user.id in LASTMSG: + prevmsg = LASTMSG[user.id] + if event.text != prevmsg: + async for message in event.client.iter_messages( + user.id, from_user="me", search=UNAPPROVED_MSG + ): + await message.delete() + await event.client.send_file( + user.id, + PMPIC, + caption=UNAPPROVED_MSG.format(OWNER_NAME, wrn, WARNS), + ) + elif event.text == prevmsg: + async for message in event.client.iter_messages( + user.id, from_user="me", search=UNAPPROVED_MSG + ): + await message.delete() + await event.client.send_file( + user.id, + PMPIC, + caption=UNAPPROVED_MSG.format(OWNER_NAME, wrn, WARNS), + ) + LASTMSG.update({user.id: event.text}) + else: + await event.client.send_file( + user.id, + PMPIC, + caption=UNAPPROVED_MSG.format(OWNER_NAME, wrn, WARNS), + ) + LASTMSG.update({user.id: event.text}) + if user.id not in COUNT_PM: + COUNT_PM.update({user.id: 1}) + else: + COUNT_PM[user.id] = COUNT_PM[user.id] + 1 + if COUNT_PM[user.id] > WARNS: + await event.respond( + "`You were spamming my Master's PM, which I didn't like.`\n`You have been BLOCKED and reported as SPAM, until further notice.`" + ) + try: + del COUNT_PM[user.id] + del LASTMSG[user.id] + except KeyError: + if Var.LOG_CHANNEL: + await event.client.send_message( + Var.LOG_CHANNEL, + "PMPermit is messed! Pls restart the bot!!", + ) + return LOGS.info("COUNT_PM is messed.") + await event.client(BlockRequest(user.id)) + await event.client(ReportSpamRequest(peer=user.id)) + if Var.LOG_CHANNEL: + name = await event.client.get_entity(user.id) + name0 = str(name.first_name) + await event.client.send_message( + Var.LOG_CHANNEL, + f"[{name0}](tg://user?id={user.id}) was blocked for spamming.", + ) + + @ultroid_cmd(pattern="(a|approve)(?: |$)") + async def approvepm(apprvpm): + if apprvpm.reply_to_msg_id: + reply = await apprvpm.get_reply_message() + replied_user = await apprvpm.client.get_entity(reply.sender_id) + aname = replied_user.id + name0 = str(replied_user.first_name) + uid = replied_user.id + if not is_approved(uid): + approve_user(uid) + await apprvpm.edit(f"[{name0}](tg://user?id={uid}) `approved to PM!`") + await asyncio.sleep(3) + await apprvpm.delete() + else: + await apprvpm.edit("`User may already be approved.`") + await asyncio.sleep(5) + await apprvpm.delete() + elif apprvpm.is_private: + user = await apprvpm.get_chat() + aname = await apprvpm.client.get_entity(user.id) + name0 = str(aname.first_name) + uid = user.id + if not is_approved(uid): + approve_user(uid) + await apprvpm.edit(f"[{name0}](tg://user?id={uid}) `approved to PM!`") + async for message in apprvpm.client.iter_messages( + user.id, from_user="me", search=UNAPPROVED_MSG + ): + await message.delete() + await asyncio.sleep(3) + await apprvpm.delete() + if Var.LOG_CHANNEL: + await apprvpm.client.send_message( + Var.LOG_CHANNEL, + f"#APPROVED\nUser: [{name0}](tg://user?id={uid})", + ) + else: + await apprvpm.edit("`User may already be approved.`") + await asyncio.sleep(5) + await apprvpm.delete() + if Var.LOG_CHANNEL: + await apprvpm.client.send_message( + Var.LOG_CHANNEL, + f"#APPROVED\nUser: [{name0}](tg://user?id={uid})", + ) + else: + await apprvpm.edit(NO_REPLY) + + @ultroid_cmd(pattern="(da|disapprove)(?: |$)") + async def disapprovepm(e): + if e.reply_to_msg_id: + reply = await e.get_reply_message() + replied_user = await e.client.get_entity(reply.sender_id) + aname = replied_user.id + name0 = str(replied_user.first_name) + if is_approved(replied_user.id): + disapprove_user(replied_user.id) + await e.edit( + f"[{name0}](tg://user?id={replied_user.id}) `Disaproved to PM!`" + ) + await asyncio.sleep(5) + await e.delete() + else: + await e.edit( + f"[{name0}](tg://user?id={replied_user.id}) was never approved!" + ) + await asyncio.sleep(5) + await e.delete() + elif e.is_private: + bbb = await e.get_chat() + aname = await e.client.get_entity(bbb.id) + name0 = str(aname.first_name) + if is_approved(bbb.id): + disapprove_user(bbb.id) + await e.edit(f"[{name0}](tg://user?id={bbb.id}) `Disaproved to PM!`") + await asyncio.sleep(5) + await e.delete() + if Var.LOG_CHANNEL: + await e.client.send_message( + Var.LOG_CHANNEL, + f"[{name0}](tg://user?id={bbb.id}) was disapproved to PM you.", + ) + else: + await e.edit(f"[{name0}](tg://user?id={bbb.id}) was never approved!") + await asyncio.sleep(5) + await e.delete() + else: + await e.edit(NO_REPLY) + + @ultroid_cmd(pattern="block$") + async def blockpm(block): + if block.reply_to_msg_id: + reply = await block.get_reply_message() + replied_user = await block.client.get_entity(reply.sender_id) + aname = replied_user.id + name0 = str(replied_user.first_name) + await block.client(BlockRequest(replied_user.id)) + await block.edit("`You've been blocked!`") + uid = replied_user.id + elif block.is_private: + bbb = await block.get_chat() + await block.client(BlockRequest(bbb.id)) + aname = await block.client.get_entity(bbb.id) + await block.edit("`You've been blocked!`") + name0 = str(aname.first_name) + uid = bbb.id + else: + await block.edit(NO_REPLY) + try: + disapprove_user(uid) + except AttributeError: + pass + if Var.LOG_CHANNEL: + await block.client.send_message( + Var.LOG_CHANNEL, f"#BLOCKED\nUser: [{name0}](tg://user?id={uid})" + ) + + @ultroid_cmd(pattern="unblock$") + async def unblockpm(unblock): + if unblock.reply_to_msg_id: + reply = await unblock.get_reply_message() + replied_user = await unblock.client.get_entity(reply.sender_id) + name0 = str(replied_user.first_name) + await unblock.client(UnblockRequest(replied_user.id)) + await unblock.edit("`You have been unblocked.`") + else: + await unblock.edit(NO_REPLY) + if Var.LOG_CHANNEL: + await unblock.client.send_message( + Var.LOG_CHANNEL, + f"[{name0}](tg://user?id={replied_user.id}) was unblocked!.", + ) diff --git a/plugins/profile.py b/plugins/profile.py new file mode 100644 index 0000000000..7364ae3028 --- /dev/null +++ b/plugins/profile.py @@ -0,0 +1,163 @@ +# Ultroid - UserBot +# Copyright (C) 2020 TeamUltroid +# +# This file is a part of < https://github.com/TeamUltroid/Ultroid/ > +# PLease read the GNU Affero General Public License in +# . + +""" +✘ Commands Available - + +• `{i}setname ` + Change your profile name. + +• `{i}setbio ` + Change your profile bio. + +• `{i}setpic ` + Change your profile pic. + +• `{i}delpfp (optional)` + Delete one profile pic, if no value given, else delete n number of pics. + +• `{i}gpoto ` + Upload the photo of Chat/User if Available. +""" + +import asyncio +import os + +from telethon.tl import functions +from telethon.tl.functions.photos import DeletePhotosRequest, GetUserPhotosRequest +from telethon.tl.types import InputPhoto + +from . import * + +TMP_DOWNLOAD_DIRECTORY = "resources/downloads/" + +# bio changer + + +@ultroid_cmd( + pattern="setbio ?(.*)", +) +async def _(ult): + ok = await eor(ult, "...") + set = ult.pattern_match.group(1) + try: + await ultroid_bot(functions.account.UpdateProfileRequest(about=set)) + await ok.edit("Profile bio changed to\n`{}`".format(set)) + except Exception as ex: + await ok.edit("Error occured.\n`{}`".format(str(ex))) + await asyncio.sleep(10) + await ok.delete() + + +# name changer + + +@ultroid_cmd( + pattern="setname ?((.|//)*)", +) +async def _(ult): + ok = await eor(ult, "...") + names = ult.pattern_match.group(1) + first_name = names + last_name = "" + if "//" in names: + first_name, last_name = names.split("//", 1) + try: + await ultroid_bot( + functions.account.UpdateProfileRequest( + first_name=first_name, last_name=last_name + ) + ) + await ok.edit("Name changed to `{}`".format(names)) + except Exception as ex: + await ok.edit("Error occured.\n`{}`".format(str(ex))) + await asyncio.sleep(10) + await ok.delete() + + +# profile pic + + +@ultroid_cmd( + pattern="setpic$", +) +async def _(ult): + ok = await eor(ult, "...") + reply_message = await ult.get_reply_message() + await ok.edit("`Downloading that picture...`") + if not os.path.isdir(TMP_DOWNLOAD_DIRECTORY): + os.makedirs(TMP_DOWNLOAD_DIRECTORY) + photo = None + try: + photo = await ultroid_bot.download_media(reply_message, TMP_DOWNLOAD_DIRECTORY) + except Exception as ex: + await ok.edit("Error occured.\n`{}`".format(str(ex))) + else: + if photo: + await ok.edit("`Uploading it to my profile...`") + file = await ultroid_bot.upload_file(photo) + try: + await ultroid_bot(functions.photos.UploadProfilePhotoRequest(file)) + except Exception as ex: + await ok.edit("Error occured.\n`{}`".format(str(ex))) + else: + await ok.edit("`My profile picture has been changed !`") + await asyncio.sleep(10) + await ok.delete() + try: + os.remove(photo) + except Exception as ex: + LOGS.exception(ex) + + +# delete profile pic(s) + + +@ultroid_cmd( + pattern="delpfp ?(.*)", +) +async def remove_profilepic(delpfp): + ok = await eor(delpfp, "...") + group = delpfp.text[8:] + if group == "all": + lim = 0 + elif group.isdigit(): + lim = int(group) + else: + lim = 1 + pfplist = await ultroid_bot( + GetUserPhotosRequest(user_id=delpfp.from_id, offset=0, max_id=0, limit=lim) + ) + input_photos = [] + for sep in pfplist.photos: + input_photos.append( + InputPhoto( + id=sep.id, + access_hash=sep.access_hash, + file_reference=sep.file_reference, + ) + ) + await ultroid_bot(DeletePhotosRequest(id=input_photos)) + await ok.edit(f"`Successfully deleted {len(input_photos)} profile picture(s).`") + await asyncio.sleep(10) + await ok.delete() + + +@ultroid_cmd(pattern="gpoto ?(.*)") +async def gpoto(e): + ult = e.pattern_match.group(1) + try: + okla = await ultroid_bot.download_profile_photo( + ult, "profile.jpg", download_big=True + ) + await ultroid_bot.send_message(e.chat_id, file=okla) + os.remove(okla) + except Exception as e: + await eor(e, f"ERROR - {str(e)}") + + +HELP.update({f"{__name__.split('.')[1]}": f"{__doc__.format(i=Var.HNDLR)}"}) diff --git a/plugins/redis.py b/plugins/redis.py new file mode 100644 index 0000000000..29718a5403 --- /dev/null +++ b/plugins/redis.py @@ -0,0 +1,115 @@ +# Ultroid - UserBot +# Copyright (C) 2020 TeamUltroid +# +# This file is a part of < https://github.com/TeamUltroid/Ultroid/ > +# PLease read the GNU Affero General Public License in +# . + +""" +✘ Commands Available - + +• `{i}setredis key | value` + Redis Set Value. + e.g : + `{i}setredis hi there` + `{i}setredis hi there | ultroid here` + +• `{i}getredis key` + Redis Get Value + +• `{i}delredis key` + Delete Key from Redis DB + +• `{i}renredis old keyname | new keyname` + Update Key Name + +• `{i}getkeys` + Get the list of keys stored in Redis +""" + +import re + +from . import * + + +@ultroid_cmd( + pattern="setredis ?(.*)", +) +async def _(ult): + ok = await eor(ult, "`...`") + try: + delim = " " if re.search("[|]", ult.pattern_match.group(1)) is None else " | " + data = ult.pattern_match.group(1).split(delim) + udB.set(data[0], data[1]) + redisdata = Redis(data[0]) + await ok.edit( + "Redis Key Value Pair Updated\nKey : `{}`\nValue : `{}`".format( + data[0], redisdata + ) + ) + except BaseException: + await ok.edit("`Something Went Wrong`") + + +@ultroid_cmd( + pattern="getredis ?(.*)", +) +async def _(ult): + ok = await eor(ult, "`Fetching data from Redis`") + val = ult.pattern_match.group(1) + if val == "": + return await ult.edit(f"Please use `{hndlr}getkeys `") + try: + value = Redis(val) + await ok.edit("Key: `{}`\nValue: `{}`".format(val, value)) + except BaseException: + await ok.edit("`Something Went Wrong`") + + +@ultroid_cmd( + pattern="delredis ?(.*)", +) +async def _(ult): + ok = await eor(ult, "`Deleting data from Redis ...`") + try: + key = ult.pattern_match.group(1) + udB.delete(key) + await ok.edit(f"`Successfully deleted key {key}`") + except BaseException: + await ok.edit("`Something Went Wrong`") + + +@ultroid_cmd( + pattern="renredis ?(.*)", +) +async def _(ult): + ok = await eor(ult, "`...`") + delim = " " if re.search("[|]", ult.pattern_match.group(1)) is None else " | " + data = ult.pattern_match.group(1).split(delim) + if Redis(data[0]): + try: + udB.rename(data[0], data[1]) + await ok.edit( + "Redis Key Rename Successful\nOld Key : `{}`\nNew Key : `{}`".format( + data[0], data[1] + ) + ) + except BaseException: + await ok.edit("Something went wrong ...") + else: + await ok.edit("Key not found") + + +@ultroid_cmd( + pattern="getkeys$", +) +async def _(ult): + ok = await eor(ult, "`Fetching Keys ...`") + keys = udB.keys() + msg = "" + for x in keys: + msg += "• `{}`".format(x) + "\n" + await ok.edit("**List of Redis Keys :**\n{}".format(msg)) + + +HELP.update({f"{__name__.split('.')[1]}": f"{__doc__.format(i=Var.HNDLR)}"}) diff --git a/plugins/specialtools.py b/plugins/specialtools.py new file mode 100644 index 0000000000..92c13e716e --- /dev/null +++ b/plugins/specialtools.py @@ -0,0 +1,246 @@ +# Ultroid - UserBot +# Copyright (C) 2020 TeamUltroid +# +# This file is a part of < https://github.com/TeamUltroid/Ultroid/ > +# PLease read the GNU Affero General Public License in +# . + +""" +✘ Commands Available - + +• `{i}wspr ` + Send secret message.. + +• `{i}sticker ` + Search Stickers as Per ur Wish.. + +• `{i}getaudio ` + Download Audio To put in ur Desired Video/Gif. + +• `{i}addaudio ` + It will put the above audio to the replied video/gif. + +• `{i}dob ` + Put in dd/mm/yy Format only(eg .dob 01/01/1999). + +• `{i}wall ` + Search Hd Wallpaper as Per ur Wish.. +""" + +import os +from datetime import datetime as dt +from random import choice +from shutil import rmtree + +import moviepy.editor as m +import pytz +import requests +from bs4 import BeautifulSoup as b + +from . import * + + +@ultroid_cmd( + pattern="getaudio$", +) +async def daudtoid(event): + ureply = await event.get_reply_message() + if not (ureply and ("audio" in ureply.document.mime_type)): + await eor(event, "`Reply To Audio Only..`") + return + xx = await eor(event, "`processing...`") + d = os.path.join("resources/extras/", "ul.mp3") + await xx.edit("`Downloading... Large Files Takes Time..`") + await event.client.download_media(ureply, d) + await xx.edit("`Done.. Now reply to video In which u want to add that Audio`") + + +@ultroid_cmd( + pattern="addaudio$", +) +async def adaudroid(event): + ureply = await event.get_reply_message() + if not (ureply and ("video" in ureply.document.mime_type)): + await eor(event, "`Reply To Gif/Video In which u want to add audio.`") + return + xx = await eor(event, "`processing...`") + ultt = await ureply.download_media() + ls = os.listdir("resources/extras") + z = "ul.mp3" + x = "resources/extras/ul.mp3" + if z not in ls: + await xx.edit("`First reply an audio with .aw`") + return + video = m.VideoFileClip(ultt) + audio = m.AudioFileClip(x) + out = video.set_audio(audio) + out.write_videofile("ok.mp4", fps=30) + await event.client.send_file( + event.chat_id, + file="ok.mp4", + force_document=False, + reply_to=event.reply_to_msg_id, + ) + os.remove("ok.mp4") + os.remove(x) + os.remove(ultt) + await xx.delete() + + +@ultroid_cmd( + pattern=r"dob ?(.*)", +) +async def hbd(event): + if not event.pattern_match.group(1): + await eor(event, "`Put input in dd/mm/yyyy format`") + return + if event.reply_to_msg_id: + kk = await event.get_reply_message() + nam = await ultroid_bot.get_entity(kk.from_id) + name = nam.first_name + else: + a = await ultroid_bot.get_me() + name = a.first_name + zn = pytz.timezone("Asia/Kolkata") + abhi = dt.now(zn) + n = event.text + q = n[5:] + p = n[5:7] + r = n[8:10] + s = n[11:] + day = int(p) + month = r + paida = q + jn = dt.strptime(paida, "%d/%m/%Y") + jnm = zn.localize(jn) + zinda = abhi - jnm + barsh = (zinda.total_seconds()) / (365.242 * 24 * 3600) + saal = int(barsh) + mash = (barsh - saal) * 12 + mahina = int(mash) + divas = (mash - mahina) * (365.242 / 12) + din = int(divas) + samay = (divas - din) * 24 + ghanta = int(samay) + pehl = (samay - ghanta) * 60 + mi = int(pehl) + sec = (pehl - mi) * 60 + slive = int(sec) + y = int(s) + int(saal) + 1 + m = int(r) + brth = dt(y, m, day) + cm = dt(abhi.year, brth.month, brth.day) + ish = (cm - abhi.today()).days + 1 + dan = ish + if dan == 0: + hp = "`Happy BirthDay To U🎉🎊`" + elif dan < 0: + okk = 365 + ish + hp = f"{okk} Days Left 🥳" + elif dan > 0: + hp = f"{ish} Days Left 🥳" + if month == "12": + sign = "Sagittarius" if (day < 22) else "Capricorn" + elif month == "01": + sign = "Capricorn" if (day < 20) else "Aquarius" + elif month == "02": + sign = "Aquarius" if (day < 19) else "Pisces" + elif month == "03": + sign = "Pisces" if (day < 21) else "Aries" + elif month == "04": + sign = "Aries" if (day < 20) else "Taurus" + elif month == "05": + sign = "Taurus" if (day < 21) else "Gemini" + elif month == "06": + sign = "Gemini" if (day < 21) else "Cancer" + elif month == "07": + sign = "Cancer" if (day < 23) else "Leo" + elif month == "08": + sign = "Leo" if (day < 23) else "Virgo" + elif month == "09": + sign = "Virgo" if (day < 23) else "Libra" + elif month == "10": + sign = "Libra" if (day < 23) else "Scorpion" + elif month == "11": + sign = "Scorpio" if (day < 22) else "Sagittarius" + sign = f"{sign}" + params = (("sign", sign), ("today", day)) + response = requests.post("https://aztro.sameerkumar.website/", params=params) + json = response.json() + dd = json.get("current_date") + ds = json.get("description") + lt = json.get("lucky_time") + md = json.get("mood") + cl = json.get("color") + ln = json.get("lucky_number") + await event.delete() + await event.client.send_message( + event.chat_id, + f""" + Name -: {name} + +D.O.B -: {paida} + +Lived -: {saal}yr, {mahina}m, {din}d, {ghanta}hr, {mi}min, {slive}sec + +Birthday -: {hp} + +Zodiac -: {sign} + +**Horoscope On {dd} -** + +`{ds}` + + Lucky Time :- {lt} + Lucky Number :- {ln} + Lucky Color :- {cl} + Mood :- {md} + """, + reply_to=event.reply_to_msg_id, + ) + + +@ultroid_cmd(pattern="sticker ?(.*)") +async def _(event): + x = event.pattern_match.group(1) + if not x: + return await eor(event, "`Give something to search`") + uu = await eor(event, "`Processing...`") + z = requests.get("https://combot.org/telegram/stickers?q=" + x).text + xx = b(z, "lxml") + title = xx.find_all("div", "sticker-pack__title") + link = xx.find_all("a", {"class": "sticker-pack__btn"}) + if not link: + return await uu.edit("Found Nothing") + a = "SᴛɪᴄᴋEʀs Aᴡᴀɪʟᴀʙʟᴇ ~" + for xxx, yyy in zip(title, link): + v = xxx.get_text() + w = yyy["href"] + d = f"\n\n[{v}]({w})" + if d not in a: + a += d + await uu.edit(a) + + +@ultroid_cmd(pattern="wall ?(.*)") +async def wall(event): + inp = event.pattern_match.group(1) + if not inp: + return await eor(event, "`Give something to search") + nn = await eor(event, "`Processing Keep Patience...`") + query = f"hd {inp}" + gi = googleimagesdownload() + args = { + "keywords": query, + "limit": 10, + "format": "jpg", + "output_directory": "./resources/downloads/", + } + gi.download(args) + xx = choice(os.listdir(os.path.abspath(f"./resources/downloads/{query}/"))) + await event.client.send_file(event.chat_id, f"./resources/downloads/{query}/{xx}") + rmtree(f"./resources/downloads/{query}/") + await nn.delete() + + +HELP.update({f"{__name__.split('.')[1]}": f"{__doc__.format(i=Var.HNDLR)}"}) diff --git a/plugins/stickertools.py b/plugins/stickertools.py new file mode 100644 index 0000000000..ec241535a5 --- /dev/null +++ b/plugins/stickertools.py @@ -0,0 +1,524 @@ +# Ultroid - UserBot +# Copyright (C) 2020 TeamUltroid +# +# This file is a part of < https://github.com/TeamUltroid/Ultroid/ > +# PLease read the GNU Affero General Public License in +# . + +""" +✘ Commands Available - + +• `{i}destroy ` + To destroy the sticker. + +• `{i}tiny ` + To create Tiny stickers. + +• `{i}convert ` + Reply to animated sticker. + +• `{i}kang ` + Kang the sticker (add to your pack). + +• `{i}round ` + To extract round sticker. + +• `{i}waifu ` + paste text on random stickers. + +""" + +import asyncio +import io +import os +import random +import re +import urllib.request +from os import remove + +import cv2 +import numpy as np +from PIL import Image, ImageDraw +from telethon.errors import ChatSendInlineForbiddenError, ChatSendStickersForbiddenError +from telethon.tl.types import ( + DocumentAttributeFilename, + DocumentAttributeSticker, + MessageMediaPhoto, +) + +from . import * + +EMOJI_PATTERN = re.compile( + "[" + "\U0001F1E0-\U0001F1FF" # flags (iOS) + "\U0001F300-\U0001F5FF" # symbols & pictographs + "\U0001F600-\U0001F64F" # emoticons + "\U0001F680-\U0001F6FF" # transport & map symbols + "\U0001F700-\U0001F77F" # alchemical symbols + "\U0001F780-\U0001F7FF" # Geometric Shapes Extended + "\U0001F800-\U0001F8FF" # Supplemental Arrows-C + "\U0001F900-\U0001F9FF" # Supplemental Symbols and Pictographs + "\U0001FA00-\U0001FA6F" # Chess Symbols + "\U0001FA70-\U0001FAFF" # Symbols and Pictographs Extended-A + "\U00002702-\U000027B0" # Dingbats + "]+" +) + + +def deEmojify(inputString: str) -> str: + """Remove emojis and other non-safe characters from string""" + return re.sub(EMOJI_PATTERN, "", inputString) + + +@ultroid_cmd( + pattern="waifu ?(.*)", +) +async def waifu(animu): + xx = await eor(animu, "`Processing...`") + # """Creates random anime sticker!""" + text = animu.pattern_match.group(1) + if not text: + if animu.is_reply: + text = (await animu.get_reply_message()).message + else: + await xx.edit("`You haven't written any article, Waifu is going away.`") + return + animus = [0, 1, 3, 7, 9, 13, 22, 34, 35, 36, 37, 43, 44, 45, 52, 53, 55] + t1 = "#" + (str(random.choice(animus))) + animus2 = [0, 11, 12, 19, 20, 21, 22, 23, 28, 32, 33] + t2 = "$" + (str(random.choice(animus2))) + animus3 = [10, 14, 19] + t3 = "&" + (str(random.choice(animus3))) + animus4 = [0, 3, 9, 15] + t4 = "%" + (str(random.choice(animus4))) + t5 = "*" + (str(random.choice(animus4))) + # to increase probability of getting sticker from special category + finalcall = random.choice([t1, t2, t3, t4, t5, t1]) + try: + sticcers = await ultroid_bot.inline_query( + "stickerizerbot", f"{finalcall}{(deEmojify(text))}" + ) + await sticcers[0].click( + animu.chat_id, + reply_to=animu.reply_to_msg_id, + silent=True if animu.is_reply else False, + hide_via=True, + ) + await xx.delete() + except ChatSendInlineForbiddenError: + await xx.edit("`Boss ! I cant use inline things here...`") + except ChatSendStickersForbiddenError: + await xx.edit("Sorry boss, I can't send Sticker Here !!") + + +@ultroid_cmd( + pattern="convert ?(.*)", +) +async def uconverter(event): + xx = await eor(event, "`Processing...`") + a = await event.get_reply_message() + input = event.pattern_match.group(1) + b = await event.client.download_media(a, "resources/downloads/") + if "gif" in input: + cmd = ["lottie_convert.py", b, "something.gif"] + file = "something.gif" + elif "sticker" in input: + cmd = ["lottie_convert.py", b, "something.webp"] + file = "something.webp" + elif "img" in input: + cmd = ["lottie_convert.py", b, "something.png"] + file = "something.png" + else: + await xx.edit("**Please select from gif/sticker/img**") + process = await asyncio.create_subprocess_exec( + *cmd, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE + ) + stdout, stderr = await process.communicate() + stderr.decode().strip() + stdout.decode().strip() + os.remove(b) + await event.client.send_file(event.chat_id, file, force_document=False) + os.remove(file) + await xx.delete() + + +@ultroid_cmd( + pattern="kang", +) +async def hehe(args): + xx = await eor(args, "`Processing...`") + user = await ultroid_bot.get_me() + if not user.username: + user.username = user.first_name + message = await args.get_reply_message() + photo = None + emojibypass = False + is_anim = False + emoji = None + if message and message.media: + if isinstance(message.media, MessageMediaPhoto): + await xx.edit(f"`{random.choice(KANGING_STR)}`") + photo = io.BytesIO() + photo = await ultroid_bot.download_media(message.photo, photo) + elif "image" in message.media.document.mime_type.split("/"): + await xx.edit(f"`{random.choice(KANGING_STR)}`") + photo = io.BytesIO() + await ultroid_bot.download_file(message.media.document, photo) + if ( + DocumentAttributeFilename(file_name="sticker.webp") + in message.media.document.attributes + ): + emoji = message.media.document.attributes[1].alt + emojibypass = True + elif "video" in message.media.document.mime_type.split("/"): + await xx.edit(f"`{random.choice(KANGING_STR)}`") + xy = await message.download_media() + y = cv2.VideoCapture(xy) + heh, lol = y.read() + cv2.imwrite("ult.webp", lol) + photo = "ult.webp" + elif "tgsticker" in message.media.document.mime_type: + await xx.edit(f"`{random.choice(KANGING_STR)}`") + await ultroid_bot.download_file( + message.media.document, "AnimatedSticker.tgs" + ) + + attributes = message.media.document.attributes + for attribute in attributes: + if isinstance(attribute, DocumentAttributeSticker): + emoji = attribute.alt + + emojibypass = True + is_anim = True + photo = 1 + else: + await xx.edit("`Unsupported File!`") + return + else: + await xx.edit("`I can't kang that...`") + return + + if photo: + splat = args.text.split() + if not emojibypass: + emoji = "🔰" + pack = 1 + if len(splat) == 3: + pack = splat[2] # User sent ultroid_both + emoji = splat[1] + elif len(splat) == 2: + if splat[1].isnumeric(): + pack = int(splat[1]) + else: + emoji = splat[1] + + packname = f"ult_{user.id}_{pack}" + packnick = f"@{user.username}'s Pack {pack}" + cmd = "/newpack" + file = io.BytesIO() + + if not is_anim: + image = await resize_photo(photo) + file.name = "sticker.png" + image.save(file, "PNG") + else: + packname += "_anim" + packnick += " (Animated)" + cmd = "/newanimated" + + response = urllib.request.urlopen( + urllib.request.Request(f"http://t.me/addstickers/{packname}") + ) + htmlstr = response.read().decode("utf8").split("\n") + + if ( + " A Telegram user has created the Sticker Set." + not in htmlstr + ): + async with ultroid_bot.conversation("Stickers") as conv: + await conv.send_message("/addsticker") + await conv.get_response() + await ultroid_bot.send_read_acknowledge(conv.chat_id) + await conv.send_message(packname) + x = await conv.get_response() + while "120" in x.text: + pack += 1 + packname = f"ult_{user.id}_{pack}" + packnick = f"@{user.username}'s Pack {pack}" + await xx.edit( + "`Switching to Pack " + + str(pack) + + " due to insufficient space`" + ) + await conv.send_message(packname) + x = await conv.get_response() + if x.text == "Invalid pack selected.": + await conv.send_message(cmd) + await conv.get_response() + await ultroid_bot.send_read_acknowledge(conv.chat_id) + await conv.send_message(packnick) + await conv.get_response() + await ultroid_bot.send_read_acknowledge(conv.chat_id) + if is_anim: + await conv.send_file("AnimatedSticker.tgs") + remove("AnimatedSticker.tgs") + else: + file.seek(0) + await conv.send_file(file, force_document=True) + await conv.get_response() + await conv.send_message(emoji) + await ultroid_bot.send_read_acknowledge(conv.chat_id) + await conv.get_response() + await conv.send_message("/publish") + if is_anim: + await conv.get_response() + await conv.send_message(f"<{packnick}>") + await conv.get_response() + await ultroid_bot.send_read_acknowledge(conv.chat_id) + await conv.send_message("/skip") + await ultroid_bot.send_read_acknowledge(conv.chat_id) + await conv.get_response() + await conv.send_message(packname) + await ultroid_bot.send_read_acknowledge(conv.chat_id) + await conv.get_response() + await ultroid_bot.send_read_acknowledge(conv.chat_id) + await xx.edit( + f"`Sticker added in a Different Pack !\ + \nThis Pack is Newly created!\ + \nYour pack can be found [here](t.me/addstickers/{packname})", + parse_mode="md", + ) + return + if is_anim: + await conv.send_file("AnimatedSticker.tgs") + remove("AnimatedSticker.tgs") + else: + file.seek(0) + await conv.send_file(file, force_document=True) + rsp = await conv.get_response() + if "Sorry, the file type is invalid." in rsp.text: + await xx.edit( + "`Failed to add sticker, use` @Stickers `bot to add the sticker manually.`" + ) + return + await conv.send_message(emoji) + await ultroid_bot.send_read_acknowledge(conv.chat_id) + await conv.get_response() + await conv.send_message("/done") + await conv.get_response() + await ultroid_bot.send_read_acknowledge(conv.chat_id) + else: + await xx.edit("`Brewing a new Pack...`") + async with ultroid_bot.conversation("Stickers") as conv: + await conv.send_message(cmd) + await conv.get_response() + await ultroid_bot.send_read_acknowledge(conv.chat_id) + await conv.send_message(packnick) + await conv.get_response() + await ultroid_bot.send_read_acknowledge(conv.chat_id) + if is_anim: + await conv.send_file("AnimatedSticker.tgs") + remove("AnimatedSticker.tgs") + else: + file.seek(0) + await conv.send_file(file, force_document=True) + rsp = await conv.get_response() + if "Sorry, the file type is invalid." in rsp.text: + await xx.edit( + "`Failed to add sticker, use` @Stickers `bot to add the sticker manually.`" + ) + return + await conv.send_message(emoji) + await ultroid_bot.send_read_acknowledge(conv.chat_id) + await conv.get_response() + await conv.send_message("/publish") + if is_anim: + await conv.get_response() + await conv.send_message(f"<{packnick}>") + + await conv.get_response() + await ultroid_bot.send_read_acknowledge(conv.chat_id) + await conv.send_message("/skip") + await ultroid_bot.send_read_acknowledge(conv.chat_id) + await conv.get_response() + await conv.send_message(packname) + await ultroid_bot.send_read_acknowledge(conv.chat_id) + await conv.get_response() + await ultroid_bot.send_read_acknowledge(conv.chat_id) + await xx.edit( + f"`Kanged!`\ + \n`Emoji` - {emoji}\ + \n`Sticker Pack` [here](t.me/addstickers/{packname})", + parse_mode="md", + ) + try: + os.remove(photo) + except BaseException: + pass + + +@ultroid_cmd( + pattern="round$", +) +async def ultdround(event): + ureply = await event.get_reply_message() + xx = await eor(event, "`Processing...`") + if not (ureply and (ureply.media)): + await xx.edit("`Reply to any media`") + return + ultt = await ureply.download_media() + if ultt.endswith(".tgs"): + await xx.edit("`Ooo Animated Sticker 👀...`") + cmd = ["lottie_convert.py", ultt, "ult.png"] + file = "ult.png" + process = await asyncio.create_subprocess_exec( + *cmd, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE + ) + stdout, stderr = await process.communicate() + stderr.decode().strip() + stdout.decode().strip() + elif ultt.endswith((".gif", ".mp4", ".mkv")): + await xx.edit("`Processing...`") + img = cv2.VideoCapture(ultt) + heh, lol = img.read() + cv2.imwrite("ult.png", lol) + file = "ult.png" + else: + file = ultt + img = Image.open(file).convert("RGB") + npImage = np.array(img) + h, w = img.size + alpha = Image.new("L", img.size, 0) + draw = ImageDraw.Draw(alpha) + draw.pieslice([0, 0, h, w], 0, 360, fill=255) + npAlpha = np.array(alpha) + npImage = np.dstack((npImage, npAlpha)) + Image.fromarray(npImage).save("ult.webp") + await event.client.send_file( + event.chat_id, "ult.webp", force_document=False, reply_to=event.reply_to_msg_id + ) + await xx.delete() + os.remove(file) + os.remove("ult.webp") + os.remove(ultt) + + +@ultroid_cmd( + pattern="destroy$", +) +async def ultdestroy(event): + ult = await event.get_reply_message() + if not (ult and ("tgsticker" in ult.media.document.mime_type)): + await eor(event, "`Reply to Animated Sticker Only...`") + return + roid = await event.client.download_media(ult, "ultroid.tgs") + xx = await eor(event, "`Processing...`") + os.system("lottie_convert.py ultroid.tgs json.json") + json = open("json.json", "r") + jsn = json.read() + json.close() + jsn = ( + jsn.replace("[100]", "[200]") + .replace("[10]", "[40]") + .replace("[-1]", "[-10]") + .replace("[0]", "[15]") + .replace("[1]", "[20]") + .replace("[2]", "[17]") + .replace("[3]", "[40]") + .replace("[4]", "[37]") + .replace("[5]", "[60]") + .replace("[6]", "[70]") + .replace("[7]", "[40]") + .replace("[8]", "[37]") + .replace("[9]", "[110]") + ) + open("json.json", "w").write(jsn) + os.system("lottie_convert.py json.json ultroid.tgs") + await event.client.send_file( + event.chat_id, + file="ultroid.tgs", + force_document=False, + reply_to=event.reply_to_msg_id, + ) + await xx.delete() + os.remove("ultroid.tgs") + os.remove("json.json") + os.remove(roid) + + +@ultroid_cmd( + pattern="tiny$", +) +async def ultiny(event): + reply = await event.get_reply_message() + if not (reply and (reply.media)): + await eor(event, "`Reply To Media`") + return + xx = await eor(event, "`processing...`") + ik = await ultroid_bot.download_media(reply) + im1 = Image.open("resources/extras/ultroid_blank.png") + if ik.endswith(".tgs"): + await event.client.download_media(reply, "ult.tgs") + os.system("lottie_convert.py ult.tgs json.json") + json = open("json.json", "r") + jsn = json.read() + json.close() + jsn = jsn.replace("512", "2000") + open("json.json", "w").write(jsn) + os.system("lottie_convert.py json.json ult.tgs") + file = "ult.tgs" + os.remove("json.json") + elif ik.endswith((".gif", ".mp4")): + iik = cv2.VideoCapture(ik) + dani, busy = iik.read() + cv2.imwrite("i.png", busy) + fil = "i.png" + im = Image.open(fil) + z, d = im.size + if z == d: + xxx, yyy = 200, 200 + else: + t = z + d + a = z / t + b = d / t + aa = (a * 100) - 50 + bb = (b * 100) - 50 + xxx = 200 + 5 * aa + yyy = 200 + 5 * bb + k = im.resize((int(xxx), int(yyy))) + k.save("k.png", format="PNG", optimize=True) + im2 = Image.open("k.png") + back_im = im1.copy() + back_im.paste(im2, (150, 0)) + back_im.save("o.webp", "WEBP", quality=95) + file = "o.webp" + os.remove(fil) + os.remove("k.png") + else: + im = Image.open(ik) + z, d = im.size + if z == d: + xxx, yyy = 200, 200 + else: + t = z + d + a = z / t + b = d / t + aa = (a * 100) - 50 + bb = (b * 100) - 50 + xxx = 200 + 5 * aa + yyy = 200 + 5 * bb + k = im.resize((int(xxx), int(yyy))) + k.save("k.png", format="PNG", optimize=True) + im2 = Image.open("k.png") + back_im = im1.copy() + back_im.paste(im2, (150, 0)) + back_im.save("o.webp", "WEBP", quality=95) + file = "o.webp" + os.remove("k.png") + await event.client.send_file(event.chat_id, file, reply_to=event.reply_to_msg_id) + await xx.delete() + os.remove(file) + os.remove(ik) + + +HELP.update({f"{__name__.split('.')[1]}": f"{__doc__.format(i=Var.HNDLR)}"}) diff --git a/plugins/sudo.py b/plugins/sudo.py new file mode 100644 index 0000000000..d5c1a84c6d --- /dev/null +++ b/plugins/sudo.py @@ -0,0 +1,194 @@ +# Ultroid - UserBot +# Copyright (C) 2020 TeamUltroid +# +# This file is a part of < https://github.com/TeamUltroid/Ultroid/ > +# PLease read the GNU Affero General Public License in +# . + +""" +✘ Commands Available - + +• `{i}addsudo` + Add Sudo Users by replying to user or using separated userid(s) + +• `{i}delsudo` + Remove Sudo Users by replying to user or using separated userid(s) + +• `{i}listsudo` + List all sudo users. +""" + +import re + +from telethon.tl.functions.users import GetFullUserRequest + +from . import * + + +@ultroid_cmd( + pattern="addsudo ?(.*)", +) +async def _(ult): + ok = await eor(ult, "`Updating SUDO Users List ...`") + + if ult.reply_to_msg_id: + replied_to = await ult.get_reply_message() + id = replied_to.sender.id + user = await ult.client(GetFullUserRequest(int(id))) + sed.append(id) + if id == ultroid_bot.me.id: + return await ok.edit("You cant add yourself as Sudo User...") + elif is_sudo(id): + return await ok.edit( + f"[{user.user.first_name}](tg://user?id={id}) `is already a SUDO User ...`" + ) + elif add_sudo(id): + return await ok.edit( + f"**Added [{user.user.first_name}](tg://user?id={id}) as SUDO User**" + ) + else: + return await ok.edit("`SEEMS LIKE THIS FUNCTION CHOOSE TO BROKE ITSELF`") + + args = ult.pattern_match.group(1).strip() + + if re.search(r"[\s]", args) is not None: + args = args.split(" ") + msg = "" + sudos = get_sudos() + for item in args: + user = "" + try: + user = await ult.client(GetFullUserRequest(int(item))) + except BaseException: + pass + if not hasattr(user, "user"): + msg += f"• `{item}` __Invalid UserID__\n" + elif item in sudos: + msg += f"• [{user.user.first_name}](tg://user?id={item}) __Already a SUDO__\n" + elif add_sudo(item.strip()): + msg += ( + f"• [{user.user.first_name}](tg://user?id={item}) __Added SUDO__\n" + ) + else: + msg += f"• `{item}` __Failed to Add SUDO__\n" + return await ok.edit(f"**Adding Sudo Users :**\n{msg}") + + id = args.strip() + user = "" + + try: + user = await ult.client(GetFullUserRequest(int(i))) + except BaseException: + pass + + if not id.isdigit(): + return await ok.edit("`Integer(s) Expected`") + elif not hasattr(user, "user"): + return await ok.edit("`Invalid UserID`") + elif is_sudo(id): + return await ok.edit( + f"[{user.user.first_name}](tg://user?id={id}) `is already a SUDO User ...`" + ) + elif add_sudo(id): + return await ok.edit( + f"**Added [{user.user.first_name}](tg://user?id={id}) as SUDO User**" + ) + else: + return await ok.edit(f"**Failed to add `{id}` as SUDO User ... **") + + +@ultroid_cmd( + pattern="delsudo ?(.*)", +) +async def _(ult): + ok = await eor(ult, "`Updating SUDO Users List ...`") + + if ult.reply_to_msg_id: + replied_to = await ult.get_reply_message() + id = replied_to.sender.id + user = await ult.client(GetFullUserRequest(int(id))) + sed.remove(id) + if not is_sudo(id): + return await ok.edit( + f"[{user.user.first_name}](tg://user?id={id}) `wasn't a SUDO User ...`" + ) + elif del_sudo(id): + return await ok.edit( + f"**Removed [{user.user.first_name}](tg://user?id={id}) from SUDO User(s)**" + ) + else: + return await ok.edit("`SEEMS LIKE THIS FUNCTION CHOOSE TO BROKE ITSELF`") + + args = ult.pattern_match.group(1) + + if re.search(r"[\s]", args) is not None: + args = args.split(" ") + msg = "" + sudos = get_sudos() + for item in args: + user = "" + try: + user = await ult.client(GetFullUserRequest(int(item))) + except BaseException: + pass + if not hasattr(user, "user"): + msg += f"• `{item}` __Invalid UserID__\n" + elif item in sudos and del_sudo(item): + msg += ( + f"• [{user.user.first_name}](tg://user?id={id}) __Removed SUDO__\n" + ) + elif item not in sudos: + msg += ( + f"• [{user.user.first_name}](tg://user?id={id}) __Wasn't a SUDO__\n" + ) + else: + msg += f"• `{item}` __Failed to Remove SUDO__\n" + return await ok.edit(msg) + + id = args.strip() + user = "" + + try: + user = await ult.client(GetFullUserRequest(int(i))) + except BaseException: + pass + + if not id.isdigit(): + return await ok.edit("`Integer(s) Expected`") + elif not hasattr(user, "user"): + return await ok.edit("`Invalid UserID`") + elif not is_sudo(id): + return await ok.edit( + f"[{user.user.first_name}](tg://user?id={id}) wasn't a SUDO user ..." + ) + elif del_sudo(id): + return await ok.edit( + f"**Removed [{user.user.first_name}](tg://user?id={id}) from SUDO User**" + ) + else: + return await ok.edit(f"**Failed to Remove `{id}` as SUDO User ... **") + + +@ultroid_cmd( + pattern="listsudo$", +) +async def _(ult): + ok = await eor(ult, "`...") + sudos = get_sudos() + if "" in sudos: + return await ok.edit("`No SUDO User was assigned ...`") + msg = "" + for i in sudos: + user = "" + try: + user = await ok.client(GetFullUserRequest(int(i.strip()))) + except BaseException: + pass + if hasattr(user, "user"): + msg += f"• [{user.user.first_name}](tg://user?id={i}) ( `{i}` )\n" + else: + msg += f"• `{i}` -> Invalid User\n" + return await ok.edit(f"**List of SUDO Users :**\n{msg}") + + +HELP.update({f"{__name__.split('.')[1]}": f"{__doc__.format(i=Var.HNDLR)}"}) diff --git a/plugins/superfban.py b/plugins/superfban.py new file mode 100644 index 0000000000..5d5e29e9ed --- /dev/null +++ b/plugins/superfban.py @@ -0,0 +1,328 @@ +# Ultroid - UserBot +# Copyright (C) 2020 TeamUltroid +# +# This file is a part of < https://github.com/TeamUltroid/Ultroid/ > +# PLease read the GNU Affero General Public License in +# . + +""" +✘ Commands Available - + +• `{i}superfban ` + FBan the person across all feds in which you are admin. + +• `{i}superunfban ` + Un-FBan the person across all feds in which you are admin. + +Specify FBan Group and Feds to exclude in the assistant. +""" + +import asyncio +import os + +from . import * + + +@ultroid_cmd(pattern="superfban ?(.*)") +async def _(event): + msg = await eor(event, "Starting a Mass-FedBan...") + fedList = [] + if event.reply_to_msg_id: + previous_message = await event.get_reply_message() + if previous_message.media: + downloaded_file_name = await ultroid_bot.download_media( + previous_message, "fedlist" + ) + file = open(downloaded_file_name, encoding="utf8") + lines = file.readlines() + for line in lines: + try: + fedList.append(line[:36]) + except BaseException: + pass + arg = event.text.split(" ", maxsplit=2) + if len(arg) > 2: + FBAN = arg[1] + REASON = arg[2] + else: + FBAN = arg[1] + REASON = " #TBMassBanned " + else: + FBAN = previous_message.sender_id + try: + REASON = event.text.split(" ", maxsplit=1)[1] + except BaseException: + REASON = "" + if REASON.strip() == "": + REASON = " #TBMassBanned " + else: + arg = event.text.split(" ", maxsplit=2) + if len(arg) > 2: + try: + FBAN = arg[1] + REASON = arg[2] + except BaseException: + return await msg.edit("`No user designated!`") + else: + try: + FBAN = arg[1] + REASON = " #TBMassBanned " + except BaseException: + return await msg.edit("`No user designated!`") + try: + if str(FBAN) in DEVLIST: + await msg.edit("You can't ban my dev you noob!!") + return + elif FBAN.startswith("@"): + try: + x = await ultroid_bot(GetFullUserRequest(FBAN)) + uid = x.user.id + if str(uid) in DEVLIST: + await msg.edit("You can't ban my dev you noob!!") + return + except Exception as e: + print(str(e)) + return await msg.edit(str(e)) + except Exception as e: + print(str(e)) + return await msg.edit(str(e)) + if udB.get("FBAN_GROUP_ID"): + chat = int(udB.get("FBAN_GROUP_ID")) + else: + chat = await event.get_chat() + if not len(fedList): + for a in range(3): + async with ultroid_bot.conversation("@MissRose_bot") as bot_conv: + await bot_conv.send_message("/start") + await asyncio.sleep(3) + await bot_conv.send_message("/myfeds") + await asyncio.sleep(3) + try: + response = await bot_conv.get_response() + except asyncio.exceptions.TimeoutError: + return await msg.edit( + "`Seems like rose isn't responding, or, the plugin is misbehaving`" + ) + await asyncio.sleep(3) + if "make a file" in response.text or "Looks like" in response.text: + await response.click(0) + await asyncio.sleep(3) + fedfile = await bot_conv.get_response() + await asyncio.sleep(3) + if fedfile.media: + downloaded_file_name = await ultroid_bot.download_media( + fedfile, "fedlist" + ) + await asyncio.sleep(6) + file = open(downloaded_file_name, "r", errors="ignore") + lines = file.readlines() + for line in lines: + try: + fedList.append(line[:36]) + except BaseException: + pass + elif "You can only use fed commands once every 5 minutes" in ( + await bot_conv.get_edit + ): + await msg.edit("Try again after 5 mins.") + return + if len(fedList) == 0: + await msg.edit( + f"Unable to collect FedAdminList. Retrying ({a+1}/3)..." + ) + else: + break + else: + await msg.edit("Error") + In = False + tempFedId = "" + for x in response.text: + if x == "`": + if In: + In = False + fedList.append(tempFedId) + tempFedId = "" + else: + In = True + elif In: + tempFedId += x + if len(fedList) == 0: + await msg.edit("Unable to collect FedAdminList.") + return + await msg.edit(f"FBaning in {len(fedList)} feds.") + try: + await ultroid_bot.send_message(chat, f"/start") + except BaseException: + await msg.edit("Specified FBan Group ID is incorrect.") + return + await asyncio.sleep(3) + if udB.get("EXCLUDE_FED"): + excludeFed = udB.get("EXCLUDE_FED").split(" ") + for n in range(len(excludeFed)): + excludeFed[n] = excludeFed[n].strip() + exCount = 0 + for fed in fedList: + if udB.get("EXCLUDE_FED") and fed in excludeFed: + await ultroid_bot.send_message(chat, f"{fed} Excluded.") + exCount += 1 + continue + await ultroid_bot.send_message(chat, f"/joinfed {fed}") + await asyncio.sleep(3) + await ultroid_bot.send_message(chat, f"/fban {FBAN} {REASON}") + await asyncio.sleep(3) + try: + os.remove("fedlist") + except Exception as e: + print(f"Error in removing FedAdmin file.\n{str(e)}") + await msg.edit( + f"SuperFBan Completed.\nTotal Feds - {len(fedlist)}.\nExcluded - {exCount}.\n Affected {len(fedList) - exCount} feds.\n#TB" + ) + + +@ultroid_cmd(pattern="superunfban ?(.*)") +async def _(event): + msg = await eor(event, "Starting a Mass-UnFedBan...") + fedList = [] + if event.reply_to_msg_id: + previous_message = await event.get_reply_message() + if previous_message.media: + downloaded_file_name = await ultroid_bot.download_media( + previous_message, "fedlist" + ) + file = open(downloaded_file_name, encoding="utf8") + lines = file.readlines() + for line in lines: + try: + fedList.append(line[:36]) + except BaseException: + pass + arg = event.text.split(" ", maxsplit=2) + if len(arg) > 2: + FBAN = arg[1] + REASON = arg[2] # rose unbans now can have reasons + else: + FBAN = arg[1] + REASON = "" + else: + FBAN = previous_message.sender_id + try: + REASON = event.text.split(" ", maxsplit=1)[1] + except BaseException: + REASON = "" + if REASON.strip() == "": + REASON = "" + else: + arg = event.text.split(" ", maxsplit=2) + if len(arg) > 2: + try: + FBAN = arg[1] + REASON = arg[2] + except BaseException: + return await msg.edit("`No user designated!`") + else: + try: + FBAN = arg[1] + REASON = " #TBMassUnBanned " + except BaseException: + return await msg.edit("`No user designated!`") + try: + if str(FBAN) in DEVLIST: + await msg.edit("You can't ban my dev you noob!!") + return + except Exception as e: + print(str(e)) + return await msg.edit(str(e)) + if udB.get("FBAN_GROUP_ID"): + chat = int(udB.get("FBAN_GROUP_ID")) + else: + chat = await event.get_chat() + if not len(fedList): + for a in range(3): + async with ultroid_bot.conversation("@MissRose_bot") as bot_conv: + await bot_conv.send_message("/start") + await asyncio.sleep(3) + await bot_conv.send_message("/myfeds") + await asyncio.sleep(3) + try: + response = await bot_conv.get_response() + except asyncio.exceptions.TimeoutError: + return await msg.edit( + "`Seems like rose isn't responding, or, the plugin is misbehaving`" + ) + await asyncio.sleep(3) + if "make a file" in response.text or "Looks like" in response.text: + await response.click(0) + await asyncio.sleep(3) + fedfile = await bot_conv.get_response() + await asyncio.sleep(3) + if fedfile.media: + downloaded_file_name = await ultroid_bot.download_media( + fedfile, "fedlist" + ) + await asyncio.sleep(6) + file = open(downloaded_file_name, "r", errors="ignore") + lines = file.readlines() + for line in lines: + try: + fedList.append(line[:36]) + except BaseException: + pass + elif "You can only use fed commands once every 5 minutes" in ( + await bot_conv.get_edit + ): + await msg.edit("Try again after 5 mins.") + return + if len(fedList) == 0: + await msg.edit( + f"Unable to collect FedAdminList. Retrying ({a+1}/3)..." + ) + else: + break + else: + await msg.edit("Error") + In = False + tempFedId = "" + for x in response.text: + if x == "`": + if In: + In = False + fedList.append(tempFedId) + tempFedId = "" + else: + In = True + elif In: + tempFedId += x + if len(fedList) == 0: + await msg.edit("Unable to collect FedAdminList.") + return + await msg.edit(f"UnFBaning in {len(fedList)} feds.") + try: + await ultroid_bot.send_message(chat, f"/start") + except BaseException: + await msg.edit("Specified FBan Group ID is incorrect.") + return + await asyncio.sleep(3) + if udB.get("EXCLUDE_FED"): + excludeFed = udB.get("EXCLUDE_FED").split(" ") + for n in range(len(excludeFed)): + excludeFed[n] = excludeFed[n].strip() + exCount = 0 + for fed in fedList: + if udB.get("EXCLUDE_FED") and fed in excludeFed: + await ultroid_bot.send_message(chat, f"{fed} Excluded.") + exCount += 1 + continue + await ultroid_bot.send_message(chat, f"/joinfed {fed}") + await asyncio.sleep(3) + await ultroid_bot.send_message(chat, f"/unfban {FBAN} {REASON}") + await asyncio.sleep(3) + try: + os.remove("fedlist") + except Exception as e: + print(f"Error in removing FedAdmin file.\n{str(e)}") + await msg.edit( + f"SuperUnFBan Completed.\nTotal Feds - {len(fedlist)}.\nExcluded - {exCount}.\n Affected {len(fedList) - exCount} feds.\n#TB" + ) + + +HELP.update({f"{__name__.split('.')[1]}": f"{__doc__.format(i=Var.HNDLR)}"}) diff --git a/plugins/tools.py b/plugins/tools.py new file mode 100644 index 0000000000..314e36cb67 --- /dev/null +++ b/plugins/tools.py @@ -0,0 +1,411 @@ +# Ultroid - UserBot +# Copyright (C) 2020 TeamUltroid +# +# This file is a part of < https://github.com/TeamUltroid/Ultroid/ > +# PLease read the GNU Affero General Public License in +# . + +""" +✘ Commands Available - + +• `{i}bash ` + Run linux commands on telegram. + +• `{i}eval ` + Evaluate python commands on telegram. + +• `{i}circle` + Reply to a audio song or gif to get video note. + +• `{i}bots` + Shows the number of bots in the current chat with their perma-link. + +• `{i}hl` + {i}hl hyperlinks the message by editing the message with a blank text. + +• `{i}id` + Reply a Sticker to Get Its Id + Reply a User to Get His Id + Without Replying You Will Get the Chat's Id + +• `{i}sg` + Reply The User to Get His Name History + +• `{i}tr ` + Reply to a message with `{i}tr ` + Use `{i}tr ` + To get translated message. +""" + +import asyncio +import io +import sys +import time +import traceback +from asyncio.exceptions import TimeoutError + +import cv2 +import emoji +from googletrans import Translator +from telethon.errors.rpcerrorlist import YouBlockedUserError +from telethon.tl.types import ChannelParticipantAdmin, ChannelParticipantsBots +from telethon.utils import pack_bot_file_id + +from . import * + + +@ultroid_cmd( + pattern="tr", +) +async def _(event): + input = event.text[4:6] + txt = event.text[7:] + xx = await eor(event, "`Translating...`") + if event.reply_to_msg_id: + previous_message = await event.get_reply_message() + text = previous_message.message + lan = input or "en" + elif input: + text = txt + lan = input or "en" + else: + return await eod(xx, f"`{hndlr}tr LanguageCode` as reply to a message", time=5) + text = emoji.demojize(text.strip()) + lan = lan.strip() + translator = Translator() + try: + tt = translator.translate(text, dest=lan) + output_str = f"**TRANSLATED** from {tt.src} to {lan}\n{tt.text}" + await eod(xx, output_str) + except Exception as exc: + await eod(xx, str(exc), time=10) + + +@ultroid_cmd( + pattern="id$", +) +async def _(event): + if event.reply_to_msg_id: + await event.get_input_chat() + r_msg = await event.get_reply_message() + if r_msg.media: + bot_api_file_id = pack_bot_file_id(r_msg.media) + await eor( + event, + "**Current Chat ID:** `{}`\n**From User ID:** `{}`\n**Bot API File ID:** `{}`".format( + str(event.chat_id), str(r_msg.sender.id), bot_api_file_id + ), + ) + else: + await eor( + event, + "**Chat ID:** `{}`\n**User ID:** `{}`".format( + str(event.chat_id), str(r_msg.sender.id) + ), + ) + else: + await eor(event, "**Current Chat ID:** `{}`".format(str(event.chat_id))) + + +@ultroid_cmd(pattern="bots ?(.*)") +async def _(ult): + mentions = "**Bots in this Chat**: \n" + input_str = ult.pattern_match.group(1) + to_write_chat = await ult.get_input_chat() + chat = None + if not input_str: + chat = to_write_chat + else: + mentions = "**Bots in **{}: \n".format(input_str) + try: + chat = await ultroid_bot.get_entity(input_str) + except Exception as e: + await eor(ult, str(e)) + return None + try: + async for x in ultroid_bot.iter_participants( + chat, filter=ChannelParticipantsBots + ): + if isinstance(x.participant, ChannelParticipantAdmin): + mentions += "\n ⚜️ [{}](tg://user?id={}) `{}`".format( + x.first_name, x.id, x.id + ) + else: + mentions += "\n [{}](tg://user?id={}) `{}`".format( + x.first_name, x.id, x.id + ) + except Exception as e: + mentions += " " + str(e) + "\n" + await eod(ult, mentions) + + +@ultroid_cmd(pattern="hl") +async def _(ult): + try: + input = ult.text.split(" ", maxsplit=1)[1] + except IndexError: + return await eod(ult, "`Input some link`", time=5) + await eod(ult, "[ㅤㅤㅤㅤㅤㅤㅤ](" + input + ")", link_preview=False) + + +@ultroid_cmd( + pattern="circle$", +) +async def _(e): + a = await e.get_reply_message() + if a is None: + return await eor(e, "Reply to a gif or audio") + if a.document and a.document.mime_type == "audio/mpeg": + z = await eor(e, "**Cʀᴇᴀᴛɪɴɢ Vɪᴅᴇᴏ Nᴏᴛᴇ**") + toime = time.time() + try: + bbbb = await a.download_media(thumb=-1) + im = cv2.imread(bbbb) + dsize = (320, 320) + output = cv2.resize(im, dsize, interpolation=cv2.INTER_AREA) + cv2.imwrite("img.png", output) + thumb = "img.png" + except TypeError: + thumb = "./resources/extras/thumb.jpg" + c = await a.download_media( + "resources/downloads/", + progress_callback=lambda d, t: asyncio.get_event_loop().create_task( + progress(d, t, z, toime, "**Dᴏᴡɴʟᴏᴀᴅɪɴɢ...**") + ), + ) + await z.edit("**Dᴏᴡɴʟᴏᴀᴅᴇᴅ...\nNᴏᴡ Cᴏɴᴠᴇʀᴛɪɴɢ...**") + cmd = [ + "ffmpeg", + "-i", + c, + "-acodec", + "libmp3lame", + "-ac", + "2", + "-ab", + "144k", + "-ar", + "44100", + "comp.mp3", + ] + proess = await asyncio.create_subprocess_exec( + *cmd, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE + ) + stdout, stderr = await proess.communicate() + stderr.decode().strip() + stdout.decode().strip() + mcd = [ + "ffmpeg", + "-y", + "-i", + thumb, + "-i", + "comp.mp3", + "-c:a", + "copy", + "circle.mp4", + ] + process = await asyncio.create_subprocess_exec( + *mcd, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE + ) + stdout, stderr = await process.communicate() + stderr.decode().strip() + stdout.decode().strip() + taime = time.time() + await e.client.send_file( + e.chat_id, + "circle.mp4", + thumb=thumb, + video_note=True, + reply_to=a, + progress_callback=lambda d, t: asyncio.get_event_loop().create_task( + progress(d, t, z, taime, "**Uᴘʟᴏᴀᴅɪɴɢ...**") + ), + ) + await z.delete() + os.system("rm resources/downloads/*") + os.system("rm circle.mp4 comp.mp3 img.png") + os.remove(bbbb) + elif a.document and a.document.mime_type == "video/mp4": + z = await eor(e, "**Cʀᴇᴀᴛɪɴɢ Vɪᴅᴇᴏ Nᴏᴛᴇ**") + c = await a.download_media("resources/downloads/") + await e.client.send_file(e.chat_id, c, video_note=True, reply_to=a) + await z.delete() + os.remove(c) + else: + return await eor(e, "**Reply to a gif or audio file only**") + + +@ultroid_cmd( + pattern="bash", +) +async def _(event): + if (Var.I_DEV if Var.I_DEV else Redis("I_DEV")) != "True": + await eor( + event, + "Developer Restricted!\nIf you know what this does, and want to proceed\n\n set var `I_DEV` as `True`\n\nThis Might Be Dangerous.", + ) + return + xx = await eor(event, "`Processing...`") + try: + cmd = event.text.split(" ", maxsplit=1)[1] + except IndexError: + return await eod(xx, "`No cmd given`", time=10) + reply_to_id = event.message.id + if event.reply_to_msg_id: + reply_to_id = event.reply_to_msg_id + time.time() + 100 + process = await asyncio.create_subprocess_shell( + cmd, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE + ) + stdout, stderr = await process.communicate() + OUT = f"**☞ BASH\n\n• COMMAND:**\n`{cmd}` \n\n" + e = stderr.decode() + if e: + OUT += f"**• ERROR:** \n`{e}`\n" + o = stdout.decode() + if not o and not e: + o = "Success" + OUT += f"**• OUTPUT:**\n`{o}`" + else: + _o = o.split("\n") + o = "`\n".join(_o) + OUT += f"**• OUTPUT:**\n{o}" + if len(OUT) > 4096: + with io.BytesIO(str.encode(OUT)) as out_file: + out_file.name = "bash.txt" + await event.client.send_file( + event.chat_id, + out_file, + force_document=True, + allow_cache=False, + caption=f"`{cmd}`", + reply_to=reply_to_id, + ) + await xx.delete() + else: + await eod(xx, OUT) + + +@ultroid_cmd( + pattern="eval", +) +async def _(event): + if (Var.I_DEV if Var.I_DEV else Redis("I_DEV")) != "True": + await eor( + event, + "Developer Restricted!\nIf you know what this does, and want to proceed\n\n set var `I_DEV` as `True`\n\nThis Might Be Dangerous.", + ) + return + xx = await eor(event, "`Processing ...`") + try: + cmd = event.text.split(" ", maxsplit=1)[1] + except IndexError: + return await eod(xx, "`Give some python cmd`", time=5) + if event.reply_to_msg_id: + reply_to_id = event.reply_to_msg_id + old_stderr = sys.stderr + old_stdout = sys.stdout + redirected_output = sys.stdout = io.StringIO() + redirected_error = sys.stderr = io.StringIO() + stdout, stderr, exc = None, None, None + reply_to_id = event.message.id + try: + await aexec(cmd, event) + except Exception: + exc = traceback.format_exc() + stdout = redirected_output.getvalue() + stderr = redirected_error.getvalue() + sys.stdout = old_stdout + sys.stderr = old_stderr + evaluation = "" + if exc: + evaluation = exc + elif stderr: + evaluation = stderr + elif stdout: + evaluation = stdout + else: + evaluation = "Success" + final_output = ( + "__►__ **EVAL**\n```{}``` \n\n __►__ **OUTPUT**: \n```{}``` \n".format( + cmd, evaluation + ) + ) + if len(final_output) > 4096: + with io.BytesIO(str.encode(final_output)) as out_file: + out_file.name = "eval.txt" + await ultroid_bot.send_file( + event.chat_id, + out_file, + force_document=True, + allow_cache=False, + caption=f"```{cmd}```", + reply_to=reply_to_id, + ) + await xx.delete() + else: + await eod(xx, final_output) + + +async def aexec(code, event): + e = message = event + client = event.client + exec( + f"async def __aexec(e, client): " + + "\n message = event = e" + + "".join(f"\n {l}" for l in code.split("\n")) + ) + + return await locals()["__aexec"](e, e.client) + + +@ultroid_cmd( + pattern="sg(?: |$)(.*)", +) +async def lastname(steal): + if steal.fwd_from: + return + if not steal.reply_to_msg_id: + await steal.edit("Reply to any user message.") + return + message = await steal.get_reply_message() + chat = "@SangMataInfo_bot" + user_id = message.sender.id + id = f"/search_id {user_id}" + if message.sender.bot: + await steal.edit("Reply to actual users message.") + return + lol = await eor(steal, "Processingg !!!!!") + try: + async with ultroid_bot.conversation(chat) as conv: + try: + msg = await conv.send_message(id) + response = await conv.get_response() + respond = await conv.get_response() + responds = await conv.get_response() + except YouBlockedUserError: + await lol.edit("Please unblock @sangmatainfo_bot and try again") + return + if response.text.startswith("No records found"): + await lol.edit("No records found for this user") + await steal.client.delete_messages(conv.chat_id, [msg.id, response.id]) + return + else: + if response.text.startswith("🔗"): + await lol.edit(respond.message) + await lol.reply(responds.message) + elif respond.text.startswith("🔗"): + await lol.edit(response.message) + await lol.reply(responds.message) + else: + await lol.edit(respond.message) + await lol.reply(response.message) + await steal.client.delete_messages( + conv.chat_id, [msg.id, responds.id, respond.id, response.id] + ) + except TimeoutError: + return await lol.edit("Error: @SangMataInfo_bot is not responding!.") + + +HELP.update({f"{__name__.split('.')[1]}": f"{__doc__.format(i=Var.HNDLR)}"}) diff --git a/plugins/updater.py b/plugins/updater.py new file mode 100644 index 0000000000..a05f0e185f --- /dev/null +++ b/plugins/updater.py @@ -0,0 +1,178 @@ +# Ultroid - UserBot +# Copyright (C) 2020 TeamUltroid +# +# This file is a part of < https://github.com/TeamUltroid/Ultroid/ > +# PLease read the GNU Affero General Public License in +# . + +import asyncio +import sys +from os import environ, execle, path, remove + +from git import Repo +from git.exc import GitCommandError, InvalidGitRepositoryError, NoSuchPathError + +UPSTREAM_REPO_URL = "https://github.com/TeamUltroid/Ultroid" +requirements_path = path.join( + path.dirname(path.dirname(path.dirname(__file__))), "requirements.txt" +) + + +async def gen_chlog(repo, diff): + ch_log = "" + d_form = "On %d/%m/%y at %H:%M:%S" + for c in repo.iter_commits(diff): + ch_log += f"**#{c.count()}** : {c.committed_datetime.strftime(d_form)} : [{c.summary}]({UPSTREAM_REPO_URL.rstrip('/')}/commit/{c}) by `{c.author}`\n" + return ch_log + + +async def updateme_requirements(): + reqs = str(requirements_path) + try: + process = await asyncio.create_subprocess_shell( + " ".join([sys.executable, "-m", "pip", "install", "-r", reqs]), + stdout=asyncio.subprocess.PIPE, + stderr=asyncio.subprocess.PIPE, + ) + await process.communicate() + return process.returncode + except Exception as e: + return repr(e) + + +@ultroid_cmd( + pattern="update ?(.*)", +) +async def upstream(ups): + pagal = await eor(ups, "`Checking for updates, please wait....`") + conf = ups.pattern_match.group(1) + off_repo = UPSTREAM_REPO_URL + try: + txt = "`Oops.. Updater cannot continue due to " + txt += "some problems occured`\n\n**LOGTRACE:**\n" + repo = Repo() + except NoSuchPathError as error: + await eod(pagal, f"{txt}\n`directory {error} is not found`", time=10) + repo.__del__() + return + except GitCommandError as error: + await eod(pagal, f"{txt}\n`Early failure! {error}`", time=10) + repo.__del__() + return + except InvalidGitRepositoryError as error: + if conf != "now": + await eod( + pagal, + f"**Unfortunately, the directory {error} does not seem to be a git repository.Or Maybe it just needs a sync verification with {GIT_REPO_NAME} But we can fix that by force updating the userbot using** `.update now.`", + time=30, + ) + return + repo = Repo.init() + origin = repo.create_remote("upstream", off_repo) + origin.fetch() + repo.create_head("main", origin.refs.main) + repo.heads.main.set_tracking_branch(origin.refs.main) + repo.heads.main.checkout(True) + ac_br = repo.active_branch.name + if ac_br != "main": + await eod( + pagal, + f"**[UPDATER]:**` You are on ({ac_br})\n Please change to main branch.`", + ) + repo.__del__() + return + try: + repo.create_remote("upstream", off_repo) + except BaseException: + pass + ups_rem = repo.remote("upstream") + ups_rem.fetch(ac_br) + changelog = await gen_chlog(repo, f"HEAD..upstream/{ac_br}") + if "now" not in conf: + if changelog: + changelog_str = f"**New UPDATE available for [[{ac_br}]]({UPSTREAM_REPO_URL}/tree/{ac_br}):\n\nCHANGELOG**\n\n{changelog}" + if len(changelog_str) > 4096: + await eor(pagal, "`Changelog is too big, view the file to see it.`") + file = open("output.txt", "w+") + file.write(changelog_str) + file.close() + await ups.client.send_file( + ups.chat_id, + "output.txt", + caption=f"Do `{hndlr}update now` to update.", + reply_to=ups.id, + ) + remove("output.txt") + else: + return await eod( + pagal, f"{changelog_str}\n\nDo `{hndlr}update now` to update." + ) + else: + await eod( + pagal, + f"\n`Your BOT is` **up-to-date** `with` **[[{ac_br}]]({UPSTREAM_REPO_URL}/tree/{ac_br})**\n", + time=10, + ) + repo.__del__() + return + if Var.HEROKU_API is not None: + import heroku3 + + heroku = heroku3.from_key(Var.HEROKU_API) + heroku_app = None + heroku_applications = heroku.apps() + if not Var.HEROKU_APP_NAME: + await eod( + pagal, + "`Please set up the HEROKU_APP_NAME variable to be able to update userbot.`", + time=10, + ) + repo.__del__() + return + for app in heroku_applications: + if app.name == Var.HEROKU_APP_NAME: + heroku_app = app + break + if heroku_app is None: + await eod( + pagal, + f"{txt}\n`Invalid Heroku credentials for updating userbot dyno.`", + time=10, + ) + repo.__del__() + return + await eor( + pagal, "`Userbot dyno build in progress, please wait for it to complete.`" + ) + ups_rem.fetch(ac_br) + repo.git.reset("--hard", "FETCH_HEAD") + heroku_git_url = heroku_app.git_url.replace( + "https://", "https://api:" + Var.HEROKU_API + "@" + ) + if "heroku" in repo.remotes: + remote = repo.remote("heroku") + remote.set_url(heroku_git_url) + else: + remote = repo.create_remote("heroku", heroku_git_url) + try: + remote.push(refspec=f"HEAD:refs/heads/{ac_br}", force=True) + except GitCommandError as error: + await eod(pagal, f"{txt}\n`Here is the error log:\n{error}`", time=10) + repo.__del__() + return + await eod(pagal, "`Successfully Updated!\nRestarting, please wait...`", time=60) + else: + # Classic Updater, pretty straightforward. + try: + ups_rem.pull(ac_br) + except GitCommandError: + repo.git.reset("--hard", "FETCH_HEAD") + await updateme_requirements() + await eod( + pagal, + "`Successfully Updated!\nBot is restarting... Wait for a second!`", + ) + # Spin a new instance of bot + args = [sys.executable, "./resources/startup/deploy.sh"] + execle(sys.executable, *args, environ) + return diff --git a/plugins/uploads_files.py b/plugins/uploads_files.py new file mode 100644 index 0000000000..0501e8fa08 --- /dev/null +++ b/plugins/uploads_files.py @@ -0,0 +1,175 @@ +# Ultroid - UserBot +# Copyright (C) 2020 TeamUltroid +# +# This file is a part of < https://github.com/TeamUltroid/Ultroid/ > +# PLease read the GNU Affero General Public License in +# . + +""" +✘ Commands Available - + +• `{i}ul ` + Upload file to telegram chat. + +• `{i}dl ` + Reply to file to download. + +• `{i}save ` + Reply to a text msg to save it in a file. + +• `{i}open` + Reply to a file to reveal it's text. +""" + +import asyncio +import os +import time +from datetime import datetime as dt + +from . import * + +opn = [] + + +@ultroid_cmd( + pattern="dl ?(.*)", +) +async def download(event): + xx = await eor(event, "`Processing...`") + kk = event.pattern_match.group(1) + s = dt.now() + k = time.time() + if event.reply_to_msg_id: + ok = await event.get_reply_message() + if not ok.media: + return await eod(xx, "`Reply The File/Media u Want to Download..`", time=5) + else: + if not kk: + d = "resources/downloads/" + o = await event.client.download_media( + ok, + d, + progress_callback=lambda d, t: asyncio.get_event_loop().create_task( + progress( + d, + t, + xx, + k, + "Downloading...", + ) + ), + ) + else: + d = f"resources/downloads/{kk}" + o = await event.client.download_media( + ok, + d, + progress_callback=lambda d, t: asyncio.get_event_loop().create_task( + progress( + d, + t, + xx, + k, + "Downloading...", + file_name=d, + ) + ), + ) + e = datetime.now() + t = convert((e - s).seconds) + await eod(xx, f"Download Successful..\nTo\n`{o}`\nin `{t}`") + + +@ultroid_cmd( + pattern="ul ?(.*)", +) +async def download(event): + xx = await eor(event, "`Processing...`") + kk = event.pattern_match.group(1) + s = dt.now() + tt = time.time() + if not kk: + return await eod(xx, "`Give a specific path to file`") + else: + try: + x = await event.client.send_file( + event.chat_id, + kk, + caption=kk, + progress_callback=lambda d, t: asyncio.get_event_loop().create_task( + progress( + d, + t, + xx, + tt, + "Uploading...", + file_name=kk, + ) + ), + ) + except ValueError as ve: + return await eod(xx, str(ve)) + e = datetime.now() + t = convert((e - s).seconds) + try: + await x.edit(f"`{kk}`\nTime Taken: `{t}`") + except BaseException: + pass + await eod(xx, f"Uploaded `{kk}` in `{t}`", time=5) + + +@ultroid_cmd( + pattern="save", +) +async def _(event): + input_str = event.text[6:] + xx = await eor(event, "`Processing...`") + if event.reply_to_msg_id: + a = await event.get_reply_message() + if not a.message: + return await xx.edit("`Reply to a message`") + else: + b = open(input_str, "w") + b.write(str(a.message)) + b.close() + await xx.edit(f"**Packing into** `{input_str}`") + await asyncio.sleep(2) + await xx.edit(f"**Uploading** `{input_str}`") + await asyncio.sleep(2) + await event.client.send_file(event.chat_id, input_str) + await xx.delete() + os.remove(input_str) + + +@ultroid_cmd( + pattern="open$", +) +async def _(event): + xx = await eor(event, "`Processing...`") + if event.reply_to_msg_id: + a = await event.get_reply_message() + if a.media: + b = await a.download_media() + c = open(b, "r") + d = c.read() + c.close() + n = 4096 + for bkl in range(0, len(d), n): + opn.append(d[bkl : bkl + n]) + for bc in opn: + await event.client.send_message( + event.chat_id, + f"```{bc}```", + reply_to=event.reply_to_msg_id, + ) + await event.delete() + opn.clear() + os.remove(b) + await xx.delete() + else: + return await eod(xx, "`Reply to a readable file`", time=10) + else: + return await eod(xx, "`Reply to a readable file`", time=10) + + +HELP.update({f"{__name__.split('.')[1]}": f"{__doc__.format(i=Var.HNDLR)}"}) diff --git a/plugins/utilities.py b/plugins/utilities.py new file mode 100644 index 0000000000..b9fe0faadf --- /dev/null +++ b/plugins/utilities.py @@ -0,0 +1,583 @@ +# Ultroid - UserBot +# Copyright (C) 2020 TeamUltroid +# +# This file is a part of < https://github.com/TeamUltroid/Ultroid/ > +# PLease read the GNU Affero General Public License in +# . + +""" +✘ Commands Available - + +• `{i}kickme` + Leaves the group in which it is used. + +• `{i}calc ` + A simple calculator. + +• `{i}date` + Show Calender. + +• `{i}chatinfo` + Get full info about the group/chat. + +• `{i}listreserved` + List all usernames (channels/groups) you own. + +• `{i}stats` + See your profile stats. + +• `{i}paste` + Include long text / Reply to text file. + +• `{i}hastebin` + Include long text / Reply to text file. + +• `{i}info ` + Reply to someone's msg. + +• `{i}invite ` + Add user to the chat. + +• `{i}rmbg ` + Remove background from that picture. + +• `{i}telegraph ` + Upload media/text to telegraph. + +• `{i}json ` + Get the json encoding of the message. +""" +import asyncio +import calendar +import html +import io +import os +import sys +import time +import traceback +from datetime import datetime as dt + +import pytz +import requests +from telegraph import Telegraph +from telegraph import upload_file as uf +from telethon import functions +from telethon.errors.rpcerrorlist import BotInlineDisabledError, BotResponseTimeoutError +from telethon.events import NewMessage +from telethon.tl.custom import Dialog +from telethon.tl.functions.channels import LeaveChannelRequest +from telethon.tl.functions.photos import GetUserPhotosRequest +from telethon.tl.types import Channel, Chat, User +from telethon.utils import get_input_location + +# =================================================================# +from . import * + +TMP_DOWNLOAD_DIRECTORY = "resources/downloads/" + +# Telegraph Things +telegraph = Telegraph() +telegraph.create_account(short_name="Ultroid") +# ================================================================# + + +@ultroid_cmd( + pattern="kickme$", + groups_only=True, +) +async def leave(ult): + x = ultroid_bot.me + name = x.first_name + await eor(ult, f"`{name} has left this group, bye!!.`") + await ultroid_bot(LeaveChannelRequest(ult.chat_id)) + + +@ultroid_cmd( + pattern="date$", +) +async def date(event): + k = pytz.timezone("Asia/Kolkata") + m = dt.now(k).month + y = dt.now(k).year + d = dt.now(k).strftime("Date - %B %d, %Y\nTime- %H:%M:%S") + k = calendar.month(y, m) + ultroid = await eor(event, f"`{k}\n\n{d}`") + + +@ultroid_cmd( + pattern="calc", +) +async def _(event): + x = await eor(event, "...") + cmd = event.text.split(" ", maxsplit=1)[1] + event.message.id + if event.reply_to_msg_id: + event.reply_to_msg_id + wtf = f"print({cmd})" + old_stderr = sys.stderr + old_stdout = sys.stdout + redirected_output = sys.stdout = io.StringIO() + redirected_error = sys.stderr = io.StringIO() + stdout, stderr, exc = None, None, None + try: + await aexec(wtf, event) + except Exception: + exc = traceback.format_exc() + stdout = redirected_output.getvalue() + stderr = redirected_error.getvalue() + sys.stdout = old_stdout + sys.stderr = old_stderr + evaluation = "" + if exc: + evaluation = exc + elif stderr: + evaluation = stderr + elif stdout: + evaluation = stdout + else: + evaluation = "`Something went wrong`" + + final_output = """ +**EQUATION**: +`{}` +**SOLUTION**: +`{}` +""".format( + cmd, evaluation + ) + await x.edit(final_output) + + +async def aexec(code, event): + exec(f"async def __aexec(event): " + "".join(f"\n {l}" for l in code.split("\n"))) + return await locals()["__aexec"](event) + + +@ultroid_cmd( + pattern="chatinfo(?: |$)(.*)", +) +async def info(event): + ok = await eor(event, "`...`") + chat = await get_chatinfo(event) + caption = await fetch_info(chat, event) + try: + await ok.edit(caption, parse_mode="html") + except Exception as e: + print("Exception:", e) + await ok.edit(f"`An unexpected error has occurred. {e}`") + await asyncio.sleep(5) + await ok.delete() + return + + +@ultroid_cmd( + pattern="listreserved$", +) +async def _(event): + result = await ultroid_bot(functions.channels.GetAdminedPublicChannelsRequest()) + output_str = "" + r = result.chats + for channel_obj in r: + output_str += f"- {channel_obj.title} @{channel_obj.username} \n" + if not r: + await eor(event, "`Not username Reserved`") + else: + await eor(event, output_str) + + +@ultroid_cmd( + pattern="stats$", +) +async def stats( + event: NewMessage.Event, +) -> None: + ok = await eor(event, "`Collecting stats...`") + start_time = time.time() + private_chats = 0 + bots = 0 + groups = 0 + broadcast_channels = 0 + admin_in_groups = 0 + creator_in_groups = 0 + admin_in_broadcast_channels = 0 + creator_in_channels = 0 + unread_mentions = 0 + unread = 0 + dialog: Dialog + async for dialog in ultroid_bot.iter_dialogs(): + entity = dialog.entity + if isinstance(entity, Channel): + if entity.broadcast: + broadcast_channels += 1 + if entity.creator or entity.admin_rights: + admin_in_broadcast_channels += 1 + if entity.creator: + creator_in_channels += 1 + + elif entity.megagroup: + groups += 1 + if entity.creator or entity.admin_rights: + admin_in_groups += 1 + if entity.creator: + creator_in_groups += 1 + + elif isinstance(entity, User): + private_chats += 1 + if entity.bot: + bots += 1 + + elif isinstance(entity, Chat): + groups += 1 + if entity.creator or entity.admin_rights: + admin_in_groups += 1 + if entity.creator: + creator_in_groups += 1 + + unread_mentions += dialog.unread_mentions_count + unread += dialog.unread_count + stop_time = time.time() - start_time + + full_name = inline_mention(await ultroid_bot.get_me()) + response = f"🔸 **Stats for {full_name}** \n\n" + response += f"**Private Chats:** {private_chats} \n" + response += f"** •• **`Users: {private_chats - bots}` \n" + response += f"** •• **`Bots: {bots}` \n" + response += f"**Groups:** {groups} \n" + response += f"**Channels:** {broadcast_channels} \n" + response += f"**Admin in Groups:** {admin_in_groups} \n" + response += f"** •• **`Creator: {creator_in_groups}` \n" + response += f"** •• **`Admin Rights: {admin_in_groups - creator_in_groups}` \n" + response += f"**Admin in Channels:** {admin_in_broadcast_channels} \n" + response += f"** •• **`Creator: {creator_in_channels}` \n" + response += f"** •• **`Admin Rights: {admin_in_broadcast_channels - creator_in_channels}` \n" + response += f"**Unread:** {unread} \n" + response += f"**Unread Mentions:** {unread_mentions} \n\n" + response += f"**__It Took:__** {stop_time:.02f}s \n" + await ok.edit(response) + + +@ultroid_cmd( + pattern="paste( (.*)|$)", +) +async def _(event): + xx = await eor(event, "`...`") + input_str = "".join(event.text.split(maxsplit=1)[1:]) + if input_str: + message = input_str + downloaded_file_name = None + elif event.reply_to_msg_id: + previous_message = await event.get_reply_message() + if previous_message.media: + downloaded_file_name = await event.client.download_media( + previous_message, + "./resources/downloads", + ) + m_list = None + with open(downloaded_file_name, "rb") as fd: + m_list = fd.readlines() + message = "" + try: + for m in m_list: + message += m.decode("UTF-8") + except BaseException: + message = "`Include long text / Reply to text file`" + os.remove(downloaded_file_name) + else: + downloaded_file_name = None + message = previous_message.message + else: + downloaded_file_name = None + message = "`Include long text / Reply to text file`" + if downloaded_file_name and downloaded_file_name.endswith(".py"): + data = message + key = ( + requests.post("https://nekobin.com/api/documents", json={"content": data}) + .json() + .get("result") + .get("key") + ) + else: + data = message + key = ( + requests.post("https://nekobin.com/api/documents", json={"content": data}) + .json() + .get("result") + .get("key") + ) + q = f"paste-{key}" + try: + ok = await ultroid_bot.inline_query(Var.BOT_USERNAME, q) + await ok[0].click(event.chat_id, reply_to=event.reply_to_msg_id, hide_via=True) + await xx.delete() + except BotInlineDisabledError or BotResponseTimeoutError: # incase the bot doesnt respond + await xx.edit(reply_text) + + +@ultroid_cmd( + pattern="hastebin ?(.*)", +) +async def _(event): + input_str = event.pattern_match.group(1) + xx = await eor(event, "`Pasting...`") + message = "SYNTAX: `.paste `" + if input_str: + message = input_str + elif event.reply_to_msg_id: + previous_message = await event.get_reply_message() + if previous_message.media: + downloaded_file_name = await event.client.download_media( + previous_message, + "./resources/downloads", + ) + m_list = None + with open(downloaded_file_name, "rb") as fd: + m_list = fd.readlines() + message = "" + for m in m_list: + message += m.decode("UTF-8") + "\r\n" + os.remove(downloaded_file_name) + else: + message = previous_message.message + else: + message = "SYNTAX: `.hastebin `" + url = "https://hastebin.com/documents" + r = requests.post(url, data=message).json() + url = f"https://hastebin.com/{r['key']}" + await xx.edit("**Pasted to Hastebin** : [Link]({})".format(url)) + + +@ultroid_cmd( + pattern="info ?(.*)", +) +async def _(event): + xx = await eor(event, "`Processing...`") + replied_user, error_i_a = await get_full_user(event) + if replied_user is None: + await xx.edit("Please repl to a user.\nError - " + str(error_i_a)) + return False + replied_user_profile_photos = await event.client( + GetUserPhotosRequest( + user_id=replied_user.user.id, offset=42, max_id=0, limit=80 + ) + ) + replied_user_profile_photos_count = "NaN" + try: + replied_user_profile_photos_count = replied_user_profile_photos.count + except AttributeError: + pass + user_id = replied_user.user.id + first_name = html.escape(replied_user.user.first_name) + if first_name is not None: + first_name = first_name.replace("\u2060", "") + last_name = replied_user.user.last_name + last_name = ( + last_name.replace("\u2060", "") if last_name else ("Last Name not found") + ) + user_bio = replied_user.about + if user_bio is not None: + user_bio = html.escape(replied_user.about) + common_chats = replied_user.common_chats_count + try: + dc_id, location = get_input_location(replied_user.profile_photo) + except Exception as e: + dc_id = "Need a Profile Picture to check this" + str(e) + caption = """Exᴛʀᴀᴄᴛᴇᴅ Dᴀᴛᴀʙᴀsᴇ Fʀᴏᴍ Tᴇʟᴇɢʀᴀᴍ's Dᴀᴛᴀʙᴀsᴇ + ••Tᴇʟᴇɢʀᴀᴍ ID: {} + ••Pᴇʀᴍᴀɴᴇɴᴛ Lɪɴᴋ: Click Here + ••Fɪʀsᴛ Nᴀᴍᴇ: {} + ••Sᴇᴄᴏɴᴅ Nᴀᴍᴇ: {} + ••Bɪᴏ: {} + ••Dᴄ ID: {} + ••Nᴏ. Oғ PғPs : {} + ••Is Rᴇsᴛʀɪᴄᴛᴇᴅ: {} + ••Vᴇʀɪғɪᴇᴅ: {} + ••Is A Bᴏᴛ: {} + ••Gʀᴏᴜᴘs Iɴ Cᴏᴍᴍᴏɴ: {} + """.format( + user_id, + user_id, + first_name, + last_name, + user_bio, + dc_id, + replied_user_profile_photos_count, + replied_user.user.restricted, + replied_user.user.verified, + replied_user.user.bot, + common_chats, + ) + message_id_to_reply = event.message.reply_to_msg_id + if not message_id_to_reply: + message_id_to_reply = event.message.id + await event.client.send_message( + event.chat_id, + caption, + reply_to=message_id_to_reply, + parse_mode="HTML", + file=replied_user.profile_photo, + force_document=False, + silent=True, + ) + await xx.delete() + + +@ultroid_cmd( + pattern="invite ?(.*)", + groups_only=True, +) +async def _(ult): + xx = await eor(ult, "`Processing...`") + to_add_users = ult.pattern_match.group(1) + if not ult.is_channel and ult.is_group: + for user_id in to_add_users.split(" "): + try: + await ultroid_bot( + functions.messages.AddChatUserRequest( + chat_id=ult.chat_id, user_id=user_id, fwd_limit=1000000 + ) + ) + await xx.edit(f"Successfully invited `{user_id}` to `{ult.chat_id}`") + except Exception as e: + await xx.edit(str(e)) + else: + for user_id in to_add_users.split(" "): + try: + await ultroid_bot( + functions.channels.InviteToChannelRequest( + channel=ult.chat_id, users=[user_id] + ) + ) + await xx.edit(f"Successfully invited `{user_id}` to `{ult.chat_id}`") + except Exception as e: + await xx.edit(str(e)) + + +@ultroid_cmd( + pattern=r"rmbg ?(.*)", +) +async def rmbg(event): + RMBG_API = udB.get("RMBG_API") + xx = await eor(event, "`Processing...`") + if not RMBG_API: + return await xx.edit( + "Get your API key from [here](https://www.remove.bg/) for this plugin to work.", + ) + input_str = event.pattern_match.group(1) + message_id = event.message.id + if event.reply_to_msg_id: + message_id = event.reply_to_msg_id + reply_message = await event.get_reply_message() + try: + dl_file = await ultroid_bot.download_media( + reply_message, TMP_DOWNLOAD_DIRECTORY + ) + except Exception as e: + return await xx.edit("**ERROR:**\n`{}`".format(str(e))) + else: + await xx.edit("`Sending to remove.bg`") + output_file_name = ReTrieveFile(dl_file) + os.remove(dl_file) + elif input_str: + await xx.edit("`Sending to remove.bg`") + output_file_name = ReTrieveURL(input_str) + else: + await xx.edit( + f"Use `{Var.HNDLR}rmbg` as reply to a pic to remove its background." + ) + await asyncio.sleep(5) + await xx.delete() + return + contentType = output_file_name.headers.get("content-type") + if "image" in contentType: + with io.BytesIO(output_file_name.content) as remove_bg_image: + remove_bg_image.name = "rmbg-ult.png" + await ultroid_bot.send_file( + event.chat_id, + remove_bg_image, + force_document=True, + supports_streaming=False, + allow_cache=False, + reply_to=message_id, + ) + await xx.edit("`Done.`") + else: + await xx.edit( + "RemoveBG returned an error - \n`{}`".format( + output_file_name.content.decode("UTF-8") + ), + ) + + +@ultroid_cmd( + pattern="telegraph ?(.*)", +) +async def telegraphcmd(event): + input_str = event.pattern_match.group(1) + xx = await eor(event, "`Processing...`") + if event.reply_to_msg_id: + getmsg = await event.get_reply_message() + if getmsg.photo or getmsg.video or getmsg.gif: + getit = await ultroid_bot.download_media(getmsg) + try: + variable = uf(getit) + os.remove(getit) + nn = "https://telegra.ph" + variable[0] + amsg = f"Uploaded to [Telegraph]({nn}) !" + except Exception as e: + amsg = f"Error - {e}" + await xx.edit(amsg) + elif getmsg.document: + getit = await ultroid_bot.download_media(getmsg) + ab = open(getit, "r") + cd = ab.read() + ab.close() + if input_str: + tcom = input_str + else: + tcom = "Ultroid" + makeit = telegraph.create_page(title=tcom, content=[f"{cd}"]) + war = makeit["url"] + os.remove(getit) + await xx.edit(f"Pasted to Telegraph : [Telegraph]({war})") + elif getmsg.text: + if input_str: + tcom = input_str + else: + tcom = "Ultroid" + makeit = telegraph.create_page(title=tcom, content=[f"{getmsg.text}"]) + war = makeit["url"] + await xx.edit(f"Pasted to Telegraph : [Telegraph]({war})") + else: + await xx.edit("Reply to a Media or Text !") + else: + await xx.edit("Reply to a Message !") + + +@ultroid_cmd(pattern="json") +async def _(event): + the_real_message = None + reply_to_id = None + if event.reply_to_msg_id: + previous_message = await event.get_reply_message() + the_real_message = previous_message.stringify() + reply_to_id = event.reply_to_msg_id + else: + the_real_message = event.stringify() + reply_to_id = event.message.id + if len(the_real_message) > 4096: + with io.BytesIO(str.encode(the_real_message)) as out_file: + out_file.name = "json-ult.txt" + await borg.send_file( + event.chat_id, + out_file, + force_document=True, + allow_cache=False, + reply_to=reply_to_id, + ) + await event.delete() + else: + await eor(event, f"```{the_real_message}```") + + +HELP.update({f"{__name__.split('.')[1]}": f"{__doc__.format(i=Var.HNDLR)}"}) diff --git a/plugins/words.py b/plugins/words.py new file mode 100644 index 0000000000..f7556cb24a --- /dev/null +++ b/plugins/words.py @@ -0,0 +1,145 @@ +# Ultroid - UserBot +# Copyright (C) 2020 TeamUltroid +# +# This file is a part of < https://github.com/TeamUltroid/Ultroid/ > +# PLease read the GNU Affero General Public License in +# . + +""" +✘ Commands Available - + +• `{i}meaning ` + Get the meaning of the word. + +• `{i}synonym ` + Get all synonyms. + +• `{i}antonym ` + Get all antonyms. + +• `{i}ud ` + Fetch word defenition from urbandictionary. +""" + +import asyncurban +from PyDictionary import PyDictionary + +from . import * + +dictionary = PyDictionary() + + +@ultroid_cmd( + pattern="meaning", +) +async def mean(event): + evid = event.message.id + xx = await eor(event, "`Processing...`") + wrd = event.text.split(" ", maxsplit=1)[1] + ok = dictionary.meaning(wrd) + try: + p = ok["Noun"] + except BaseException: + return await xx.edit("Oops! No such word found!!") + x = f"**Word** - `{wrd}`\n\n**Meanings** - \n" + c = 1 + for i in p: + x += f"**{c}.** `{i}`\n" + c += 1 + if len(x) > 4096: + with io.BytesIO(str.encode(x)) as fle: + fle.name = f"{wrd}-meanings.txt" + await ultroid_bot.send_file( + event.chat_id, + out_file, + force_document=True, + allow_cache=False, + caption=f"Meanings of {wrd}", + reply_to=evid, + ) + await xx.delete() + else: + await xx.edit(x) + + +@ultroid_cmd( + pattern="synonym", +) +async def mean(event): + evid = event.message.id + xx = await eor(event, "`Processing...`") + wrd = event.text.split(" ", maxsplit=1)[1] + ok = dictionary.synonym(wrd) + x = f"**Word** - `{wrd}`\n\n**Synonyms** - \n" + c = 1 + try: + for i in ok: + x += f"**{c}.** `{i}`\n" + c += 1 + if len(x) > 4096: + with io.BytesIO(str.encode(x)) as fle: + fle.name = f"{wrd}-synonyms.txt" + await ultroid_bot.send_file( + event.chat_id, + out_file, + force_document=True, + allow_cache=False, + caption=f"Synonyms of {wrd}", + reply_to=evid, + ) + await xx.delete() + else: + await xx.edit(x) + except Exception as e: + await xx.edit(f"No synonym found!!\n{str(e)}") + + +@ultroid_cmd( + pattern="antonym", +) +async def mean(event): + evid = event.message.id + xx = await eor(event, "`Processing...`") + wrd = event.text.split(" ", maxsplit=1)[1] + ok = dictionary.antonym(wrd) + x = f"**Word** - `{wrd}`\n\n**Antonyms** - \n" + c = 1 + try: + for i in ok: + x += f"**{c}.** `{i}`\n" + c += 1 + if len(x) > 4096: + with io.BytesIO(str.encode(x)) as fle: + fle.name = f"{wrd}-antonyms.txt" + await ultroid_bot.send_file( + event.chat_id, + out_file, + force_document=True, + allow_cache=False, + caption=f"Antonyms of {wrd}", + reply_to=evid, + ) + await xx.delete() + else: + await xx.edit(x) + except Exception as e: + await xx.edit(f"No antonym found!!\n{str(e)}") + + +@ultroid_cmd(pattern="ud (.*)") +async def _(event): + xx = await eor(event, "`Processing...`") + word = event.pattern_match.group(1) + if word is None: + return await xx.edit("`No word given!`") + urban = asyncurban.UrbanDictionary() + try: + mean = await urban.get_word(word) + await xx.edit( + f"**Text**: `{mean.word}`\n\n**Meaning**: `{mean.definition}`\n\n**Example**: __{mean.example}__" + ) + except asyncurban.WordNotFoundError: + await xx.edit(f"**No result found for** `{word}`") + + +HELP.update({f"{__name__.split('.')[1]}": f"{__doc__.format(i=Var.HNDLR)}"}) diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000000..4a4c0a4fc9 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,31 @@ +py-Ultroid==2021.2.21 +asyncurban +carbonnow +cairosvg +emoji +GitPython +googletrans==3.1.0a0 +heroku3 +imutils +lottie +lxml +moviepy +numpy +opencv-python-headless +Pillow>=7.0.0 +play-scraper +PyDictionary +PyPDF2 +psutil +pytz +requests>=2.18.4 +scikit-image +search-engine-parser +speedtest-cli==2.1.2 +telegraph +validators +youtube_dl +youtube-search-python +google-api-python-client==1.7.11 +oauth2client==4.1.3 +httplib2==0.13.1 diff --git a/resources/downloads/.atoz b/resources/downloads/.atoz new file mode 100644 index 0000000000..9c558e357c --- /dev/null +++ b/resources/downloads/.atoz @@ -0,0 +1 @@ +. diff --git a/resources/extras/logo_rdm.png b/resources/extras/logo_rdm.png new file mode 100644 index 0000000000..44157c50e3 Binary files /dev/null and b/resources/extras/logo_rdm.png differ diff --git a/resources/extras/redistut.md b/resources/extras/redistut.md new file mode 100644 index 0000000000..99b094a04d --- /dev/null +++ b/resources/extras/redistut.md @@ -0,0 +1,16 @@ +# Tutorial To Get Redis DB Url and Password + +Process For Creating DB :- +i.) Go To redislabs.com and click "Try Free" in Top Right Corner. +ii.) Fill All The Required Details Like email, first and last name, password, etc. +iii.) Tick Below "I agree the corresponding...Privacy Policy." and Click "Get Started". +iv) Now Check Your Email, and click the "Activate Now" sent by redislabs via email. +v) Now Login and Chose Free Plan in "Fixed Size" Area and Write any name in "Subscription Area". +vi) On the Next Page Write Database Name and click Activate. + + Congo! Your DB has been created 🥳 + +Process For Getting DB Credentials:- +i.) Wait 5 mins after DB creation. +ii.) Then There Would Be 2 Things Named "Endpoint" and "Access Control & Security". +iii.) Copy Both Of Them and Paste Endpoint url in `REDIS_URI` and "Access ...Secrutity" in `REDIS_PASSWORD`. \ No newline at end of file diff --git a/resources/extras/thumb.jpg b/resources/extras/thumb.jpg new file mode 100644 index 0000000000..c04495d9a7 Binary files /dev/null and b/resources/extras/thumb.jpg differ diff --git a/resources/extras/ultroid.jpg b/resources/extras/ultroid.jpg new file mode 100644 index 0000000000..c339c08229 Binary files /dev/null and b/resources/extras/ultroid.jpg differ diff --git a/resources/extras/ultroid_blank.png b/resources/extras/ultroid_blank.png new file mode 100644 index 0000000000..5972e18ec8 Binary files /dev/null and b/resources/extras/ultroid_blank.png differ diff --git a/resources/fonts/2.ttf b/resources/fonts/2.ttf new file mode 100644 index 0000000000..23d266d3d2 Binary files /dev/null and b/resources/fonts/2.ttf differ diff --git a/resources/fonts/default.ttf b/resources/fonts/default.ttf new file mode 100644 index 0000000000..739ed7440c Binary files /dev/null and b/resources/fonts/default.ttf differ diff --git a/resources/session/session.sh b/resources/session/session.sh new file mode 100644 index 0000000000..0a11b48f1c --- /dev/null +++ b/resources/session/session.sh @@ -0,0 +1,32 @@ +# !/bin/bash +# Ultroid - UserBot +# Copyright (C) 2020 TeamUltroid +# +# This file is a part of < https://github.com/TeamUltroid/Ultroid/ > +# PLease read the GNU Affero General Public License in . + +clear +echo -e "\e[1m" +echo " _ _ _ _ _ _ " +echo " | | | | | | (_) | |" +echo " | | | | | |_ _ __ ___ _ __| |" +echo " | | | | | __| '__/ _ \| |/ _ |" +echo " | |__| | | |_| | | (_) | | (_| |" +echo " \____/|_|\__|_| \___/|_|\__,_|" +echo -e "\e[0m" +sec=5 +spinner=(⣻ ⢿ ⡿ ⣟ ⣯ ⣷) +while [ $sec -gt 0 ]; do + echo -ne "\e[33m ${spinner[sec]} Starting dependency installation in $sec seconds...\r" + sleep 1 + sec=$(($sec - 1)) +done +echo -e "\e[1;32mInstalling Dependencies ---------------------------\e[0m\n" # Don't Remove Dashes / Fix it +apt-get update +apt-get upgrade -y +pkg upgrade -y +pkg install python wget -y +wget https://raw.githubusercontent.com/TeamUltroid/ultroid/main/resources/session/ssgen.py +pip install telethon +clear +python3 ssgen.py diff --git a/resources/session/ssgen.py b/resources/session/ssgen.py new file mode 100644 index 0000000000..cd3b4d6cbc --- /dev/null +++ b/resources/session/ssgen.py @@ -0,0 +1,24 @@ +#!/bin/bash +# Ultroid - UserBot +# Copyright (C) 2020 TeamUltroid +# +# This file is a part of < https://github.com/TeamUltroid/Ultroid/ > +# PLease read the GNU Affero General Public License in +# . + +from telethon.sessions import StringSession +from telethon.sync import TelegramClient + +print("Please ensure that you have your API ID and API HASH.") +print("") + +API_ID = int(input("Enter API ID: ")) +API_HASH = input("Enter API HASH: ") + +with TelegramClient(StringSession(), API_ID, API_HASH) as client: + ult = client.send_message("me", client.session.save()) + ult.reply( + "The above is the `SESSION` for your current session.\nVisit @TheUltroid") + print("") + print("String Session for the current login has been generated.") + print("Check your Telegram Saved messages for your SESSION.") diff --git a/resources/startup/deploy.sh b/resources/startup/deploy.sh new file mode 100644 index 0000000000..6847eb46d8 --- /dev/null +++ b/resources/startup/deploy.sh @@ -0,0 +1,50 @@ +# Ultroid - UserBot +# Copyright (C) 2020 TeamUltroid +# +# This file is a part of < https://github.com/TeamUltroid/Ultroid/ > +# PLease read the GNU Affero General Public License in +# . + +echo " + ╔╦╦╦══╦═╦═╦══╦══╗ + ║║║╠╗╔╣╬║║╠║║╩╗╗║ + ║║║╚╣║║╗╣║╠║║╦╩╝║ + ╚═╩═╩╝╚╩╩═╩══╩══╝ + + °•° Deployment Begins •°• +" +echo ' + •• Getting Packages and Installing +' + +export DEBIAN_FRONTEND=noninteractive +export TZ=Asia/Kolkata +ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone + +apt-get update +apt-get upgrade -y +apt-get install -y --no-install-recommends ffmpeg neofetch mediainfo megatools +apt-get autoremove --purge + +echo ' + •• Cloning Repository +' +git clone https://github.com/TeamUltroid/Ultroid.git /root/TeamUltroid/ + +echo ' + •• Getting Libraries and Installing +' +pip install --upgrade pip setuptools wheel +pip install -r /root/TeamUltroid/requirements.txt + +echo " + + ┏┳┓╋┏┓╋╋╋╋┏┓┏┓ + ┃┃┣┓┃┗┳┳┳━╋╋┛┃ + ┃┃┃┗┫┏┫┏┫╋┃┃╋┃ + ┗━┻━┻━┻┛┗━┻┻━┛ + + •°• Deployed Successfully °•° + •• Wait till python images are pushed + •• Give build logs in @UltroidSupport if build fails +" diff --git a/resources/startup/startup.sh b/resources/startup/startup.sh new file mode 100644 index 0000000000..5bd1de5938 --- /dev/null +++ b/resources/startup/startup.sh @@ -0,0 +1,19 @@ +#!/bin/bash +# Ultroid - UserBot +# Copyright (C) 2020 TeamUltroid +# +# This file is a part of < https://github.com/TeamUltroid/Ultroid/ > +# PLease read the GNU Affero General Public License in . + +echo " + + +-+ +-+ +-+ +-+ +-+ +-+ +-+ + |U| |L| |T| |R| |O| |I| |D| + +-+ +-+ +-+ +-+ +-+ +-+ +-+ + + + Visit @TheUltroid for updates!! + +" + +python3 -m pyUltroid diff --git a/sessiongen b/sessiongen new file mode 100644 index 0000000000..5fc90cbbac --- /dev/null +++ b/sessiongen @@ -0,0 +1,7 @@ +# Ultroid - UserBot +# Copyright (C) 2020 TeamUltroid +# +# This file is a part of < https://github.com/TeamUltroid/Ultroid/ > +# PLease read the GNU Affero General Public License in . + +bash resources/session/session.sh \ No newline at end of file