├── .gitignore
├── CODE_OF_CONDUCT.md
├── LICENSE
├── MsgObj.py
├── README.md
├── bot.py
├── command_session.py
├── init_bot.py
├── plugin.py
└── requirements.txt
/.gitignore:
--------------------------------------------------------------------------------
1 | config.py
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Contributor Covenant Code of Conduct
2 |
3 | ## Our Pledge
4 |
5 | In the interest of fostering an open and welcoming environment, we as
6 | contributors and maintainers pledge to making participation in our project and
7 | our community a harassment-free experience for everyone, regardless of age, body
8 | size, disability, ethnicity, sex characteristics, gender identity and expression,
9 | level of experience, education, socio-economic status, nationality, personal
10 | appearance, race, religion, or sexual identity and orientation.
11 |
12 | ## Our Standards
13 |
14 | Examples of behavior that contributes to creating a positive environment
15 | include:
16 |
17 | * Using welcoming and inclusive language
18 | * Being respectful of differing viewpoints and experiences
19 | * Gracefully accepting constructive criticism
20 | * Focusing on what is best for the community
21 | * Showing empathy towards other community members
22 |
23 | Examples of unacceptable behavior by participants include:
24 |
25 | * The use of sexualized language or imagery and unwelcome sexual attention or
26 | advances
27 | * Trolling, insulting/derogatory comments, and personal or political attacks
28 | * Public or private harassment
29 | * Publishing others' private information, such as a physical or electronic
30 | address, without explicit permission
31 | * Other conduct which could reasonably be considered inappropriate in a
32 | professional setting
33 |
34 | ## Our Responsibilities
35 |
36 | Project maintainers are responsible for clarifying the standards of acceptable
37 | behavior and are expected to take appropriate and fair corrective action in
38 | response to any instances of unacceptable behavior.
39 |
40 | Project maintainers have the right and responsibility to remove, edit, or
41 | reject comments, commits, code, wiki edits, issues, and other contributions
42 | that are not aligned to this Code of Conduct, or to ban temporarily or
43 | permanently any contributor for other behaviors that they deem inappropriate,
44 | threatening, offensive, or harmful.
45 |
46 | ## Scope
47 |
48 | This Code of Conduct applies both within project spaces and in public spaces
49 | when an individual is representing the project or its community. Examples of
50 | representing a project or community include using an official project e-mail
51 | address, posting via an official social media account, or acting as an appointed
52 | representative at an online or offline event. Representation of a project may be
53 | further defined and clarified by project maintainers.
54 |
55 | ## Enforcement
56 |
57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be
58 | reported by contacting the project team at 1149558764@qq.com. All
59 | complaints will be reviewed and investigated and will result in a response that
60 | is deemed necessary and appropriate to the circumstances. The project team is
61 | obligated to maintain confidentiality with regard to the reporter of an incident.
62 | Further details of specific enforcement policies may be posted separately.
63 |
64 | Project maintainers who do not follow or enforce the Code of Conduct in good
65 | faith may face temporary or permanent repercussions as determined by other
66 | members of the project's leadership.
67 |
68 | ## Attribution
69 |
70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
72 |
73 | [homepage]: https://www.contributor-covenant.org
74 |
75 | For answers to common questions about this code of conduct, see
76 | https://www.contributor-covenant.org/faq
77 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU AFFERO GENERAL PUBLIC LICENSE
2 | Version 3, 19 November 2007
3 |
4 | Copyright (C) 2007 Free Software Foundation, Inc.
5 | Everyone is permitted to copy and distribute verbatim copies
6 | of this license document, but changing it is not allowed.
7 |
8 | Preamble
9 |
10 | The GNU Affero General Public License is a free, copyleft license for
11 | software and other kinds of works, specifically designed to ensure
12 | cooperation with the community in the case of network server software.
13 |
14 | The licenses for most software and other practical works are designed
15 | to take away your freedom to share and change the works. By contrast,
16 | our General Public Licenses are intended to guarantee your freedom to
17 | share and change all versions of a program--to make sure it remains free
18 | software for all its users.
19 |
20 | When we speak of free software, we are referring to freedom, not
21 | price. Our General Public Licenses are designed to make sure that you
22 | have the freedom to distribute copies of free software (and charge for
23 | them if you wish), that you receive source code or can get it if you
24 | want it, that you can change the software or use pieces of it in new
25 | free programs, and that you know you can do these things.
26 |
27 | Developers that use our General Public Licenses protect your rights
28 | with two steps: (1) assert copyright on the software, and (2) offer
29 | you this License which gives you legal permission to copy, distribute
30 | and/or modify the software.
31 |
32 | A secondary benefit of defending all users' freedom is that
33 | improvements made in alternate versions of the program, if they
34 | receive widespread use, become available for other developers to
35 | incorporate. Many developers of free software are heartened and
36 | encouraged by the resulting cooperation. However, in the case of
37 | software used on network servers, this result may fail to come about.
38 | The GNU General Public License permits making a modified version and
39 | letting the public access it on a server without ever releasing its
40 | source code to the public.
41 |
42 | The GNU Affero General Public License is designed specifically to
43 | ensure that, in such cases, the modified source code becomes available
44 | to the community. It requires the operator of a network server to
45 | provide the source code of the modified version running there to the
46 | users of that server. Therefore, public use of a modified version, on
47 | a publicly accessible server, gives the public access to the source
48 | code of the modified version.
49 |
50 | An older license, called the Affero General Public License and
51 | published by Affero, was designed to accomplish similar goals. This is
52 | a different license, not a version of the Affero GPL, but Affero has
53 | released a new version of the Affero GPL which permits relicensing under
54 | this license.
55 |
56 | The precise terms and conditions for copying, distribution and
57 | modification follow.
58 |
59 | TERMS AND CONDITIONS
60 |
61 | 0. Definitions.
62 |
63 | "This License" refers to version 3 of the GNU Affero General Public License.
64 |
65 | "Copyright" also means copyright-like laws that apply to other kinds of
66 | works, such as semiconductor masks.
67 |
68 | "The Program" refers to any copyrightable work licensed under this
69 | License. Each licensee is addressed as "you". "Licensees" and
70 | "recipients" may be individuals or organizations.
71 |
72 | To "modify" a work means to copy from or adapt all or part of the work
73 | in a fashion requiring copyright permission, other than the making of an
74 | exact copy. The resulting work is called a "modified version" of the
75 | earlier work or a work "based on" the earlier work.
76 |
77 | A "covered work" means either the unmodified Program or a work based
78 | on the Program.
79 |
80 | To "propagate" a work means to do anything with it that, without
81 | permission, would make you directly or secondarily liable for
82 | infringement under applicable copyright law, except executing it on a
83 | computer or modifying a private copy. Propagation includes copying,
84 | distribution (with or without modification), making available to the
85 | public, and in some countries other activities as well.
86 |
87 | To "convey" a work means any kind of propagation that enables other
88 | parties to make or receive copies. Mere interaction with a user through
89 | a computer network, with no transfer of a copy, is not conveying.
90 |
91 | An interactive user interface displays "Appropriate Legal Notices"
92 | to the extent that it includes a convenient and prominently visible
93 | feature that (1) displays an appropriate copyright notice, and (2)
94 | tells the user that there is no warranty for the work (except to the
95 | extent that warranties are provided), that licensees may convey the
96 | work under this License, and how to view a copy of this License. If
97 | the interface presents a list of user commands or options, such as a
98 | menu, a prominent item in the list meets this criterion.
99 |
100 | 1. Source Code.
101 |
102 | The "source code" for a work means the preferred form of the work
103 | for making modifications to it. "Object code" means any non-source
104 | form of a work.
105 |
106 | A "Standard Interface" means an interface that either is an official
107 | standard defined by a recognized standards body, or, in the case of
108 | interfaces specified for a particular programming language, one that
109 | is widely used among developers working in that language.
110 |
111 | The "System Libraries" of an executable work include anything, other
112 | than the work as a whole, that (a) is included in the normal form of
113 | packaging a Major Component, but which is not part of that Major
114 | Component, and (b) serves only to enable use of the work with that
115 | Major Component, or to implement a Standard Interface for which an
116 | implementation is available to the public in source code form. A
117 | "Major Component", in this context, means a major essential component
118 | (kernel, window system, and so on) of the specific operating system
119 | (if any) on which the executable work runs, or a compiler used to
120 | produce the work, or an object code interpreter used to run it.
121 |
122 | The "Corresponding Source" for a work in object code form means all
123 | the source code needed to generate, install, and (for an executable
124 | work) run the object code and to modify the work, including scripts to
125 | control those activities. However, it does not include the work's
126 | System Libraries, or general-purpose tools or generally available free
127 | programs which are used unmodified in performing those activities but
128 | which are not part of the work. For example, Corresponding Source
129 | includes interface definition files associated with source files for
130 | the work, and the source code for shared libraries and dynamically
131 | linked subprograms that the work is specifically designed to require,
132 | such as by intimate data communication or control flow between those
133 | subprograms and other parts of the work.
134 |
135 | The Corresponding Source need not include anything that users
136 | can regenerate automatically from other parts of the Corresponding
137 | Source.
138 |
139 | The Corresponding Source for a work in source code form is that
140 | same work.
141 |
142 | 2. Basic Permissions.
143 |
144 | All rights granted under this License are granted for the term of
145 | copyright on the Program, and are irrevocable provided the stated
146 | conditions are met. This License explicitly affirms your unlimited
147 | permission to run the unmodified Program. The output from running a
148 | covered work is covered by this License only if the output, given its
149 | content, constitutes a covered work. This License acknowledges your
150 | rights of fair use or other equivalent, as provided by copyright law.
151 |
152 | You may make, run and propagate covered works that you do not
153 | convey, without conditions so long as your license otherwise remains
154 | in force. You may convey covered works to others for the sole purpose
155 | of having them make modifications exclusively for you, or provide you
156 | with facilities for running those works, provided that you comply with
157 | the terms of this License in conveying all material for which you do
158 | not control copyright. Those thus making or running the covered works
159 | for you must do so exclusively on your behalf, under your direction
160 | and control, on terms that prohibit them from making any copies of
161 | your copyrighted material outside their relationship with you.
162 |
163 | Conveying under any other circumstances is permitted solely under
164 | the conditions stated below. Sublicensing is not allowed; section 10
165 | makes it unnecessary.
166 |
167 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
168 |
169 | No covered work shall be deemed part of an effective technological
170 | measure under any applicable law fulfilling obligations under article
171 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or
172 | similar laws prohibiting or restricting circumvention of such
173 | measures.
174 |
175 | When you convey a covered work, you waive any legal power to forbid
176 | circumvention of technological measures to the extent such circumvention
177 | is effected by exercising rights under this License with respect to
178 | the covered work, and you disclaim any intention to limit operation or
179 | modification of the work as a means of enforcing, against the work's
180 | users, your or third parties' legal rights to forbid circumvention of
181 | technological measures.
182 |
183 | 4. Conveying Verbatim Copies.
184 |
185 | You may convey verbatim copies of the Program's source code as you
186 | receive it, in any medium, provided that you conspicuously and
187 | appropriately publish on each copy an appropriate copyright notice;
188 | keep intact all notices stating that this License and any
189 | non-permissive terms added in accord with section 7 apply to the code;
190 | keep intact all notices of the absence of any warranty; and give all
191 | recipients a copy of this License along with the Program.
192 |
193 | You may charge any price or no price for each copy that you convey,
194 | and you may offer support or warranty protection for a fee.
195 |
196 | 5. Conveying Modified Source Versions.
197 |
198 | You may convey a work based on the Program, or the modifications to
199 | produce it from the Program, in the form of source code under the
200 | terms of section 4, provided that you also meet all of these conditions:
201 |
202 | a) The work must carry prominent notices stating that you modified
203 | it, and giving a relevant date.
204 |
205 | b) The work must carry prominent notices stating that it is
206 | released under this License and any conditions added under section
207 | 7. This requirement modifies the requirement in section 4 to
208 | "keep intact all notices".
209 |
210 | c) You must license the entire work, as a whole, under this
211 | License to anyone who comes into possession of a copy. This
212 | License will therefore apply, along with any applicable section 7
213 | additional terms, to the whole of the work, and all its parts,
214 | regardless of how they are packaged. This License gives no
215 | permission to license the work in any other way, but it does not
216 | invalidate such permission if you have separately received it.
217 |
218 | d) If the work has interactive user interfaces, each must display
219 | Appropriate Legal Notices; however, if the Program has interactive
220 | interfaces that do not display Appropriate Legal Notices, your
221 | work need not make them do so.
222 |
223 | A compilation of a covered work with other separate and independent
224 | works, which are not by their nature extensions of the covered work,
225 | and which are not combined with it such as to form a larger program,
226 | in or on a volume of a storage or distribution medium, is called an
227 | "aggregate" if the compilation and its resulting copyright are not
228 | used to limit the access or legal rights of the compilation's users
229 | beyond what the individual works permit. Inclusion of a covered work
230 | in an aggregate does not cause this License to apply to the other
231 | parts of the aggregate.
232 |
233 | 6. Conveying Non-Source Forms.
234 |
235 | You may convey a covered work in object code form under the terms
236 | of sections 4 and 5, provided that you also convey the
237 | machine-readable Corresponding Source under the terms of this License,
238 | in one of these ways:
239 |
240 | a) Convey the object code in, or embodied in, a physical product
241 | (including a physical distribution medium), accompanied by the
242 | Corresponding Source fixed on a durable physical medium
243 | customarily used for software interchange.
244 |
245 | b) Convey the object code in, or embodied in, a physical product
246 | (including a physical distribution medium), accompanied by a
247 | written offer, valid for at least three years and valid for as
248 | long as you offer spare parts or customer support for that product
249 | model, to give anyone who possesses the object code either (1) a
250 | copy of the Corresponding Source for all the software in the
251 | product that is covered by this License, on a durable physical
252 | medium customarily used for software interchange, for a price no
253 | more than your reasonable cost of physically performing this
254 | conveying of source, or (2) access to copy the
255 | Corresponding Source from a network server at no charge.
256 |
257 | c) Convey individual copies of the object code with a copy of the
258 | written offer to provide the Corresponding Source. This
259 | alternative is allowed only occasionally and noncommercially, and
260 | only if you received the object code with such an offer, in accord
261 | with subsection 6b.
262 |
263 | d) Convey the object code by offering access from a designated
264 | place (gratis or for a charge), and offer equivalent access to the
265 | Corresponding Source in the same way through the same place at no
266 | further charge. You need not require recipients to copy the
267 | Corresponding Source along with the object code. If the place to
268 | copy the object code is a network server, the Corresponding Source
269 | may be on a different server (operated by you or a third party)
270 | that supports equivalent copying facilities, provided you maintain
271 | clear directions next to the object code saying where to find the
272 | Corresponding Source. Regardless of what server hosts the
273 | Corresponding Source, you remain obligated to ensure that it is
274 | available for as long as needed to satisfy these requirements.
275 |
276 | e) Convey the object code using peer-to-peer transmission, provided
277 | you inform other peers where the object code and Corresponding
278 | Source of the work are being offered to the general public at no
279 | charge under subsection 6d.
280 |
281 | A separable portion of the object code, whose source code is excluded
282 | from the Corresponding Source as a System Library, need not be
283 | included in conveying the object code work.
284 |
285 | A "User Product" is either (1) a "consumer product", which means any
286 | tangible personal property which is normally used for personal, family,
287 | or household purposes, or (2) anything designed or sold for incorporation
288 | into a dwelling. In determining whether a product is a consumer product,
289 | doubtful cases shall be resolved in favor of coverage. For a particular
290 | product received by a particular user, "normally used" refers to a
291 | typical or common use of that class of product, regardless of the status
292 | of the particular user or of the way in which the particular user
293 | actually uses, or expects or is expected to use, the product. A product
294 | is a consumer product regardless of whether the product has substantial
295 | commercial, industrial or non-consumer uses, unless such uses represent
296 | the only significant mode of use of the product.
297 |
298 | "Installation Information" for a User Product means any methods,
299 | procedures, authorization keys, or other information required to install
300 | and execute modified versions of a covered work in that User Product from
301 | a modified version of its Corresponding Source. The information must
302 | suffice to ensure that the continued functioning of the modified object
303 | code is in no case prevented or interfered with solely because
304 | modification has been made.
305 |
306 | If you convey an object code work under this section in, or with, or
307 | specifically for use in, a User Product, and the conveying occurs as
308 | part of a transaction in which the right of possession and use of the
309 | User Product is transferred to the recipient in perpetuity or for a
310 | fixed term (regardless of how the transaction is characterized), the
311 | Corresponding Source conveyed under this section must be accompanied
312 | by the Installation Information. But this requirement does not apply
313 | if neither you nor any third party retains the ability to install
314 | modified object code on the User Product (for example, the work has
315 | been installed in ROM).
316 |
317 | The requirement to provide Installation Information does not include a
318 | requirement to continue to provide support service, warranty, or updates
319 | for a work that has been modified or installed by the recipient, or for
320 | the User Product in which it has been modified or installed. Access to a
321 | network may be denied when the modification itself materially and
322 | adversely affects the operation of the network or violates the rules and
323 | protocols for communication across the network.
324 |
325 | Corresponding Source conveyed, and Installation Information provided,
326 | in accord with this section must be in a format that is publicly
327 | documented (and with an implementation available to the public in
328 | source code form), and must require no special password or key for
329 | unpacking, reading or copying.
330 |
331 | 7. Additional Terms.
332 |
333 | "Additional permissions" are terms that supplement the terms of this
334 | License by making exceptions from one or more of its conditions.
335 | Additional permissions that are applicable to the entire Program shall
336 | be treated as though they were included in this License, to the extent
337 | that they are valid under applicable law. If additional permissions
338 | apply only to part of the Program, that part may be used separately
339 | under those permissions, but the entire Program remains governed by
340 | this License without regard to the additional permissions.
341 |
342 | When you convey a copy of a covered work, you may at your option
343 | remove any additional permissions from that copy, or from any part of
344 | it. (Additional permissions may be written to require their own
345 | removal in certain cases when you modify the work.) You may place
346 | additional permissions on material, added by you to a covered work,
347 | for which you have or can give appropriate copyright permission.
348 |
349 | Notwithstanding any other provision of this License, for material you
350 | add to a covered work, you may (if authorized by the copyright holders of
351 | that material) supplement the terms of this License with terms:
352 |
353 | a) Disclaiming warranty or limiting liability differently from the
354 | terms of sections 15 and 16 of this License; or
355 |
356 | b) Requiring preservation of specified reasonable legal notices or
357 | author attributions in that material or in the Appropriate Legal
358 | Notices displayed by works containing it; or
359 |
360 | c) Prohibiting misrepresentation of the origin of that material, or
361 | requiring that modified versions of such material be marked in
362 | reasonable ways as different from the original version; or
363 |
364 | d) Limiting the use for publicity purposes of names of licensors or
365 | authors of the material; or
366 |
367 | e) Declining to grant rights under trademark law for use of some
368 | trade names, trademarks, or service marks; or
369 |
370 | f) Requiring indemnification of licensors and authors of that
371 | material by anyone who conveys the material (or modified versions of
372 | it) with contractual assumptions of liability to the recipient, for
373 | any liability that these contractual assumptions directly impose on
374 | those licensors and authors.
375 |
376 | All other non-permissive additional terms are considered "further
377 | restrictions" within the meaning of section 10. If the Program as you
378 | received it, or any part of it, contains a notice stating that it is
379 | governed by this License along with a term that is a further
380 | restriction, you may remove that term. If a license document contains
381 | a further restriction but permits relicensing or conveying under this
382 | License, you may add to a covered work material governed by the terms
383 | of that license document, provided that the further restriction does
384 | not survive such relicensing or conveying.
385 |
386 | If you add terms to a covered work in accord with this section, you
387 | must place, in the relevant source files, a statement of the
388 | additional terms that apply to those files, or a notice indicating
389 | where to find the applicable terms.
390 |
391 | Additional terms, permissive or non-permissive, may be stated in the
392 | form of a separately written license, or stated as exceptions;
393 | the above requirements apply either way.
394 |
395 | 8. Termination.
396 |
397 | You may not propagate or modify a covered work except as expressly
398 | provided under this License. Any attempt otherwise to propagate or
399 | modify it is void, and will automatically terminate your rights under
400 | this License (including any patent licenses granted under the third
401 | paragraph of section 11).
402 |
403 | However, if you cease all violation of this License, then your
404 | license from a particular copyright holder is reinstated (a)
405 | provisionally, unless and until the copyright holder explicitly and
406 | finally terminates your license, and (b) permanently, if the copyright
407 | holder fails to notify you of the violation by some reasonable means
408 | prior to 60 days after the cessation.
409 |
410 | Moreover, your license from a particular copyright holder is
411 | reinstated permanently if the copyright holder notifies you of the
412 | violation by some reasonable means, this is the first time you have
413 | received notice of violation of this License (for any work) from that
414 | copyright holder, and you cure the violation prior to 30 days after
415 | your receipt of the notice.
416 |
417 | Termination of your rights under this section does not terminate the
418 | licenses of parties who have received copies or rights from you under
419 | this License. If your rights have been terminated and not permanently
420 | reinstated, you do not qualify to receive new licenses for the same
421 | material under section 10.
422 |
423 | 9. Acceptance Not Required for Having Copies.
424 |
425 | You are not required to accept this License in order to receive or
426 | run a copy of the Program. Ancillary propagation of a covered work
427 | occurring solely as a consequence of using peer-to-peer transmission
428 | to receive a copy likewise does not require acceptance. However,
429 | nothing other than this License grants you permission to propagate or
430 | modify any covered work. These actions infringe copyright if you do
431 | not accept this License. Therefore, by modifying or propagating a
432 | covered work, you indicate your acceptance of this License to do so.
433 |
434 | 10. Automatic Licensing of Downstream Recipients.
435 |
436 | Each time you convey a covered work, the recipient automatically
437 | receives a license from the original licensors, to run, modify and
438 | propagate that work, subject to this License. You are not responsible
439 | for enforcing compliance by third parties with this License.
440 |
441 | An "entity transaction" is a transaction transferring control of an
442 | organization, or substantially all assets of one, or subdividing an
443 | organization, or merging organizations. If propagation of a covered
444 | work results from an entity transaction, each party to that
445 | transaction who receives a copy of the work also receives whatever
446 | licenses to the work the party's predecessor in interest had or could
447 | give under the previous paragraph, plus a right to possession of the
448 | Corresponding Source of the work from the predecessor in interest, if
449 | the predecessor has it or can get it with reasonable efforts.
450 |
451 | You may not impose any further restrictions on the exercise of the
452 | rights granted or affirmed under this License. For example, you may
453 | not impose a license fee, royalty, or other charge for exercise of
454 | rights granted under this License, and you may not initiate litigation
455 | (including a cross-claim or counterclaim in a lawsuit) alleging that
456 | any patent claim is infringed by making, using, selling, offering for
457 | sale, or importing the Program or any portion of it.
458 |
459 | 11. Patents.
460 |
461 | A "contributor" is a copyright holder who authorizes use under this
462 | License of the Program or a work on which the Program is based. The
463 | work thus licensed is called the contributor's "contributor version".
464 |
465 | A contributor's "essential patent claims" are all patent claims
466 | owned or controlled by the contributor, whether already acquired or
467 | hereafter acquired, that would be infringed by some manner, permitted
468 | by this License, of making, using, or selling its contributor version,
469 | but do not include claims that would be infringed only as a
470 | consequence of further modification of the contributor version. For
471 | purposes of this definition, "control" includes the right to grant
472 | patent sublicenses in a manner consistent with the requirements of
473 | this License.
474 |
475 | Each contributor grants you a non-exclusive, worldwide, royalty-free
476 | patent license under the contributor's essential patent claims, to
477 | make, use, sell, offer for sale, import and otherwise run, modify and
478 | propagate the contents of its contributor version.
479 |
480 | In the following three paragraphs, a "patent license" is any express
481 | agreement or commitment, however denominated, not to enforce a patent
482 | (such as an express permission to practice a patent or covenant not to
483 | sue for patent infringement). To "grant" such a patent license to a
484 | party means to make such an agreement or commitment not to enforce a
485 | patent against the party.
486 |
487 | If you convey a covered work, knowingly relying on a patent license,
488 | and the Corresponding Source of the work is not available for anyone
489 | to copy, free of charge and under the terms of this License, through a
490 | publicly available network server or other readily accessible means,
491 | then you must either (1) cause the Corresponding Source to be so
492 | available, or (2) arrange to deprive yourself of the benefit of the
493 | patent license for this particular work, or (3) arrange, in a manner
494 | consistent with the requirements of this License, to extend the patent
495 | license to downstream recipients. "Knowingly relying" means you have
496 | actual knowledge that, but for the patent license, your conveying the
497 | covered work in a country, or your recipient's use of the covered work
498 | in a country, would infringe one or more identifiable patents in that
499 | country that you have reason to believe are valid.
500 |
501 | If, pursuant to or in connection with a single transaction or
502 | arrangement, you convey, or propagate by procuring conveyance of, a
503 | covered work, and grant a patent license to some of the parties
504 | receiving the covered work authorizing them to use, propagate, modify
505 | or convey a specific copy of the covered work, then the patent license
506 | you grant is automatically extended to all recipients of the covered
507 | work and works based on it.
508 |
509 | A patent license is "discriminatory" if it does not include within
510 | the scope of its coverage, prohibits the exercise of, or is
511 | conditioned on the non-exercise of one or more of the rights that are
512 | specifically granted under this License. You may not convey a covered
513 | work if you are a party to an arrangement with a third party that is
514 | in the business of distributing software, under which you make payment
515 | to the third party based on the extent of your activity of conveying
516 | the work, and under which the third party grants, to any of the
517 | parties who would receive the covered work from you, a discriminatory
518 | patent license (a) in connection with copies of the covered work
519 | conveyed by you (or copies made from those copies), or (b) primarily
520 | for and in connection with specific products or compilations that
521 | contain the covered work, unless you entered into that arrangement,
522 | or that patent license was granted, prior to 28 March 2007.
523 |
524 | Nothing in this License shall be construed as excluding or limiting
525 | any implied license or other defenses to infringement that may
526 | otherwise be available to you under applicable patent law.
527 |
528 | 12. No Surrender of Others' Freedom.
529 |
530 | If conditions are imposed on you (whether by court order, agreement or
531 | otherwise) that contradict the conditions of this License, they do not
532 | excuse you from the conditions of this License. If you cannot convey a
533 | covered work so as to satisfy simultaneously your obligations under this
534 | License and any other pertinent obligations, then as a consequence you may
535 | not convey it at all. For example, if you agree to terms that obligate you
536 | to collect a royalty for further conveying from those to whom you convey
537 | the Program, the only way you could satisfy both those terms and this
538 | License would be to refrain entirely from conveying the Program.
539 |
540 | 13. Remote Network Interaction; Use with the GNU General Public License.
541 |
542 | Notwithstanding any other provision of this License, if you modify the
543 | Program, your modified version must prominently offer all users
544 | interacting with it remotely through a computer network (if your version
545 | supports such interaction) an opportunity to receive the Corresponding
546 | Source of your version by providing access to the Corresponding Source
547 | from a network server at no charge, through some standard or customary
548 | means of facilitating copying of software. This Corresponding Source
549 | shall include the Corresponding Source for any work covered by version 3
550 | of the GNU General Public License that is incorporated pursuant to the
551 | following paragraph.
552 |
553 | Notwithstanding any other provision of this License, you have
554 | permission to link or combine any covered work with a work licensed
555 | under version 3 of the GNU General Public License into a single
556 | combined work, and to convey the resulting work. The terms of this
557 | License will continue to apply to the part which is the covered work,
558 | but the work with which it is combined will remain governed by version
559 | 3 of the GNU General Public License.
560 |
561 | 14. Revised Versions of this License.
562 |
563 | The Free Software Foundation may publish revised and/or new versions of
564 | the GNU Affero General Public License from time to time. Such new versions
565 | will be similar in spirit to the present version, but may differ in detail to
566 | address new problems or concerns.
567 |
568 | Each version is given a distinguishing version number. If the
569 | Program specifies that a certain numbered version of the GNU Affero General
570 | Public License "or any later version" applies to it, you have the
571 | option of following the terms and conditions either of that numbered
572 | version or of any later version published by the Free Software
573 | Foundation. If the Program does not specify a version number of the
574 | GNU Affero General Public License, you may choose any version ever published
575 | by the Free Software Foundation.
576 |
577 | If the Program specifies that a proxy can decide which future
578 | versions of the GNU Affero General Public License can be used, that proxy's
579 | public statement of acceptance of a version permanently authorizes you
580 | to choose that version for the Program.
581 |
582 | Later license versions may give you additional or different
583 | permissions. However, no additional obligations are imposed on any
584 | author or copyright holder as a result of your choosing to follow a
585 | later version.
586 |
587 | 15. Disclaimer of Warranty.
588 |
589 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
590 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
591 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
592 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
593 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
594 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
595 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
596 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
597 |
598 | 16. Limitation of Liability.
599 |
600 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
601 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
602 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
603 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
604 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
605 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
606 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
607 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
608 | SUCH DAMAGES.
609 |
610 | 17. Interpretation of Sections 15 and 16.
611 |
612 | If the disclaimer of warranty and limitation of liability provided
613 | above cannot be given local legal effect according to their terms,
614 | reviewing courts shall apply local law that most closely approximates
615 | an absolute waiver of all civil liability in connection with the
616 | Program, unless a warranty or assumption of liability accompanies a
617 | copy of the Program in return for a fee.
618 |
619 | END OF TERMS AND CONDITIONS
620 |
621 | How to Apply These Terms to Your New Programs
622 |
623 | If you develop a new program, and you want it to be of the greatest
624 | possible use to the public, the best way to achieve this is to make it
625 | free software which everyone can redistribute and change under these terms.
626 |
627 | To do so, attach the following notices to the program. It is safest
628 | to attach them to the start of each source file to most effectively
629 | state the exclusion of warranty; and each file should have at least
630 | the "copyright" line and a pointer to where the full notice is found.
631 |
632 |
633 | Copyright (C)
634 |
635 | This program is free software: you can redistribute it and/or modify
636 | it under the terms of the GNU Affero General Public License as published
637 | by the Free Software Foundation, either version 3 of the License, or
638 | (at your option) any later version.
639 |
640 | This program is distributed in the hope that it will be useful,
641 | but WITHOUT ANY WARRANTY; without even the implied warranty of
642 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
643 | GNU Affero General Public License for more details.
644 |
645 | You should have received a copy of the GNU Affero General Public License
646 | along with this program. If not, see .
647 |
648 | Also add information on how to contact you by electronic and paper mail.
649 |
650 | If your software can interact with users remotely through a computer
651 | network, you should also make sure that it provides a way for users to
652 | get its source. For example, if your program is a web application, its
653 | interface could display a "Source" link that leads users to an archive
654 | of the code. There are many ways you could offer source, and different
655 | solutions will be better for different programs; see section 13 for the
656 | specific requirements.
657 |
658 | You should also get your employer (if you work as a programmer) or school,
659 | if any, to sign a "copyright disclaimer" for the program, if necessary.
660 | For more information on this, and how to apply and follow the GNU AGPL, see
661 | .
662 |
--------------------------------------------------------------------------------
/MsgObj.py:
--------------------------------------------------------------------------------
1 | import json
2 | from graia.application import GroupMessage
3 | from graia.application.message.elements.internal import *
4 |
5 | '''封装好的message对象'''
6 |
7 |
8 | class Msg:
9 | __slots__ = ['msg_chain', 'user_id', 'at', 'txt', 'sendChain', 'img_url', 'msg_list']
10 |
11 | def __del__(self):
12 | del self
13 |
14 | def __init__(self, *msg: GroupMessage):
15 | self.msg_list = list()
16 | if len(msg) <= 0:
17 | self.msg_chain = \
18 | self.user_id = \
19 | self.img_url = \
20 | self.at = \
21 | self.txt = \
22 | self.sendChain = None
23 | else:
24 | msg = msg[0]
25 | self.msg_chain = msg.messageChain
26 | self.user_id = msg.sender.id
27 | self.img_url = self.msg_chain.get(Image) if self.msg_chain.has(Image) else None
28 | # 提取img对象中的url组成list
29 | if self.img_url is not None:
30 | self.img_url = [urls.url for urls in self.img_url]
31 | self.at = self.msg_chain.get(At) if self.msg_chain.has(At) else None
32 | # 提取At对象中的用户ID,组成list
33 | if self.at is not None:
34 | self.at = [ats.target for ats in self.at]
35 | self.txt = ''
36 | if self.msg_chain.has(Plain):
37 | self.txt = [i.text for i in self.msg_chain.get(Plain)]
38 | txt: str = ''
39 | for i in self.txt:
40 | txt += i
41 | self.txt = txt
42 | else:
43 | self.txt = None
44 | self.init_msg_chain()
45 |
46 | def init_msg_chain(self):
47 | if self.img_url is not None:
48 | [self.msg_list.append(Image.fromNetworkAddress(i)) for i in self.img_url]
49 | if self.at is not None:
50 | [self.msg_list.append(At(i)) for i in self.at]
51 | if self.txt is not None:
52 | self.msg_list.append(Plain(self.txt))
53 | if self.msg_chain is not None:
54 | self.sendChain = self.msg_chain.create(self.msg_list)
55 |
56 | def getMsgDict(self) -> dict: # 获取msg的dict对象
57 | return {
58 | 'user_id': self.user_id,
59 | 'img_url': self.img_url,
60 | 'at': self.at,
61 | 'msg_txt': self.txt
62 | }
63 |
64 | def set_dict_from_json(self, jsons: str): # 根据json字符串初始化对象
65 | self.set_dict(json.loads(jsons))
66 |
67 | def set_dict(self, set_dict: dict): # 传入dict来初始化对象
68 | self.user_id = set_dict['user_id'] if 'user_id' in set_dict.keys() else None
69 | self.at = set_dict['at'] if 'at' in set_dict.keys() else None
70 | self.txt = set_dict['msg_txt'] if 'msg_txt' in set_dict.keys() else None
71 | self.img_url = set_dict['img_url'] if 'img_url' in set_dict.keys() else None
72 | self.init_msg_chain()
73 |
74 | def get_msg_list(self):
75 | return self.msg_list
76 |
77 | def get_msg_graia(self, MC: MessageChain) -> MessageChain: # 获取该消息的消息链(懒加载)
78 | if self.sendChain is None:
79 | self.sendChain = MC.create(self.msg_list)
80 | return self.sendChain
81 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # FAQ-In-QQ-Python(暂时停止更新)
2 | 基于[Graia Framework](https://github.com/GraiaProject/Application)框架开发的Mirai机器人插件,目前集成了迎新/问答/百度/萌娘/说骚话功能
3 | 如果对性能有高要求或是Kotlin玩家请移步[Kotlin版本](https://github.com/farewell12345/FAQ-Bot-QQ),
4 | ## 使用方法:
5 |
6 | 1.下载[MiraiOK](https://github.com/LXY1226/MiraiOK)并参阅[文档](https://graiaproject.github.io/Application/)进行配置
7 |
8 | 2.创建config.py文件,分别填入以下配置:
9 | ```python
10 | BOTQQ=123456
11 |
12 | #Bot的QQ,一定要写,否则会报找不到无头客户端的error
13 |
14 | API_ROOT='http://localhost:80'
15 |
16 | #本地地址
17 |
18 | AuthKey="graia-mirai-api-http-authkey"
19 | #你的软件key值
20 | ```
21 | config中的端口配置和key配置要与MiraiOK/plugin/MiraiAPIHTTP下的setting.yml中的端口配置相同
22 |
23 | 3.启动MiraiOK并登录一个账号
24 |
25 | 4.启动bot.py文件
26 |
27 | ## 指令菜单
28 | ```
29 | 1./start 开启百度和骚话功能
30 | 2./shutdown 关闭百度和骚话功能
31 | 3. 添加问题 问题名
32 | 4. 修改问题 问题名
33 | 5. 删除问题 问题名
34 | 6. 百度 词条
35 | 7. 萌娘 词条
36 | 8. .来点好听的
37 | ```
38 |
39 | ## 使用场景:
40 |
41 | 各大迎新群或工作室群
42 |
43 | ## 相关项目链接:
44 | [Mirai](https://github.com/mamoe/mirai)
45 |
46 | [MiraiOK](https://github.com/LXY1226/MiraiOK)
47 |
48 | [Mirai-api-http](https://github.com/project-mirai/mirai-api-http)
49 |
--------------------------------------------------------------------------------
/bot.py:
--------------------------------------------------------------------------------
1 | import functools
2 | import gc
3 | import os
4 | import signal
5 | import subprocess
6 | import sys
7 | import threading
8 | import psutil
9 | import time
10 | from apscheduler.schedulers.blocking import BlockingScheduler
11 | from graia.application import FriendMessage, Friend
12 | from graia.application.event.mirai import *
13 | from graia.broadcast.builtin.decoraters import Depend
14 | from plugin import *
15 | from MsgObj import Msg
16 | from init_bot import *
17 | from command_session import *
18 | import sched
19 |
20 | '''
21 | 各文件说明:
22 | init_bot.py 初始化bot对象和一些需要用到的list或者dict
23 | bot.py 运行的main文件,包括消息指令入口
24 | MsgObj.py 独立封装的message消息类,便于对消息数据进行保存和调用
25 | pulgin.py bot所需要到的一些函数的封装
26 | config.py bot运行所需要的配置,端口号,bot的QQ号等,配置参见Graia文档
27 | command_session.py 命令解析器相关函数
28 | '''
29 |
30 | commands = { # 命令解析器
31 | 'startBaidu': start_Baidu,
32 | 'shutdownBaidu': shutdown_Baidu,
33 | 'startQA': start_all,
34 | 'shutdownQA': shutdown_all,
35 | 'manage': open_manager,
36 | 'closeManage': close_manager,
37 | 'welcome': open_welcome,
38 | 'closeWelcome': close_welcome
39 | }
40 |
41 | '''
42 | 监听新人入群并欢迎
43 | '''
44 |
45 |
46 | @bcc.receiver("MemberJoinEvent")
47 | async def MemberJoin(event: MemberJoinEvent):
48 | group = event.member.group
49 | if group.id not in WelComeGroup:
50 | return
51 | if group.id in WelcomeScence:
52 | talk = WelcomeScence[group.id]
53 | else:
54 | talk = "欢迎小可爱来到本群"
55 | await app.sendGroupMessage(group, MessageChain.create([
56 | Plain(talk),
57 | At(event.member.id)
58 | ]))
59 |
60 |
61 | '''
62 | 修改群迎新词
63 | '''
64 |
65 |
66 | @bcc.receiver('GroupMessage', headless_decoraters=[
67 | Depend(judge_depend_target)
68 | ])
69 | async def changeWelcome(message: GroupMessage, group: Group):
70 | if not parser(message, "修改迎新词 "):
71 | return
72 | if not message.messageChain.has(Plain):
73 | return
74 | plain = message.messageChain.get(Plain)
75 | txt = plain[0].text.replace("修改迎新词 ", "")
76 | if len(txt) > 0:
77 | WelcomeScence[group.id] = txt
78 | status = "修改成功"
79 | else:
80 | status = "修改失败,不合法!"
81 | await app.sendGroupMessage(group, MessageChain.create([Plain(status)]))
82 |
83 |
84 | '''
85 | 问答模块,集合了
86 | 添加问题
87 | 修改问题
88 | 会话管理
89 | 删除问题
90 | 问答功能
91 | (注:这部分代码十分恶心,请谨慎阅读,之后会重构)
92 | '''
93 |
94 |
95 | @bcc.receiver("GroupMessage")
96 | async def close_in_group(commandApp: GraiaMiraiApplication, message: GroupMessage, group: Group):
97 | if parser(message, ".command "):
98 | if not is_manager(message):
99 | return
100 | command = message.messageChain.get(Plain)[0].text.replace('.command ', '')
101 | send_msg = f"未知的指令{command},目前可执行指令:\n"
102 | if commands.get(command):
103 | flag: bool = commands[command](message, group)
104 | if flag is None:
105 | return
106 | if flag:
107 | send_msg = f"已执行命令{command}"
108 | else:
109 | send_msg = f"此群尚不具备{command}指令的条件!"
110 | else:
111 | for i in commands.keys():
112 | send_msg += f"{i}"
113 | await commandApp.sendGroupMessage(group, message.messageChain.create(
114 | [Plain(send_msg)]
115 | ))
116 |
117 |
118 | async def indexes(message: GroupMessage, group: Group):
119 | id : str = message.messageChain.get(Plain)[0].text.strip().replace('#', '')
120 | if id.isdigit():
121 | temp_list: list = quick_find_question_list[group.id]
122 | question: str = temp_list[int(id)]
123 | answer: Msg = search(question, group)
124 | send_msg = answer.get_msg_graia(message.messageChain)
125 | await app.sendGroupMessage(group, send_msg)
126 |
127 |
128 | async def FQA(message: GroupMessage, group: Group) -> bool:
129 | if not message.messageChain.has(Plain):
130 | return False
131 | msg = Msg(message)
132 | msg_chain = message.messageChain
133 | # 首先对消息进行问答解析
134 | Question = msg.txt.strip()
135 | if Question == '列表':
136 | await app.sendGroupMessage(group, FQA_list(message, group))
137 | del msg
138 | return True
139 | at = msg_chain.get(At)[0].target if msg_chain.has(At) else 0
140 | tempQ = search(Question, group)
141 | if tempQ is not None:
142 | send_msg = tempQ.get_msg_graia(msg_chain)
143 | else:
144 | if at == BOTQQ:
145 | send_msg = msg_chain.create([
146 | Plain("没有找到这个问题,请等待学长学姐来回答或回复“列表”查看已有问题")
147 | ])
148 | else:
149 | send_msg = None
150 | if send_msg is not None:
151 | await app.sendGroupMessage(group, send_msg)
152 | del msg
153 | return True
154 | del msg
155 | return False
156 |
157 |
158 | @bcc.receiver("GroupMessage")
159 | async def BaiDu(message: GroupMessage, group: Group):
160 | if only_group_in_list(group, shutdown_all_group) \
161 | or not only_group_in_list(group, start_baiDu_group): return
162 | if parser(message, "百度 "):
163 | entry = message.messageChain.get(Plain)[0].text.strip().replace("百度 ", "")
164 | await app.sendGroupMessage(group=group, message=message.messageChain.create([
165 | Plain(getBaiduKnowledge(entry))
166 | ]))
167 | elif parser(message, "萌娘 "):
168 | entry = message.messageChain.get(Plain)[0].text.strip().replace("萌娘 ", "")
169 | await app.sendGroupMessage(group=group, message=message.messageChain.create([
170 | Plain(getACGKnowledge(entry))
171 | ]))
172 | elif parser(message, '。来点好听的'):
173 | say_loving(message, group)
174 |
175 |
176 | @bcc.receiver("GroupMessage")
177 | async def group_message_handler(message: GroupMessage, group: Group):
178 | if message.sender.id in FuckUser:
179 | await app.sendGroupMessage(group, message.messageChain.create(
180 | [
181 | Plain("此用户信用度极低,请勿相信其发布的任何小程序或广告链接,谨防上当受骗!"),
182 | At(message.sender.id)
183 | ]
184 | ))
185 | return
186 | if group_is_in_list(message, group, shutdown_all_group):
187 | return
188 | if parser(message, "百度 ") \
189 | or parser(message, "萌娘 "):
190 | return
191 | msg = Msg(message)
192 | question = message.messageChain.get(Plain)[0].text if message.messageChain.has(Plain) else None
193 | has_session = temp_talk.get(msg.user_id)
194 | if has_session is not None:
195 | await session_manager(message,group)
196 | return
197 | if await FQA(message, group):
198 | return
199 |
200 | if parser(message, '#'):
201 | await indexes(message, group)
202 | return
203 | if group.id in mast_manager_group:
204 | if not is_manager(message):
205 | return
206 | if parser(message, "添加问题 "):
207 | # 创建添加问题的新会话
208 | question = question.replace("添加问题 ", "").strip()
209 | if has_session is None:
210 | add_temp_talk(msg.user_id, 'Add', True, question)
211 | sendMsg = await AddQA(message, group)
212 | if sendMsg is not None:
213 | await app.sendGroupMessage(group, sendMsg)
214 | del msg
215 | return
216 |
217 | if parser(message, "修改问题 "):
218 | # 创建修改问题的新会话
219 | question = question.replace("修改问题", "").strip()
220 | question = question if not re.search("#",question) \
221 | else quick_find_question_list[group.id][int(question.replace('#',''))]
222 | if has_session is None:
223 | add_temp_talk(msg.user_id, 'Change', True, question)
224 | sendMsg = await change(group=group, GM=message)
225 | if sendMsg is not None:
226 | await app.sendGroupMessage(group, sendMsg)
227 | del msg
228 | return
229 |
230 | if parser(message, "删除问题 "):
231 | # 删除问题
232 | question = question.replace("删除问题", "").strip()
233 | question = question if not re.search("#", question) \
234 | else quick_find_question_list[group.id][int(question.replace('#', ''))]
235 | isdeleteOK: str = f"删除问题{question}成功" if deleteQA(question, group) else "不存在这个问题"
236 | await app.sendGroupMessage(group, message.messageChain.create([
237 | Plain(isdeleteOK)
238 | ]))
239 | await saveQA()
240 | del msg
241 | gc.collect()
242 | return
243 |
244 | if parser(message, ".Fuck") and message.messageChain.has(At) and is_manager(message):
245 | id = message.messageChain.get(At)[0].target
246 | if id not in FuckUser:
247 | FuckUser.append(id)
248 | await app.sendGroupMessage(group, message.messageChain.create([
249 | Plain("已经将此人拉入危险用户名单")
250 | ]))
251 | else:
252 | await app.sendGroupMessage(group, message.messageChain.create([
253 | Plain("此人已被认定为危险用户")
254 | ]))
255 | return
256 |
257 |
258 | def apscheduler(*args, **kwargs):
259 | def decorator(func):
260 | @functools.wraps(func)
261 | def wrapper():
262 | scheduler = BlockingScheduler()
263 | scheduler.add_job(func, args[0],
264 | hours=kwargs['hour'])
265 | scheduler.start()
266 | return func(args=args, kwargs=kwargs)
267 |
268 | return wrapper
269 |
270 | return decorator
271 |
272 |
273 | @apscheduler('interval', hour=6)
274 | def test():
275 | print("程序重新开始")
276 | python = sys.executable
277 | os.execl(python, python, *sys.argv)
278 |
279 |
280 | @bcc.receiver("FriendMessage")
281 | async def restart(message: FriendMessage, friend: Friend):
282 | if friend.id in Manager and message.messageChain.asDisplay().startswith("重启"):
283 | test()
284 |
285 |
286 | if __name__ == '__main__':
287 | # 初始化GroupQA
288 | # loop.run_until_complete(Compatible_old_index())
289 | nest_asyncio.apply()
290 | threading.Thread(target=test, args=()).start()
291 | loop.run_until_complete(ReadQA())
292 | loop.run_until_complete(read_love())
293 | app.launch_blocking()
294 |
--------------------------------------------------------------------------------
/command_session.py:
--------------------------------------------------------------------------------
1 | from graia.application import Group, GroupMessage
2 | from init_bot import *
3 |
4 |
5 | def is_manager(message: GroupMessage) -> bool:
6 | test = message.sender.permission
7 | if message.sender.permission.value == "ADMINISTRATOR" or message.sender.permission.value == "OWNER" or message.sender.id in Manager:
8 | return True
9 | return False
10 |
11 |
12 | def open_welcome(message: GroupMessage, group: Group) -> bool:
13 | if not group_is_in_list(message, group, WelComeGroup):
14 | WelComeGroup.append(group.id)
15 | return True
16 | return False
17 |
18 |
19 | def close_welcome(message: GroupMessage, group: Group) -> bool:
20 | if group_is_in_list(message, group, WelComeGroup):
21 | WelComeGroup.remove(group.id)
22 | return True
23 | return False
24 |
25 |
26 | def only_group_in_list(group: Group, start_group: list) -> bool:
27 | if group.id in start_group:
28 | return True
29 | return False
30 |
31 |
32 | def group_is_in_list(message: GroupMessage, group: Group, start_group: list) -> bool:
33 | if is_manager(message) and group.id in start_group:
34 | return True
35 | return False
36 |
37 |
38 | def shutdown_Baidu(message: GroupMessage, group: Group) -> bool:
39 | if group_is_in_list(message, group, start_baiDu_group):
40 | start_baiDu_group.remove(group.id)
41 | return True
42 | return False
43 |
44 |
45 | def open_manager(message: GroupMessage, group: Group) -> bool:
46 | if not group_is_in_list(message, group, mast_manager_group):
47 | mast_manager_group.append(group.id)
48 | return True
49 | return False
50 |
51 |
52 | def close_manager(message: GroupMessage, group: Group) -> bool:
53 | if group_is_in_list(message, group, mast_manager_group):
54 | mast_manager_group.remove(group.id)
55 | return True
56 | return False
57 |
58 |
59 | def shutdown_all(message: GroupMessage, group: Group) -> bool:
60 | if not group_is_in_list(message, group, shutdown_all_group):
61 | shutdown_all_group.append(group.id)
62 | return True
63 | return False
64 |
65 |
66 | def start_Baidu(message: GroupMessage, group: Group) -> bool:
67 | if not group_is_in_list(message, group, start_baiDu_group):
68 | start_baiDu_group.append(group.id)
69 | return True
70 | return False
71 |
72 |
73 | def start_all(message: GroupMessage, group: Group) -> bool:
74 | if group_is_in_list(message, group, shutdown_all_group):
75 | shutdown_all_group.remove(group.id)
76 | return True
77 | return False
78 |
--------------------------------------------------------------------------------
/init_bot.py:
--------------------------------------------------------------------------------
1 | '''下面是bot的初始化'''
2 | import asyncio
3 | import json
4 | from graia.application import GraiaMiraiApplication, Session
5 | from graia.broadcast import Broadcast
6 |
7 | from MsgObj import Msg
8 | from config import *
9 |
10 | GroupQA = {}
11 | LoveTalkList = []
12 | temp_talk = dict() # 简易的会话管理器
13 | WelcomeScence = {}
14 | BlackUser = []
15 | # 黑名单
16 | Manager = []
17 | # 超级管理员
18 | FuckUser = []
19 | # 诈骗黑名单
20 | start_baiDu_group = []
21 | mast_manager_group = []
22 | quick_find_question_list = {}
23 | shutdown_all_group = []
24 | loop = asyncio.get_event_loop() # 获取bot运行的协程
25 |
26 | bcc = Broadcast(loop=loop)
27 |
28 | app = GraiaMiraiApplication(
29 | broadcast=bcc,
30 | connect_info=Session(
31 | host=API_ROOT, # httpapi 服务运行的地址
32 | authKey=AuthKey, # authKey
33 | account=BOTQQ, # 机器人的 qq 号
34 | websocket=True # Graia 已经可以根据所配置的消息接收的方式来保证消息接收部分的正常运作.
35 | )
36 | )
37 |
38 |
39 | async def ReadQA():
40 | try:
41 | with open('QAindex.json', 'r') as f:
42 | tempDict = json.loads(f.read())
43 | for i in tempDict.keys():
44 | GroupQA[int(i)] = tempDict[i]
45 | for key in GroupQA[int(i)].keys():
46 | t = tempDict[i][key]
47 | GroupQA[int(i)][key] = Msg()
48 | GroupQA[int(i)][key].set_dict_from_json(t)
49 | quick_find_question_list[int(i)] = sorted(GroupQA[int(i)].keys(), key=lambda i: len(i), reverse=False)
50 | f.close()
51 | print("读取结束")
52 | except:
53 | with open('QAIndex.json', 'w+') as f:
54 | f.close()
55 |
56 |
57 | async def saveQA(): # 对已有问答数据进行保存
58 | AllData = dict()
59 | with open('QAindex.json', 'w+') as f:
60 | for key in GroupQA:
61 | t_dict = GroupQA[key]
62 | indexDict = dict()
63 | for i in t_dict:
64 | data = json.dumps(t_dict[i].getMsgDict())
65 | indexDict[i] = data
66 | AllData[key] = indexDict.copy()
67 | indexDict.clear()
68 | f.write(json.dumps(AllData))
69 | f.close()
70 | print("已保存")
71 |
72 |
73 | async def Compatible_old_index(): # 对旧有数据的转化
74 | with open('QAindex.json', 'r') as f:
75 | tempDick = json.loads(f.read())
76 | for i in tempDick.keys():
77 | tempDick[i] = json.loads(tempDick[i])
78 | GroupQA[int(i)] = tempDick[i].copy()
79 | for key in tempDick[i]:
80 | txt = tempDick[i][key]
81 | GroupQA[int(i)][key] = Msg()
82 | TransformDict = {
83 | 'user_id': None,
84 | 'at': None,
85 | 'msg_txt': txt,
86 | 'img_url': None
87 | }
88 | GroupQA[int(i)][key].set_dict(TransformDict)
89 |
90 | f.close()
91 | await saveQA()
92 |
--------------------------------------------------------------------------------
/plugin.py:
--------------------------------------------------------------------------------
1 | import json
2 | import random
3 | import re
4 | import graia
5 | from urllib.parse import quote
6 | import requests
7 | from bs4 import BeautifulSoup
8 | from graia.broadcast import ExecutionStop
9 | from graia.application import GroupMessage
10 | from graia.application.message.elements.internal import *
11 | from graia.application.group import Group
12 | from MsgObj import Msg
13 | from init_bot import *
14 | import nest_asyncio
15 | from command_session import *
16 |
17 | headers = {
18 | 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) '
19 | 'Chrome/81.0.4044.138 Safari/537.36 Edg/81.0.416.77 '
20 | } # 请求header
21 | BaiDuWiKi = 'https://baike.baidu.com/item/'
22 |
23 |
24 | def say_loving(message: GroupMessage, group: Group):
25 | if group.id in start_baiDu_group:
26 | loop.run_until_complete(
27 | app.sendGroupMessage(group, message.messageChain.create([
28 | Plain(get_love()),
29 | At(message.sender.id)
30 | ]))
31 | )
32 | return None
33 |
34 |
35 | def get_love() -> str:
36 | return LoveTalkList[random.randint(0, len(LoveTalkList) - 1)]
37 |
38 |
39 | async def read_love():
40 | try:
41 | f = open('love.txt', 'r')
42 | a = f.readline()
43 | while a:
44 | if not a in LoveTalkList:
45 | LoveTalkList.append(a)
46 | a = f.readline()
47 | except:
48 | pass
49 | # f = open('love.txt', 'w+')
50 | # f.close()
51 |
52 |
53 | def getACGKnowledge(txt: str) -> str:
54 | Entry = txt
55 | txt = quote(txt)
56 | moeGirlWiki = f'https://zh.moegirl.org.cn/{txt}'
57 | data = requests.get(moeGirlWiki, headers=headers).text
58 | content = BeautifulSoup(data, 'html.parser')
59 | [s.extract() for s in content('script')]
60 | [s.extract() for s in content('style')]
61 | try:
62 | try:
63 | datas = content.find_all(class_='mw-parser-output')[1]
64 | except:
65 | datas = content.find_all(class_='mw-parser-output')[0]
66 | try:
67 | bs = re.sub('\n+', '\n', datas.text)
68 | bs = re.sub(' +', ' ', bs)
69 | bs = ''.join([s for s in bs.splitlines(True) if s.strip()])
70 | bs = bs. \
71 | replace("萌娘百科欢迎您参与完善本条目☆欢迎有兴趣编辑讨论的朋友加入萌百Bilibili UP主专题编辑团队:338917445 欢迎正在阅读这个条目的您协助.", '') \
72 | .replace("编辑前请阅读Wiki入门或条目编辑规范,并查找相关资料。萌娘百科祝您在本站度过愉快的时光。", '')
73 | try:
74 | firstIntroduce: str = re.findall(f'{Entry}([\s\S]*?)目录', bs)[0]
75 | except:
76 | firstIntroduce = ''
77 | if len(firstIntroduce) < 200:
78 | introduce = datas.find_all(class_='toclevel-1 tocsection-1')[0].find_all(class_='toctext')[0].get_text()
79 | end = datas.find_all(class_='toclevel-1 tocsection-2')[0].find_all(class_='toctext')[0].text
80 | firstIntroduce += re.findall(f"{introduce}([\s\S]*?){end}", bs)[1]
81 | return firstIntroduce + moeGirlWiki
82 | except:
83 | return datas.find_all('p')[0].get_text() + '\n' + moeGirlWiki
84 | except:
85 | return "很抱歉没有找到相关信息或找到多个词条" + '\n' + moeGirlWiki
86 |
87 |
88 | def getBaiduKnowledge(text: str) -> str:
89 | txt = quote(text)
90 | url = BaiDuWiKi + txt
91 | try:
92 | data = requests.get(url, headers=headers).text
93 | bs = BeautifulSoup(data, 'html.parser').find_all(class_='para')[0].get_text() + url
94 | return bs
95 | except:
96 | return "很抱歉没有找到相关结果"
97 |
98 |
99 | def add_temp_talk(id: int, type: str, isFirstRun: bool, Question: str):
100 | temp_talk[id] = {
101 | 'type': type,
102 | 'isFirstRun': isFirstRun,
103 | 'Q': Question
104 | }
105 |
106 |
107 | '''进行封装的命令解析器'''
108 |
109 |
110 | async def session_manager(message: GroupMessage, group: Group):
111 | if temp_talk.get(message.sender.id):
112 | # 查看发起会话的用户是否有未结束的会话
113 | if temp_talk[message.sender.id]['isFirstRun']:
114 | temp_talk[message.sender.id]['isFirstRun'] = False
115 | type = temp_talk[message.sender.id]['type']
116 | sendMsg = None
117 | if type == 'Add':
118 | sendMsg = await AddQA(message, group)
119 | elif type == 'Change':
120 | sendMsg = await change(group, message)
121 | # 会话结束,将会话释放掉
122 | temp_talk.pop(message.sender.id)
123 | if sendMsg is not None:
124 | await app.sendGroupMessage(group, sendMsg)
125 |
126 |
127 | def list_refresh(group_id: int):
128 | quick_find_question_list[group_id] = sorted(GroupQA[group_id].keys(), key=lambda i: len(i), reverse=False)
129 |
130 |
131 | '''获取问题列表'''
132 |
133 |
134 | def FQA_list(message: GroupMessage, group: Group):
135 | AllQuestionStr = ''
136 | if group.id in GroupQA and len(GroupQA[group.id].keys()) >= 1:
137 | keyList = quick_find_question_list[group.id] if group.id in quick_find_question_list else ['']
138 | num = 0
139 | for i in keyList:
140 | AllQuestionStr += f"#{num}.{i}\n"
141 | num += 1
142 | AllQuestionStr += "使用快速索引:#+问题序号"
143 | send_txt = AllQuestionStr
144 | else:
145 | send_txt = "本群暂时没有问题哦"
146 | send_msg = message.messageChain.create(
147 | [Plain(send_txt)]
148 | )
149 | print(send_txt)
150 | return send_msg
151 |
152 |
153 | '''
154 | 判断消息链是否合法
155 | 命令解析器
156 | (目前有bug)
157 | 并不能很好地实现目的,因此在调用该解析器的函数中额外增加了判断语句
158 | '''
159 |
160 |
161 | def parser(message: GroupMessage, txt: str) -> bool:
162 | if message.messageChain.asDisplay().startswith(txt):
163 | return True
164 | return False
165 |
166 |
167 | def judge(message: MessageChain) -> bool:
168 | if message.has(Plain):
169 | if message.asSendable().asDisplay().startswith("修改迎新词"):
170 | return True
171 | return False
172 |
173 |
174 | def judge_depend_target(message: MessageChain):
175 | if not judge(message):
176 | raise ExecutionStop()
177 |
178 |
179 | # 删除问题
180 | def deleteQA(Q: str, group: Group) -> bool:
181 | if group.id in GroupQA:
182 | t_QA: dict = GroupQA[group.id]
183 | if Q in t_QA:
184 | t_QA.pop(Q)
185 | list_refresh(group.id)
186 | return True
187 | return False
188 |
189 |
190 |
191 |
192 | # 搜寻问题并返回msg对象
193 | def search(Q: str, group: Group) -> Msg:
194 | if group.id in GroupQA:
195 | t_QA: dict = GroupQA[group.id]
196 | if Q in t_QA:
197 | return t_QA[Q]
198 | return None
199 |
200 |
201 | # 对问题的回答进行修改
202 | def get_change(Q: str, group: GroupQA, GM: GroupMessage) -> bool:
203 | if group.id in GroupQA:
204 | t_QA: dict = GroupQA[group.id]
205 | if Q in t_QA:
206 | t_QA[Q] = Msg(GM)
207 | return True
208 | return False
209 |
210 |
211 | # 修改问题
212 | async def change(group: GroupQA, GM: GroupMessage) -> MessageChain:
213 | isFirstRun = temp_talk[GM.sender.id]['isFirstRun']
214 | Question = temp_talk[GM.sender.id]['Q']
215 | # 在会话管理查询该会话是否正在进行
216 | if isFirstRun: # 如果还没有进行
217 | if search(Question, group) is not None:
218 | reply = f"问题{Question}已找到,请问如何回答?"
219 | else:
220 | reply = f"问题{Question}不存在!"
221 | temp_talk.pop(GM.sender.id)
222 | else: # 如果已经进行
223 | if get_change(Question, group, GM):
224 | reply = "修改回答成功!"
225 | await saveQA()
226 | else:
227 | reply = None
228 | if reply is not None:
229 | already = GM.messageChain.create([
230 | Plain(reply)
231 | ])
232 | return already
233 |
234 |
235 | async def AddQA(groupMsg: GroupMessage, group: Group) -> MessageChain:
236 | global app
237 | isFirstRun = temp_talk[groupMsg.sender.id]['isFirstRun']
238 | Question = temp_talk[groupMsg.sender.id]['Q']
239 | sendMsg = None
240 | session = Msg(groupMsg)
241 | if isFirstRun:
242 | if session.user_id in BlackUser:
243 | sendMsg = session.msg_chain.create([
244 | At(session.user_id),
245 | Plain("你已经被拉入小黑屋")
246 | ])
247 | temp_talk.pop(session.user_id)
248 | await app.sendGroupMessage(group, sendMsg)
249 | return None
250 | if not GroupQA.get(group.id):
251 | GroupQA[group.id] = dict()
252 | t_QA: dict = GroupQA[group.id]
253 | if Question is not None:
254 | if Question in t_QA.keys():
255 | reply = "问题已存在,当前回答为:"
256 | sendMsg = groupMsg.messageChain.create([
257 | Plain(reply)
258 | ]).plusWith(t_QA[Question].get_msg_list())
259 | temp_talk.pop(session.user_id)
260 | else:
261 | sendMsg = session.msg_chain.create([
262 | Plain("问题已被录入,请问如何回答?")
263 | ])
264 | else:
265 | t_QA = GroupQA[group.id]
266 | answer = Msg(groupMsg)
267 | t_QA[Question] = answer
268 | sendMsg = session.msg_chain.create([
269 | Plain("录入成功")
270 | ])
271 | list_refresh(group.id)
272 | await saveQA()
273 | del session
274 | return sendMsg
275 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | aiohttp==3.7.4
2 | async-timeout==3.0.1
3 | attrs==20.1.0
4 | beautifulsoup4==4.9.1
5 | bs4==0.0.1
6 | certifi==2020.6.20
7 | chardet==3.0.4
8 | graia-application-mirai==0.1.12
9 | graia-broadcast==0.1.3
10 | idna==2.10
11 | iterwrapper==0.1.4
12 | multidict==4.7.6
13 | pydantic==1.6.2
14 | regex==2020.7.14
15 | requests==2.24.0
16 | soupsieve==2.0.1
17 | typing-extensions==3.7.4.2
18 | urllib3==1.26.5
19 | yarl==1.5.1
20 |
--------------------------------------------------------------------------------