diff --git a/.gitignore b/.gitignore index 4f18dbb2..2dff2784 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ build/ dist/ nonebot_plugin_admin.egg-info/ -setup.py \ No newline at end of file +setup.py +.idea/ \ No newline at end of file diff --git a/.idea/workspace.xml b/.idea/workspace.xml index dfef494a..b4d0b6ac 100644 --- a/.idea/workspace.xml +++ b/.idea/workspace.xml @@ -1,10 +1,30 @@ - + + + + + + + + + + + + + + + + + + + + + @@ -32,29 +53,41 @@ - + + - + - - 1643521853942 + + 1644496672516 diff --git a/LICENSE b/LICENSE index 335ea9d0..29ebfa54 100644 --- a/LICENSE +++ b/LICENSE @@ -1,19 +1,661 @@ -Copyright (c) 2018 The Python Packaging Authority - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. \ No newline at end of file + 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 index cdd0e958..eb63a960 100644 --- a/README.md +++ b/README.md @@ -1,17 +1,20 @@

- nonebot + nonebot

+------ +
# 简易群管 -_✨ NoneBot2 (有点不)简易群管_ ✨_ +_✨ NoneBot2 (有点不)简易群管_ ✨ +[![wakatime](https://wakatime.com/badge/user/e4795d94-d154-4c3d-a94b-b655c82e57f4/project/d4a8cb5e-ee86-4ad9-99e5-48873f38c3bd.svg)](https://wakatime.com/badge/user/e4795d94-d154-4c3d-a94b-b655c82e57f4/project/d4a8cb5e-ee86-4ad9-99e5-48873f38c3bd) -
踢 改 禁....... -**欢迎 issue pr** +**欢迎 ISSUES PR** + **权限说明:见下方指令↓** @@ -19,11 +22,25 @@ _✨ NoneBot2 (有点不)简易群管_ ✨_ `pip install nonebot-plugin-admin` 请注意与nonebot版本适配,匹配请查看:[更新](#%E6%9B%B4%E6%96%B0-1) +**Python 3.9+** ## 更新 `pip install --upgrade nonebot-plugin-admin ` +## 配置 +鉴黄配置: +腾讯云图片安全,开通地址:[https://console.cloud.tencent.com/cms](https://console.cloud.tencent.com/cms) +文档:[https://cloud.tencent.com/document/product/1125](https://cloud.tencent.com/document/product/1125) +注意,在beta2中,若不进行预先配置,启动时会无法导入,请安下方格式配置,若暂时不使用此功能,可以直接复制粘贴下面的内容 +**.env.***: +``` +# 腾讯云图片安全api +tenid="xxxxxx" +tenkeys="xxxxxx" +``` + +✨Pay tribute to A60 [https://github.com/djkcyl/ABot-Graia](https://github.com/djkcyl/ABot-Graia) ## 导入📲 在**bot.py** 导入,语句: @@ -34,9 +51,9 @@ _✨ NoneBot2 (有点不)简易群管_ ✨_ **Tips:** - 关于命令,对/sp这类`斜杠+英文`的命令做了保留,汉字命令去除了`/`若使用者担心错误触发,可下载源码自行修改`__init__.py` -- 为了防止错误触发,相同操作的` +` ` -`都写(复制)了两段代码 - 群词云功能所用库 wordcloud 未写入依赖,请自行安装:`pip install wordcloud` 安装失败参考:[WordCloud 第三方库安装失败原因及解决方法](https://www.freesion.com/article/4756295761/) -- matcher权重请自行查看代码 +- 一般情况下可正常使用,可能由于权重出现问题,matcher权重请自行查看代码 +- 使用`开关状态`指令查看各功能状态,首次使用可能会下载100Mb+的`Chromium`,请耐心等待 ``` 【初始化】: 群管初始化 :初始化插件 @@ -100,7 +117,22 @@ _✨ NoneBot2 (有点不)简易群管_ ✨_ 违禁词检测:将禁言随机时间 群内发送: 简单违禁词 :简单级别过滤 - 严格违禁词 :严格级别过滤 + 严格违禁词 :严格级别过滤(不建议) + 更新违禁词库 :手动更新词库 + 违禁词库每周一自动更新 + +【功能开关】 +群内发送: + 开关xx : 对某功能进行开/关 permission=SUPERUSER | GROUP_ADMIN | GROUP_OWNER + 开关状态 : 查看各功能的状态 + xx in : + ['管理', '踢', '禁', '改', '基础群管'] #基础功能 踢、禁、改、管理员+- + ['加群', '审批', '加群审批', '自动审批'] #加群审批 + ['词云', '群词云', 'wordcloud'] #群词云 + ['违禁词', '违禁词检测'] #违禁词检测 + ['图片检测', '图片鉴黄', '涩图检测', '色图检测'] #图片检测 +所有功能默认开 + ``` **给个star吧~** @@ -111,9 +143,23 @@ _✨ NoneBot2 (有点不)简易群管_ ✨_ - [在线运行代码](https://github.com/yzyyz1387/nonebot_plugin_code) ## 截图🖼 +**禁 改 踢** +![](https://cdn.jsdelivr.net/gh/yzyyz1387/blogimages/nonebot/ad_kick.gif) -暂无 +**管理员+ -** +![](https://cdn.jsdelivr.net/gh/yzyyz1387/blogimages/nonebot/ad_admin.gif) +**群词云** +![](https://cdn.jsdelivr.net/gh/yzyyz1387/blogimages/nonebot/ad_cloud.gif) + +**违禁词检测** +![](https://cdn.jsdelivr.net/gh/yzyyz1387/blogimages/nonebot/ad_autoban.gif) + +**图片检测** +![](https://cdn.jsdelivr.net/gh/yzyyz1387/blogimages/nonebot/ad_r18ban.gif) + +**功能开关** +![](https://cdn.jsdelivr.net/gh/yzyyz1387/blogimages/nonebot/ad_switcher.gif) ## TODO - [x] 加群自动审批[#issues1](https://github.com/yzyyz1387/nonebot_plugin_admin/issues/1) - [x] /sp在未配置群聊中的提示 @@ -121,22 +167,35 @@ _✨ NoneBot2 (有点不)简易群管_ ✨_ - [x] 加群处理状态分群分用户发送[#issues2](https://github.com/yzyyz1387/nonebot_plugin_admin/issues/2) - [x] 关键词禁言,图片鉴黄(简单实现),[#issues3](https://github.com/yzyyz1387/nonebot_plugin_admin/issues/3) - [ ] 恶意检测, [#issues3](https://github.com/yzyyz1387/nonebot_plugin_admin/issues/3) -- [ ] 鉴黄置信度呈现 +- [ ] ~~鉴黄置信度呈现~~ - [ ] 词云停用词优化 +- [ ] 分群群词云自定义停用词 - [ ] 违禁词优化 +- [ ] 全局开关 - [ ] 潜水查询 - [ ] 群聊内容分析 -- [ ] 其他功能... +- [ ] 写一个文档 +- [ ] 一些大事 -## 更新 -- 0.3.16(b1) +## 更新 +- 0.3.18(beta) + - update LICENSE to AGPL-3.0 + - 🐛修复`管理员-`无效的bug + - 🐛修复`简单违禁词`、`严格违禁词`无效的bug + - 🐛修复`禁 解 改`等指令有无空格的问题 + - 禁言命令新增不禁言superuser + - 鉴黄api改为腾讯云,请自行开通配置 + - 违禁词词库每周一自动更新,手动更新:`更新违禁词库` + - 分群功能开关 + - 使用`开关状态`指令查看各功能状态,首次使用可能会下载109Mb的`Chromium` +- 0.3.16(b1) - 修复启动时`word_analyze`报错 - 修复词云路径错误 - 分词优化 - 图片鉴黄 - 违禁词检测 违禁词词库整理上传于:[f_words](https://github.com/yzyyz1387/nwafu/tree/main/f_words) - - 词库有赘余,欢迎大神pr精简 + - 词库有赘余,欢迎大神pr精简 - 0.3.15(a16) - 同 0.3.16 - 0.3.6(b1) diff --git a/nonebot_plugin_admin_a/__init__.py b/nonebot_plugin_admin_a/__init__.py deleted file mode 100644 index 7fd9842f..00000000 --- a/nonebot_plugin_admin_a/__init__.py +++ /dev/null @@ -1,392 +0,0 @@ -# python3 -# -*- coding: utf-8 -*- -# @Time : 2021/12/23 0:52 -# @Author : yzyyz -# @Email : youzyyz1384@qq.com -# @File : __init__.py.py -# @Software: PyCharm -import nonebot -from nonebot import on_command, logger -from nonebot.adapters.cqhttp import Bot, GroupMessageEvent -from nonebot.adapters.cqhttp.exception import ActionFailed -from nonebot.adapters.cqhttp.permission import GROUP_ADMIN, GROUP_OWNER -from nonebot.permission import SUPERUSER -from .utils import At, banSb, init -from . import approve, group_request_verify, group_request, notice, utils, word_analyze, r18_pic_ban, auto_ban -su = nonebot.get_driver().config.superusers - -admin_init = on_command("群管初始化", priority=1, block=True, permission=SUPERUSER | GROUP_ADMIN | GROUP_OWNER) - - -@admin_init.handle() -async def _(bot: Bot,event:GroupMessageEvent): - await init() - - -ban = on_command('禁', priority=1, block=True, permission=SUPERUSER | GROUP_ADMIN | GROUP_OWNER) - - -@ban.handle() -async def _(bot: Bot, event: GroupMessageEvent): - """ - /禁 @user 禁言 - """ - msg = str(event.get_message()) - sb = At(event.json()) - gid = event.group_id - if sb: - if len(msg.split()) == len(sb) + 1: - time = int(msg.split()[-1:][0]) - baning = banSb(gid, ban_list=sb, time=time) - async for baned in baning: - if baned: - try: - await baned - except ActionFailed: - await ban.finish("权限不足") - else: - logger.info("禁言操作成功") - else: - baning = banSb(gid, ban_list=sb) - async for baned in baning: - if baned: - try: - await baned - except ActionFailed: - await ban.finish("权限不足") - else: - logger.info("禁言操作成功") - await ban.send(f"该用户已被禁言随机时长") - else: - pass - - -unban = on_command("解", priority=1, block=True, permission=SUPERUSER | GROUP_ADMIN | GROUP_OWNER) - - -@unban.handle() -async def _(bot: Bot, event: GroupMessageEvent): - """ - /解 @user 解禁 - """ - msg = str(event.get_message()) - sb = At(event.json()) - gid = event.group_id - if sb: - if len(msg.split()) == len(sb): - baning = banSb(gid, ban_list=sb, time=0) - async for baned in baning: - if baned: - try: - await baned - except ActionFailed: - await ban.finish("权限不足") - else: - logger.info("解禁操作成功") - - -ban_all = on_command("/all", permission=SUPERUSER | GROUP_ADMIN | GROUP_OWNER, priority=1, block=True) - - -@ban_all.handle() -async def _(bot: Bot, event: GroupMessageEvent): - """ - (测试时没用..) - /all 全员禁言 - /all 解 关闭全员禁言 - """ - msg = event.get_message() - if msg and '解' in str(msg): - enable = False - else: - enable = True - try: - await bot.set_group_whole_ban( - group_id=event.group_id, - enable=enable - ) - except ActionFailed: - await ban.finish("权限不足") - else: - logger.info(f"全体操作成功 {str(enable)}") - - -change = on_command('改', permission=SUPERUSER | GROUP_ADMIN | GROUP_OWNER, priority=1, block=True) - - -@change.handle() -async def _(bot: Bot, event: GroupMessageEvent): - """ - /改 @user xxx 改群昵称 - """ - msg = str(event.get_message()) - logger.info(msg.split()) - sb = At(event.json()) - gid = event.group_id - if sb: - if len(msg.split()) == 2: - try: - await bot.set_group_card( - group_id=gid, - user_id=int(sb[0]), - card=msg.split()[-1:][0] - ) - except ActionFailed: - await change.finish("权限不足") - else: - logger.info("改名片操作成功") - else: - await change.finish("一次仅可更改一位群员的昵称") - - -title = on_command('头衔', permission=SUPERUSER | GROUP_OWNER, priority=1, block=True) - - -@title.handle() -async def _(bot: Bot, event: GroupMessageEvent): - """ - /头衔 @user xxx 给某人头衔 - """ - msg = str(event.get_message()) - stitle = msg.split()[-1:][0] - logger.info(str(msg.split()), stitle) - sb = At(event.json()) - gid = event.group_id - if sb: - if len(msg.split()) == len(sb) + 1 and 'all' not in sb: - try: - for qq in sb: - await bot.set_group_special_title( - group_id=gid, - user_id=int(qq), - special_title=stitle, - duration=-1, - ) - except ActionFailed: - await title.finish("权限不足") - else: - logger.info(f"改头衔操作成功{stitle}") - else: - await title.finish("未填写头衔名称 或 不能含有@全体成员") - - -title_ = on_command('删头衔', permission=SUPERUSER | GROUP_ADMIN | GROUP_OWNER, priority=1, block=True) - - -@title_.handle() -async def _(bot: Bot, event: GroupMessageEvent): - """ - /删头衔 @user 删除头衔 - """ - msg = str(event.get_message()) - stitle = msg.split()[-1:][0] - logger.info(str(msg.split()), stitle) - sb = At(event.json()) - gid = event.group_id - if sb: - if len(msg.split()) == len(sb) and 'all' not in sb: - try: - for qq in sb: - await bot.set_group_special_title( - group_id=gid, - user_id=int(qq), - special_title="", - duration=-1, - ) - except ActionFailed: - await title_.finish("权限不足") - else: - logger.info(f"改头衔操作成功{stitle}") - else: - await title_.finish("未填写头衔名称 或 不能含有@全体成员") - - -kick = on_command('踢', permission=SUPERUSER | GROUP_ADMIN | GROUP_OWNER, priority=1, block=True) - - -@kick.handle() -async def _(bot: Bot, event: GroupMessageEvent): - """ - /踢 @user 踢出某人 - """ - msg = str(event.get_message()) - sb = At(event.json()) - gid = event.group_id - if sb: - if len(msg.split()) == len(sb) and 'all' not in sb: - try: - for qq in sb: - await bot.set_group_kick( - group_id=gid, - user_id=int(qq), - reject_add_request=False - ) - except ActionFailed: - await kick.finish("权限不足") - else: - logger.info(f"踢人操作成功") - else: - await kick.finish("不能含有@全体成员") - - -kick_ = on_command('黑', permission=SUPERUSER | GROUP_ADMIN | GROUP_OWNER, priority=1, block=True) - - -@kick_.handle() -async def _(bot: Bot, event: GroupMessageEvent): - """ - 黑 @user 踢出并拉黑某人 - """ - msg = str(event.get_message()) - sb = At(event.json()) - gid = event.group_id - if sb: - if len(msg.split()) == len(sb) and 'all' not in sb: - try: - for qq in sb: - await bot.set_group_kick( - group_id=gid, - user_id=int(qq), - reject_add_request=True - ) - except ActionFailed: - await kick_.finish("权限不足") - else: - logger.info(f"踢人并拉黑操作成功") - else: - await kick_.finish("不能含有@全体成员") - - -set_g_admin = on_command("管理员+", permission=SUPERUSER | GROUP_OWNER, block=True) - - -@set_g_admin.handle() -async def _(bot: Bot, event: GroupMessageEvent): - """ - 管理员+ @user 添加群管理员 - """ - msg = str(event.get_message()) - logger.info(msg) - logger.info(msg.split()) - sb = At(event.json()) - logger.info(sb) - gid = event.group_id - if sb: - if len(msg.split()) == len(sb) and 'all' not in sb: - try: - for qq in sb: - await bot.set_group_admin( - group_id=gid, - user_id=int(qq), - enable=True - ) - except ActionFailed: - await set_g_admin.finish("权限不足") - else: - logger.info(f"设置管理员操作成功") - await set_g_admin.finish("设置管理员操作成功") - else: - await set_g_admin.finish("指令不正确 或 不能含有@全体成员") - - -unset_g_admin = on_command("管理员-", permission=SUPERUSER | GROUP_OWNER, block=True) - - -@unset_g_admin.handle() -async def _(bot: Bot, event: GroupMessageEvent): - """ - 管理员+ @user 添加群管理员 - """ - msg = str(event.get_message()) - logger.info(msg) - logger.info(msg.split()) - sb = At(event.json()) - logger.info(sb) - gid = event.group_id - if sb: - if len(msg.split()) == len(sb) and 'all' not in sb: - try: - for qq in sb: - await bot.set_group_admin( - group_id=gid, - user_id=int(qq), - enable=True - ) - except ActionFailed: - await unset_g_admin.finish("权限不足") - else: - logger.info(f"取消管理员操作成功") - await unset_g_admin.finish("取消管理员操作成功") - else: - await unset_g_admin.finish("指令不正确 或 不能含有@全体成员") - - -__usage__ = """ -【初始化】: - 群管初始化 :初始化插件 - -【群管】: -权限:permission=SUPERUSER | GROUP_ADMIN | GROUP_OWNER - 禁言: - 禁 @某人 时间(s)[1,2591999] - 禁 @某人 缺省时间则随机 - 禁 @某人 0 可解禁 - 解 @某人 - 全群禁言(好像没用?) - /all - /all 解 - 改名片 - 改 @某人 名片 - 改头衔 - 头衔 @某人 头衔 - 删头衔 - 踢出: - 踢 @某人 - 踢出并拉黑: - 黑 @某人 - -【管理员】permission=SUPERUSER | GROUP_OWNER - 管理员+ @xxx 设置某人为管理员 - 管理员- @xxx 取消某人管理员 - -【加群自动审批】: -群内发送 permission=GROUP_ADMIN | GROUP_OWNER | SUPERUSER - 查看词条 : 查看本群审批词条 或/审批 - 词条+ [词条] :增加审批词条 或/审批+ - 词条- [词条] :删除审批词条 或/审批- - -【superuser】: - 所有词条 : 查看所有审批词条 或/su审批 - 指定词条+ [群号] [词条] :增加指定群审批词条 或/su审批+ - 指定词条- [群号] [词条] :删除指定群审批词条 或/su审批- - 自动审批处理结果将发送给superuser - -【分群管理员设置】*分管:可以接受加群处理结果消息的用户 -群内发送 permission=GROUP_ADMIN | GROUP_OWNER | SUPERUSER - 分管+ [user] :user可用@或qq 添加分群管理员 - 分管- [user] :删除分群管理员 - 查看分管 :查看本群分群管理员 - -群内或私聊 permission=SUPERUSER - 所有分管 :查看所有分群管理员 - 群管接收 :打开或关闭超管消息接收(关闭则审批结果不会发送给superusers) - -【群词云统计】 -该功能所用库 wordcloud 未写入依赖,请自行安装 -群内发送: - 记录本群 : 开始统计聊天记录 permission=GROUP_ADMIN | GROUP_OWNER | SUPERUSER - 停止记录本群 :停止统计聊天记录 - 群词云 : 发送词云图片 - -【被动识别】 -涩图检测:将禁言随机时间 - -违禁词检测:将禁言随机时间 -群内发送: - 简单违禁词 :简单级别过滤 - 严格违禁词 :严格级别过滤 -""" -__help_plugin_name__ = "简易群管" - -__permission__ = 1 -__help__version__ = '0.2.0' diff --git a/nonebot_plugin_admin_a/approve.py b/nonebot_plugin_admin_a/approve.py deleted file mode 100644 index 27077e1e..00000000 --- a/nonebot_plugin_admin_a/approve.py +++ /dev/null @@ -1,172 +0,0 @@ -# python3 -# -*- coding: utf-8 -*- -# @Time : 2021/12/26 5:29 -# @Author : yzyyz -# @Email : youzyyz1384@qq.com -# @File : approve.py -# @Software: PyCharm -import os.path -from typing import Optional -import aiofiles -import json -from nonebot import logger -from .utils import init -from pathlib import Path - -config_path = Path() / "config" -config_json = config_path / "admin.json" -config_group = config_path / "group_admin.json" - - -async def load() -> Optional[dict]: - """ - 加载配置 - :return:dict - """ - async with aiofiles.open(config_json, mode='r') as f: - contents_ = await f.read() - contents = json.loads(contents_) - return contents - - -async def g_admin(): - """ - :return : 分群管理json对象 - """ - if not os.path.exists(config_json): - await init() - async with aiofiles.open(config_group, mode='r') as f: - admins_ = await f.read() - admins = json.loads(admins_) - return admins - - -async def g_admin_add(gid: str, qq: int) -> Optional[bool]: - """ - - 添加分群管理(处理加群请求时接收处理结果) - :param gid: 群号 - :param qq: qq - :return: bool - """ - admins = await g_admin() - if gid in admins: - if qq in admins[gid]: - logger.info(f'{qq}已经是群{gid}的分群管理了') - return False - else: - g_admins = admins[gid] - g_admins.append(qq) - admins[gid] = g_admins - async with aiofiles.open(config_group, mode='w') as c: - await c.write(str(json.dumps(admins))) - logger.info(f"群{gid}添加分群管理:{qq}") - return True - else: - logger.info(f'群{gid}首次加入分群管理') - admins.update({gid: [qq]}) - async with aiofiles.open(config_group, mode='w') as c: - await c.write(str(json.dumps(admins))) - return True - - -async def g_admin_del(gid: str, qq: int) -> Optional[bool]: - """ - 删除分群管理 - :param gid: 群号 - :param qq: qq - :return: bool - """ - admins = await g_admin() - if gid in admins: - if qq in admins[gid]: - logger.info(f'已删除群{gid}的分群管理{qq}') - data = admins[gid] - data.remove(qq) - if data: - admins[gid] = data - else: - del (admins[gid]) - async with aiofiles.open(config_group, mode='w') as c: - await c.write(str(json.dumps(admins))) - return True - else: - logger.info(f'删除失败:群{gid}中{qq}还不是分群管理') - return False - else: - logger.info(f'群{gid}还未添加过分群管理') - return None - - -async def su_on_off() -> Optional[bool]: - admins = await g_admin() - if admins['su'] == 'False': - admins['su'] = 'True' - logger.info("打开超管消息接收") - async with aiofiles.open(config_group, mode='w') as c: - await c.write(str(json.dumps(admins))) - return True - else: - admins['su'] = 'False' - logger.info("关闭超管消息接收") - async with aiofiles.open(config_group, mode='w') as c: - await c.write(str(json.dumps(admins))) - return False - - -async def write(gid: str, answer: str) -> Optional[bool]: - """ - 写入词条 - :param gid: 群号 - :param answer: 词条 - :return: bool - """ - contents = await load() - if gid in contents: - data = contents[gid] - if answer in data: - logger.info(f'{answer} 已存在于群{gid}的词条中') - return False - else: - data.append(answer) - contents[gid] = data - async with aiofiles.open(config_json, mode='w') as c: - await c.write(str(json.dumps(contents))) - logger.info(f"群{gid}添加入群审批词条:{answer}") - return True - - else: - logger.info(f'群{gid}第一次配置此词条:{answer}') - contents.update({gid: [answer]}) - async with aiofiles.open(config_json, mode='w') as c: - await c.write(str(json.dumps(contents))) - return True - - -async def delete(gid: str, answer: str) -> Optional[bool]: - """ - 删除词条 - :param gid: 群号 - :param answer: 词条 - :return: bool - """ - contents = await load() - if gid in contents: - if answer in contents[gid]: - data = contents[gid] - data.remove(answer) - if data: - contents[gid] = data - else: - del (contents[gid]) - async with aiofiles.open(config_json, mode='w') as c: - await c.write(str(json.dumps(contents))) - logger.info(f'群{gid}删除词条:{answer}') - return True - - else: - logger.info(f'删除失败,群{gid}不存在词条:{answer}') - return False - else: - logger.info(f'群{gid}从未配置过词条') - return None diff --git a/nonebot_plugin_admin_a/auto_ban.py b/nonebot_plugin_admin_a/auto_ban.py deleted file mode 100644 index f80f41b5..00000000 --- a/nonebot_plugin_admin_a/auto_ban.py +++ /dev/null @@ -1,107 +0,0 @@ -# python3 -# -*- coding: utf-8 -*- -# @Time : 2022/1/29 0:43 -# @Author : yzyyz -# @Email : youzyyz1384@qq.com -# @File : auto_ban.py -# @Software: PyCharm -import os -import json -import aiofiles -from pathlib import Path -from nonebot import logger, on_message, on_command -from nonebot.adapters.cqhttp import Bot, GroupMessageEvent -from nonebot.adapters.cqhttp.exception import ActionFailed -from .utils import init, banSb -from nonebot.adapters.cqhttp.permission import GROUP_ADMIN, GROUP_OWNER -from nonebot.permission import SUPERUSER - -config_path = Path() / "config" -limit_word_path = config_path / "违禁词.txt" -limit_word_path_easy = config_path / "违禁词_简单.txt" -limit_level = config_path / "违禁词监控等级.json" - -f_word = on_message(priority=1, block=False) - - -@f_word.handle() -async def _(bot: Bot, event: GroupMessageEvent): - """ - 违禁词禁言 - :param bot: - :param event: - :return: - """ - await init() - gid = event.group_id - uid = [event.get_user_id()] - eid = event.message_id - msg = str(event.get_message()).replace(" ", "") - level = (await load_level()) - if str(gid) in level: - if level[str(gid)] == 'easy': - limit_path = limit_word_path_easy - else: - limit_path = limit_word_path - f_words = open(limit_path, 'r', encoding='utf-8').read().split('\n') - for words in f_words: - if words and words in msg: - logger.info(f"敏感词触发:\"{words}\"") - try: - await bot.delete_msg(message_id=eid) - logger.info('检测到违禁词,撤回') - except ActionFailed: - logger.info('检测到违禁词,但权限不足,撤回失败') - baning = banSb(gid, ban_list=uid) - async for baned in baning: - if baned: - try: - await baned - except ActionFailed: - await f_word.finish("检测到违禁词,但权限不足") - logger.info('检测到违禁词,但权限不足,禁言失败') - else: - await bot.send(event=event, message="发送了违禁词,现对你进行处罚,有异议请联系管理员", at_sender=True) - logger.info(f"检测到违禁词,禁言操作成功,用户: {uid[0]}") - break - else: - await f_word.send("本群未配置检测级别,指令如下:\n1.简单违禁:简单级别\n2.严格违禁词:严格级别\n3.群管初始化:一键配置所有群聊为简单级别") - - -async def load_level() -> dict: - async with aiofiles.open(limit_level, mode='r') as c: - level_ = await c.read() - level = json.loads(level_) - return level - - -set_level_easy = on_command("简单违禁词", priority=1, permission=GROUP_ADMIN | GROUP_OWNER | SUPERUSER) - - -@set_level_easy.handle() -async def _(bot: Bot, event: GroupMessageEvent): - gid = str(event.group_id) - level = await load_level() - if gid not in level or level[gid] != "easy": - data = level.update({gid: "easy"}) - async with aiofiles.open(limit_level, mode='w') as c: - await c.write(str(json.dumps(data))) - await set_level_easy.send("完成") - else: - await set_level_easy.send("本群已经是简单检测了") - - -set_level_rigorous = on_command("严格违禁词", priority=1, permission=GROUP_ADMIN | GROUP_OWNER | SUPERUSER) - - -@set_level_rigorous.handle() -async def _(bot: Bot, event: GroupMessageEvent): - gid = str(event.group_id) - level = await load_level() - if gid not in level or level[gid] != 'rigorous': - data = level.update({gid: "rigorous"}) - async with aiofiles.open(limit_level, mode='w') as c: - await c.write(str(json.dumps(data))) - await set_level_rigorous.send("完成") - else: - await set_level_rigorous.send("本群已经是严格检测了") diff --git a/nonebot_plugin_admin_a/group_request.py b/nonebot_plugin_admin_a/group_request.py deleted file mode 100644 index 7f4fb803..00000000 --- a/nonebot_plugin_admin_a/group_request.py +++ /dev/null @@ -1,199 +0,0 @@ -# python3 -# -*- coding: utf-8 -*- -# @Time : 2022/1/16 10:20 -# @Author : yzyyz -# @Email : youzyyz1384@qq.com -# @File : group_request.py -# @Software: PyCharm -import nonebot -from nonebot import on_command, on_request, logger -from nonebot.adapters.cqhttp import Bot, GroupMessageEvent, GroupRequestEvent, MessageEvent -from nonebot.adapters.cqhttp.permission import GROUP_ADMIN, GROUP_OWNER, PRIVATE_FRIEND -from nonebot.permission import SUPERUSER -from nonebot.typing import T_State -from . import approve -from .group_request_verify import verify -import json -import re -from pathlib import Path - -su = nonebot.get_driver().config.superusers -config_path = Path() / "config" -config_json = config_path / "admin.json" -config_group = config_path / "group_admin.json" -word_path = config_path / "word_config.txt" - - -# 查看所有审批词条 -super_sp = on_command('所有词条', aliases={"/susp", "/su审批"}, priority=1, block=True, permission=SUPERUSER) - - -@super_sp.handle() -async def _(bot: Bot, event: MessageEvent): - answers = await approve.load() - rely = "" - for i in answers: - rely += i + " : " + str(answers[i]) + "\n" - await super_sp.send(rely) - - -# 按群号添加词条 -super_sp_add = on_command('指定词条+', aliases={"/susp+", "/su审批+"}, priority=1, block=True, permission=SUPERUSER) - - -@super_sp_add.handle() -async def _(bot: Bot, event: MessageEvent): - msg = str(event.get_message()).split() - print(msg) - logger.info(str(len(msg)), msg) - if len(msg) == 3: - gid = msg[1] - answer = msg[2] - sp_write = await approve.write(gid, answer) - if gid.isdigit(): - if sp_write: - - await super_sp_add.send(f"群{gid}添加入群审批词条:{answer}") - else: - await super_sp_add.send(f'{answer} 已存在于群{gid}的词条中') - else: - await super_sp_de.finish('输入有误 /susp+ [群号] [词条]') - else: - await super_sp_de.finish('输入有误 /susp+ [群号] [词条]') - - -# 按群号删除词条 -super_sp_de = on_command('指定词条-', aliases={"/susp-", "/su审批-"}, priority=1, block=True, permission=SUPERUSER) - - -@super_sp_de.handle() -async def _(bot: Bot, event: MessageEvent): - msg = str(event.get_message()).split() - if len(msg) == 3: - gid = msg[1] - answer = msg[2] - if gid.isdigit(): - sp_delete = await approve.delete(gid, answer) - if sp_delete: - await super_sp_de.send(f"群{gid}删除入群审批词条:{answer}") - elif not sp_delete: - await super_sp_de.send(f'群{gid}不存在此词条') - elif sp_delete is None: - await super_sp_de.send(f'群{gid}从未配置过词条') - else: - await super_sp_de.finish('输入有误 /susp- [群号] [词条]') - else: - await super_sp_de.finish('输入有误 /susp- [群号] [词条]') - - -check = on_command('查看词条', aliases={"/sp", "/审批"}, priority=1, block=True, - permission=GROUP_ADMIN | GROUP_OWNER | SUPERUSER) - - -@check.handle() -async def _(bot: Bot, event: GroupMessageEvent): - """ - /sp 查看本群词条 - """ - a_config = await approve.load() - gid = str(event.group_id) - if gid in a_config: - this_config = a_config[gid] - await check.send(f"当前群审批词条:{this_config}") - else: - await check.send("当前群从未配置过审批词条") - - -config = on_command('词条+', aliases={'/sp+', '/审批+'}, priority=1, block=True, - permission=GROUP_ADMIN | GROUP_OWNER | SUPERUSER) - - -@config.handle() -async def _(bot: Bot, event: GroupMessageEvent, state: T_State): - """ - /sp+ 增加本群词条 - """ - msg = str(event.get_message()) - sp_write = await approve.write(str(event.group_id), msg) - if sp_write: - await config.send(f"群{event.group_id}添加词条:{msg}") - else: - await config.send(f"{msg} 已存在于群{event.group_id}的词条中") - - -config_ = on_command('词条-', aliases={'/sp-', '/审批-'}, priority=1, block=True, - permission=GROUP_ADMIN | GROUP_OWNER | SUPERUSER) - - -@config_.handle() -async def _(bot: Bot, event: GroupMessageEvent, state: T_State): - """ - /sp- 删除本群某词条 - """ - msg = str(event.get_message()) - sp_delete = await approve.delete(str(event.group_id), msg) - if sp_delete: - await config_.send(f"群{event.group_id}删除入群审批词条:{msg}") - elif not sp_delete: - await config_.send('当前群不存在此词条') - elif sp_delete is None: - await config_.send(f'当前群从未配置过词条') - - -# 加群审批 -group_req = on_request(priority=1, block=True) - - -@group_req.handle() -async def gr_(bot: Bot, event: GroupRequestEvent): - raw = json.loads(event.json()) - gid = str(event.group_id) - flag = raw['flag'] - logger.info('flag:', str(flag)) - sub_type = raw['sub_type'] - if sub_type == 'add': - comment = raw['comment'] - word = re.findall(re.compile('答案:(.*)'), comment)[0] - compared = await verify(word, gid) - uid = event.user_id - if compared: - logger.info(f'同意{uid}加入群 {gid},验证消息为 “{word}”') - await bot.set_group_add_request( - flag=flag, - sub_type=sub_type, - approve=True, - reason=" ", - ) - with open(config_group, mode='r') as f: - admins_ = f.read() - admins = json.loads(admins_) - f.close() - if admins['su'] == "True": - for q in su: - await bot.send_msg(user_id=int(q), message=f'同意{uid}加入群 {gid},验证消息为 “{word}”') - if gid in admins: - for q in admins[gid]: - await bot.send_msg(message_type="private", user_id=q, group_id=int(gid), - message=f'同意{uid}加入群 {gid},验证消息为 “{word}”') - - elif not compared: - logger.info(f'拒绝{uid}加入群 {gid},验证消息为 “{word}”') - await bot.set_group_add_request( - flag=flag, - sub_type=sub_type, - approve=False, - reason="答案未通过群管验证,可修改答案后再次申请", - ) - with open(config_group, mode='r') as f: - admins_ = f.read() - admins = json.loads(admins_) - f.close() - if admins['su'] == "True": - for q in su: - await bot.send_msg(user_id=int(q), message=f'拒绝{uid}加入群 {gid},验证消息为 “{word}”') - if gid in admins: - for q in admins[gid]: - await bot.send_msg(message_type="private", user_id=q, group_id=int(gid), - message=f'拒绝{uid}加入群 {gid},验证消息为 “{word}”') - elif compared is None: - await group_req.finish() diff --git a/nonebot_plugin_admin_a/group_request_verify.py b/nonebot_plugin_admin_a/group_request_verify.py deleted file mode 100644 index 5685b1e7..00000000 --- a/nonebot_plugin_admin_a/group_request_verify.py +++ /dev/null @@ -1,40 +0,0 @@ -# python3 -# -*- coding: utf-8 -*- -# @Time : 2021/12/26 1:58 -# @Author : yzyyz -# @Email : youzyyz1384@qq.com -# @File : group_request_verify.py -# @Software: PyCharm -from nonebot import logger -from typing import Optional -from fuzzyfinder import fuzzyfinder -import json -import aiofiles -from pathlib import Path - -config_path = Path() / "config" -config_json = config_path / "admin.json" -config_group = config_path / "group_admin.json" - - -async def verify(word: str, group_id: str) -> Optional[bool]: - """ - 验证答案,验证消息必须大于等于答案长度的1/2 - :param word: 用户答案 - :param group_id: 群号 - :return: bool - """ - async with aiofiles.open(config_json, mode='r') as f: - answers_ = await f.read() - answers = json.loads(answers_) - if group_id in answers: - answer = answers[group_id] - suggestions = fuzzyfinder(word, answer) - result = list(suggestions) - if result and len(word) >= len(result[0]) / 2: - return True - else: - return False - else: - logger.info(f'群{group_id}从未配置审批词条,不进行操作') - return None diff --git a/nonebot_plugin_admin_a/notice.py b/nonebot_plugin_admin_a/notice.py deleted file mode 100644 index c26f45ba..00000000 --- a/nonebot_plugin_admin_a/notice.py +++ /dev/null @@ -1,116 +0,0 @@ -# python3 -# -*- coding: utf-8 -*- -# @Time : 2022/1/16 10:13 -# @Author : yzyyz -# @Email : youzyyz1384@qq.com -# @File : notice.py -# @Software: PyCharm - -from nonebot import on_command, logger -from nonebot.adapters.cqhttp import Bot, GroupMessageEvent, MessageEvent -from nonebot.adapters.cqhttp.permission import GROUP_ADMIN, GROUP_OWNER -from nonebot.permission import SUPERUSER -from nonebot.typing import T_State - -from . import approve -from .utils import At - -# 查看当前群分管 -gad = on_command('分管', aliases={"/gad", "/分群管理"}, priority=1, block=True, - permission=GROUP_ADMIN | GROUP_OWNER | SUPERUSER) - - -@gad.handle() -async def _(bot: Bot, event: GroupMessageEvent): - gid = str(event.group_id) - admins = await approve.g_admin() - try: - rely = str(admins[gid]) - logger.info(f"用户{event.user_id}查询群 {event.group_id} 分管成功") - await gad.send(f"本群分管:{rely}") - except KeyError: - logger.info(f"用户{event.user_id}查询群 {event.group_id} 分管失败") - await gad.send(f"查询不到呢,使用 分管+@xx 来添加分管") - - -# 查看所有分管 -su_g_admin = on_command('所有分管', aliases={"/sugad", "/su分群管理"}, priority=1, block=True, permission=SUPERUSER) - - -@su_g_admin.handle() -async def _(bot: Bot, event: MessageEvent): - admins = await approve.g_admin() - admins = str(admins) - logger.info("超级用户查询所有分管成功") - await su_g_admin.send(admins) - - -# 添加分群管理员 -g_admin = on_command('分管+', aliases={"/gad+", "分群管理+"}, priority=1, block=True, - permission=GROUP_ADMIN | GROUP_OWNER | SUPERUSER) - - -@g_admin.handle() -async def _(bot: Bot, event: GroupMessageEvent, state: T_State): - msg = str(event.get_message()) - sb = At(event.json()) - gid = str(event.group_id) - if sb and "all" not in sb: - for qq in sb: - g_admin_handle = await approve.g_admin_add(gid, int(qq)) - if g_admin_handle: - await g_admin.send(f"{qq}已成为本群分群管理:将接收加群处理结果") - else: - await g_admin.send(f"用户{qq}已存在") - else: - sb = str(event.get_message()).split(" ") - for qq in sb: - g_admin_handle = await approve.g_admin_add(gid, int(qq)) - if g_admin_handle: - await g_admin.send(f"{qq}已成为本群分群管理:将接收加群处理结果") - else: - await g_admin.send(f"用户{qq}已存在") - - -# 开启superuser接收处理结果 -su_gad = g_admin = on_command('接收', priority=1, block=True, permission=SUPERUSER) - - -@su_gad.handle() -async def _(bot: Bot, event: MessageEvent): - status = await approve.su_on_off() - if status: - await su_gad.finish("已开启超管消息接收") - else: - await su_gad.finish("已关闭超管消息接收") - - -# 删除分群管理 -g_admin_ = on_command('分管-', aliases={"/gad-", "分群管理-"}, priority=1, block=True, - permission=GROUP_ADMIN | GROUP_OWNER | SUPERUSER) - - -@g_admin_.handle() -async def _(bot: Bot, event: GroupMessageEvent, state: T_State): - msg = str(event.get_message()) - sb = At(event.json()) - gid = str(event.group_id) - if sb and "all" not in sb: - for qq in sb: - g_admin_del_handle = await approve.g_admin_del(gid, int(qq)) - if g_admin_del_handle: - await g_admin_.send(f"{qq}删除成功") - elif not g_admin_del_handle: - await g_admin_.send(f'{qq}还不是分群管理') - elif g_admin_del_handle is None: - await g_admin_.send(f"群{gid}未添加过分群管理\n使用/gadmin+ [用户(可@ 可qq)]来添加分群管理") - else: - sb = str(event.get_message()).split(" ") - for qq in sb: - g_admin_del_handle = await approve.g_admin_del(gid, int(qq)) - if g_admin_del_handle: - await g_admin_.send(f"{qq}删除成功") - elif not g_admin_del_handle: - await g_admin_.send(f'{qq}还不是分群管理') - elif g_admin_del_handle is None: - await g_admin_.send(f"群{gid}未添加过分群管理\n使用/gadmin+ [用户(可@ 可qq)]来添加分群管理") diff --git a/nonebot_plugin_admin_a/r18_pic_ban.py b/nonebot_plugin_admin_a/r18_pic_ban.py deleted file mode 100644 index 9df1d51d..00000000 --- a/nonebot_plugin_admin_a/r18_pic_ban.py +++ /dev/null @@ -1,47 +0,0 @@ -# python3 -# -*- coding: utf-8 -*- -# @Time : 2022/2/5 16:25 -# @Author : yzyyz -# @Email : youzyyz1384@qq.com -# @File : r18_pic_ban.py -# @Software: PyCharm -from nonebot import logger, on_message -from nonebot.adapters.cqhttp import Bot, GroupMessageEvent, MessageEvent -from nonebot.adapters.cqhttp.exception import ActionFailed - -from .utils import pic_ban_cof, banSb - -find_pic = on_message(priority=2, block=False) - - -@find_pic.handle() -async def check_pic(bot: Bot, event: GroupMessageEvent): - uid = [event.get_user_id()] - gid = event.group_id - eid = event.message_id - if isinstance(event, MessageEvent): - for msg in event.message: - if msg.type == "image": - url: str = msg.data["url"] - image_ = url - result = await pic_ban_cof(url=image_) - if result: - try: - await bot.delete_msg(message_id=eid) - logger.info('检测到违规图片,撤回') - except ActionFailed: - logger.info('检测到违规图片,但权限不足,撤回失败') - baning = banSb(gid, ban_list=uid) - async for baned in baning: - if baned: - try: - await baned - except ActionFailed: - await find_pic.finish("检测到违规图片,但权限不足") - logger.info('检测到违规图片,但权限不足,禁言失败') - else: - await bot.send(event=event, message="发送了违规图片,现对你进行处罚,有异议请联系管理员", at_sender=True) - logger.info(f"检测到违规图片,禁言操作成功,用户: {uid[0]}") - logger.info('检测到涩图') - else: - logger.info("图片安全") diff --git a/nonebot_plugin_admin_a/utils.py b/nonebot_plugin_admin_a/utils.py deleted file mode 100644 index ac6205e1..00000000 --- a/nonebot_plugin_admin_a/utils.py +++ /dev/null @@ -1,232 +0,0 @@ -# python3 -# -*- coding: utf-8 -*- -# @Time : 2022/1/16 10:15 -# @Author : yzyyz -# @Email : youzyyz1384@qq.com -# @File : utils.py -# @Software: PyCharm -import os -import re -import json -import httpx -import random -import base64 -import nonebot -from pathlib import Path -from nonebot import logger -from typing import Optional - -config_path = Path() / "config" -config_json = config_path / "admin.json" -config_group = config_path / "group_admin.json" -word_path = config_path / "word_config.txt" -words_path = Path() / "config" / "words" -res_path = Path() / "resource" -re_img_path = Path() / "resource" / "imgs" -ttf_name = Path() / "resource" / "msyhblod.ttf" -limit_word_path = config_path / "违禁词.txt" -limit_word_path_easy = config_path / "违禁词_简单.txt" -limit_level = config_path / "违禁词监控等级.json" - - - -def At(data: str): - """ - 检测at了谁 - :param data: event.json - :return: list - """ - try: - qq_list = [] - data = json.loads(data) - for msg in data["message"]: - if msg["type"] == "at": - if 'all' not in str(msg): - qq_list.append(int(msg["data"]["qq"])) - else: - return ['all'] - return qq_list - except KeyError: - return [] - - -async def init(): - """ - 初始化配置文件 - :return: - """ - if not os.path.exists(config_path): - os.mkdir(config_path) - logger.info("创建 config 文件夹") - if not os.path.exists(config_json): - with open(config_json, 'w', encoding='utf-8') as c: - c.write('{"1008611":["This_is_an_example"]}') - c.close() - logger.info("创建admin.json") - if not os.path.exists(config_group): - with open(config_group, 'w', encoding='utf-8') as c: - c.write('{"su":"True"}') - c.close() - logger.info("创建group_admin.json") - if not os.path.exists(word_path): - with open(word_path, 'w', encoding='utf-8') as c: - c.write('123456789\n') - c.close() - logger.info("创建word_config.txt") - if not os.path.exists(words_path): - os.mkdir(words_path) - logger.info("创建/config/words/") - if not os.path.exists(res_path): - os.mkdir(res_path) - logger.info("创建/resource") - if not os.path.exists(re_img_path): - os.mkdir(re_img_path) - logger.info("创建/resource/imgs") - if not os.path.exists(ttf_name): - logger.info("下载资源字体") - async with httpx.AsyncClient() as client: - r = (await client.get(url="https://cdn.jsdelivr.net/gh/yzyyz1387/blogimages/msyhblod.ttf")).content - with open(ttf_name, "wb") as tfn: - tfn.write(r) - tfn.close() - if not os.path.exists(limit_word_path): - logger.info("下载严格违禁词库") - async with httpx.AsyncClient() as client: - r = (await client.get(url="https://cdn.jsdelivr.net/gh/yzyyz1387/nwafu/f_words/f_word_s")).text - with open(limit_word_path, "w",encoding='utf-8') as lwp: - lwp.write(r) - lwp.close() - if not os.path.exists(limit_word_path_easy): - logger.info("下载简单违禁词库") - async with httpx.AsyncClient() as client: - r = (await client.get(url="https://cdn.jsdelivr.net/gh/yzyyz1387/nwafu/f_words/f_word_easy")).text - with open(limit_word_path_easy, "w",encoding='utf-8') as lwp: - lwp.write(r) - lwp.close() - if not os.path.exists(limit_level): - bot = nonebot.get_bot() - logger.info("创建违禁词监控等级配置文件,分群设置,默认easy") - g_list = (await bot.get_group_list()) - level_dict={} - for group in g_list: - level_dict.update({str(group['group_id']):"easy"}) - with open(limit_level, "w", encoding='utf-8') as lwp: - lwp.write(f'{json.dumps(level_dict)}') - lwp.close() - - logger.info("Admin 插件 初始化检测完成") - - -async def banSb(gid: int, ban_list: list, **time: int): - """ - 构造禁言 - :param gid: 群号 - :param time: 时间(s) - :param ban_list: at列表 - :return:禁言操作 - """ - if 'all' in ban_list: - yield nonebot.get_bot().set_group_whole_ban( - group_id=gid, - enable=True - ) - else: - if not time: - time = random.randint(1, 2591999) - else: - time = time['time'] - for qq in ban_list: - yield nonebot.get_bot().set_group_ban( - group_id=gid, - user_id=qq, - duration=time, - ) - - -async def replace_tmr(msg: str) -> str: - """ - 原始消息简单处理 - :param msg: 消息字符串 - :return: 去除cq码,链接等 - """ - find_cq = re.compile(r"(\[CQ:.*])") - find_link = re.compile("(https?://.*[^\u4e00-\u9fa5])") - cq_code = re.findall(find_cq, msg) - for cq in cq_code: - msg = msg.replace(cq, "") - links = re.findall(find_link, msg) - for link in links: - msg = msg.replace(link, "链接") - return msg - - -async def participle_simple_handle() -> set: - """ - wordcloud停用词 - """ - prep_ = ['么', '了', '与', '不', '且', '之', '为', '兮', '其', '到', '云', '阿', '却', '个', - '以', '们', '价', '似', '讫', '诸', '取', '若', '得', '逝', '将', '夫', '头', '只', - '吗', '向', '吧', '呗', '呃', '呀', '员', '呵', '呢', '哇', '咦', '哟', '哉', '啊', - '哩', '啵', '唻', '啰', '唯', '嘛', '噬', '嚜', '家', '如', '掉', '给', '维', '圪', - '在', '尔', '惟', '子', '赊', '焉', '然', '旃', '所', '见', '斯', '者', '来', '欤', - '是', '毋', '曰', '的', '每', '看', '着', '矣', '罢', '而', '耶', '粤', '聿', '等', - '言', '越', '馨', '趴', '从', '自从', '自', '打', '到', '往', '在', '由', '向', '于', - '至', '趁', '当', '当着', '沿着', '顺着', '按', '按照', '遵照', '依照', '靠', '本着', - '用', '通过', '根据', '据', '拿', '比', '因', '因为', '由于', '为', '为了', '为着', - '被', '给', '让', '叫', '归', '由', '把', '将', '管', '对', '对于', '关于', '跟', '和', '给', '替', '向', '同', '除了'] - - pron_ = ["各个", "本人", "这个", "各自", "哪些", "怎的", "我", "大家", "她们", "多少", "怎么", "那么", "那样", "怎样", "几时", "哪儿", "我们", "自我", - "什么", "哪个", "那个", "另外", "自己", "哪样", "这儿", "那些", "这样", "那儿", "它们", "它", "他", "你", "谁", "今", "吗", "是", "乌", - "如何", "彼此", "其次", "列位", "该", "各", "然", "安", "之", "怎", "夫", "其", "每", "您", "伊", "此", "者", "咱们", "某", "诸位", - "这些", "予", "任何", "若", "彼", "恁", "焉", "兹", "俺", "汝", "几许", "多咱", "谁谁", "有些", "干吗", "何如", "怎么样", "好多", "哪门子", - "这程子", "他人", "奈何", "人家", "若干", "本身", "旁人", "其他", "其余", "一切", "如此", "谁人", "怎么着", "那会儿", "自家", "哪会儿", "谁边", - "这会儿", "几儿", "这么些", "那阵儿", "那么点儿", "这么点儿", "这么样", "这阵儿", "一应", "多会儿", "何许", "若何", "大伙儿", "几多", "恁地", "谁个", - "乃尔", "那程子", "多早晚", "如许", "倷", "孰", "侬", "怹", "朕", "他们", "这么着", "那么些", "咱家", "你们", "那么着"] - - others_ = ['就', '这', '那', '都', '也', '还', '又', '有', '没', '好', '我', '我的', '说', '去', '点', '不是', '就是', '要', '一个', '现在', - '啥'] - - sum_ = set(prep_ + pron_ + others_) - return sum_ - - -async def pic_cof(data: str, **kwargs) -> Optional[dict]: - try: - if kwargs['mode'] == 'url': - async with httpx.AsyncClient() as client: - data_ = str(base64.b64encode((await client.get(url=data)).content),encoding='utf-8') - json_ = {"data": [f"data:image/png;base64,{data_}"]} - else: - json_ = {"data": [f"data:image/png;base64,{data}"]} - except Exception as err: - json_ = {"data": ["data:image/png;base64,"]} - print(err) - try: - async with httpx.AsyncClient() as client: - r = (await client.post( - url='https://hf.space/gradioiframe/mayhug/rainchan-image-porn-detection/+/api/predict/', - json=json_)).json() - if 'error' in r: - return None - else: - return r - except Exception as err: - logger.debug(f'于"utils.py"中的 pic_cof 发生错误:{err}') - return None - - -async def pic_ban_cof(**data) -> Optional[bool]: - global result - if data: - if 'url' in data: - result = await pic_cof(data=data['url'], mode='url') - if 'base64' in data: - result = await pic_cof(data=data['data'], mode='default') - if result: - if result['data'][0]['label'] != 'safe': - return True - else: - return False - else: - return None - diff --git a/nonebot_plugin_admin_a/word_analyze.py b/nonebot_plugin_admin_a/word_analyze.py deleted file mode 100644 index 7ffc7caf..00000000 --- a/nonebot_plugin_admin_a/word_analyze.py +++ /dev/null @@ -1,107 +0,0 @@ -# python3 -# -*- coding: utf-8 -*- -# @Time : 2022/1/16 22:21 -# @Author : yzyyz -# @Email : youzyyz1384@qq.com -# @File : word_analyze.py -# @Software: PyCharm -from nonebot import on_command, logger, on_message -from nonebot.adapters.cqhttp import Bot, GroupMessageEvent, MessageSegment -from nonebot.adapters.cqhttp.permission import GROUP_ADMIN, GROUP_OWNER -from nonebot.permission import SUPERUSER -from .utils import init, replace_tmr, participle_simple_handle -from pathlib import Path -import os - - -config_path = Path() / "config" -word_path = config_path / "word_config.txt" -words_path = Path() / "config" / "words" -img_path = Path() / "resource" / "imgs" - -word_start = on_command("记录本群", block=True, priority=1, permission=GROUP_ADMIN | GROUP_OWNER | SUPERUSER) - - -@word_start.handle() -async def _(bot: Bot, event: GroupMessageEvent): - gid = str(event.group_id) - if not os.path.exists(word_path): - await init() - with open(word_path, 'r+', encoding='utf-8') as c: - txt = c.read().split("\n") - if gid not in txt: - c.write(gid + "\n") - c.close() - logger.info(f"开始记录{gid}") - await word_start.finish("成功") - else: - logger.info(f"{gid}已存在") - await word_start.finish(f"{gid}已存在") - - -word_stop = on_command("停止记录本群", block=True, priority=1, permission=GROUP_ADMIN | GROUP_OWNER | SUPERUSER) - - -@word_stop.handle() -async def _(bot: Bot, event: GroupMessageEvent): - gid = str(event.group_id) - if not os.path.exists(word_path): - await init() - txt = open(word_path, 'r', encoding='utf-8').read() - if gid in txt: - with open(word_path,'w',encoding='utf-8') as c: - c.write(txt.replace(gid,"")) - c.close() - logger.info(f"停止记录{gid}") - await word_start.finish("成功,曾经的记录不会被删除") - else: - logger.info(f"停用失败:{gid}不存在") - await word_start.finish(f"停用失败:{gid}不存在") - -word = on_message(priority=10) - - -@word.handle() -async def _(bot: Bot, event: GroupMessageEvent): - """ - 记录聊天内容 - :param bot: - :param event: - :return: - """ - gid = str(event.group_id) - msg = str(event.get_message()).replace(" ", "") - path_temp = config_path / f"{str(gid)}.txt" - if not os.path.exists(word_path): - await init() - txt = open(word_path, "r", encoding="utf-8").read().split("\n") - if gid in txt: - msg = await replace_tmr(msg) - with open(path_temp, "a+") as c: - c.write(msg + "\n") - - -cloud = on_command("群词云", priority=1) - - -@cloud.handle() -async def _(bot: Bot, event: GroupMessageEvent): - from wordcloud import WordCloud - import jieba - ttf_name = Path() / "resource" / "msyhblod.ttf" - gid = str(event.group_id) - path_temp = words_path / f"{str(gid)}.txt" - dir_list = os.listdir(words_path) - if gid + ".txt" in dir_list: - text = open(path_temp).read() - txt = jieba.lcut(text) - stop_ = await participle_simple_handle() - string = " ".join(txt) - try: - wc = WordCloud(font_path=str(ttf_name.resolve()), width=800, height=600, mode='RGBA', - background_color="#ffffff", stopwords=stop_).generate(string) - img = Path(img_path / f"{gid}.png") - wc.to_file(img) - await cloud.send(MessageSegment.image(img)) - except Exception as err: - await cloud.send(f"出现错误{type(err)}:{err}") diff --git a/requirements.txt b/requirements.txt index 9a647286..c48e2605 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,7 +1,10 @@ -aiofiles==0.8.0 -fuzzyfinder==2.1.0 -httpx==0.19.0 +aiofiles +fuzzyfinder +httpx jieba==0.42.1 nonebot-adapter-onebot>=2.0.0-beta.1 nonebot2>=2.0.0-beta.1 - +tencentcloud-sdk-python>=3.0.580 +setuptools +jinja2 +pyppeteer \ No newline at end of file