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.
+
+
+
+
+
+[![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