Compare commits
63 Commits
QQGuildBot
...
Backup
Author | SHA1 | Date | |
---|---|---|---|
f90bc5d658 | |||
8b7aff98cd | |||
7a508c505b | |||
b919491339 | |||
20e14ec7b3 | |||
3be56e5e2c | |||
db5d4d46f6 | |||
e439cd9f58 | |||
7e63649a55 | |||
1367222266 | |||
fd0a04e052 | |||
9d1716b82d | |||
033eed619d | |||
d25b05e802 | |||
afb9a61be2 | |||
e3b8e9b8ca | |||
287e861d06 | |||
41bcb89a38 | |||
4edf1ccb49 | |||
4bb0faa49e | |||
4664fa805d | |||
4c9f0d9f3f | |||
d614b0bf8b | |||
c365d7bce9 | |||
919c55adb1 | |||
2c21f035d4 | |||
d10d9dd982 | |||
21607fe2a7 | |||
49fdecfa25 | |||
5d11ec7998 | |||
47a9595785 | |||
5ca303c2f9 | |||
42bc1d68b9 | |||
fa143d4bf5 | |||
a4d948563e | |||
25bbede003 | |||
4d687770ef | |||
8cf1dd6b37 | |||
ec39704b72 | |||
e99928687c | |||
c7b2b14703 | |||
a4f8b3f12b | |||
a79c139077 | |||
365f5eb7e3 | |||
0b3595f9c3 | |||
899f0e7ce9 | |||
b7100af0f0 | |||
5ca4013639 | |||
83b548c2f2 | |||
5f3d37852a | |||
76b010a1bb | |||
02ee0427b8 | |||
41efadd0a3 | |||
b0392fc4c7 | |||
8a81f51679 | |||
e8f4b23741 | |||
f06a3baff9 | |||
eadd9656b3 | |||
12f7f2f77d | |||
089e69799f | |||
a95b27c181 | |||
3d8c4b8ba2 | |||
dc93f9e962 |
1
.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
/.idea/
|
674
LICENSE
Normal file
@ -0,0 +1,674 @@
|
||||
GNU GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
Preamble
|
||||
|
||||
The GNU General Public License is a free, copyleft license for
|
||||
software and other kinds of works.
|
||||
|
||||
The licenses for most software and other practical works are designed
|
||||
to take away your freedom to share and change the works. By contrast,
|
||||
the GNU General Public License is 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. We, the Free Software Foundation, use the
|
||||
GNU General Public License for most of our software; it applies also to
|
||||
any other work released this way by its authors. You can apply it to
|
||||
your programs, too.
|
||||
|
||||
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.
|
||||
|
||||
To protect your rights, we need to prevent others from denying you
|
||||
these rights or asking you to surrender the rights. Therefore, you have
|
||||
certain responsibilities if you distribute copies of the software, or if
|
||||
you modify it: responsibilities to respect the freedom of others.
|
||||
|
||||
For example, if you distribute copies of such a program, whether
|
||||
gratis or for a fee, you must pass on to the recipients the same
|
||||
freedoms that you received. You must make sure that they, too, receive
|
||||
or can get the source code. And you must show them these terms so they
|
||||
know their rights.
|
||||
|
||||
Developers that use the GNU GPL protect your rights with two steps:
|
||||
(1) assert copyright on the software, and (2) offer you this License
|
||||
giving you legal permission to copy, distribute and/or modify it.
|
||||
|
||||
For the developers' and authors' protection, the GPL clearly explains
|
||||
that there is no warranty for this free software. For both users' and
|
||||
authors' sake, the GPL requires that modified versions be marked as
|
||||
changed, so that their problems will not be attributed erroneously to
|
||||
authors of previous versions.
|
||||
|
||||
Some devices are designed to deny users access to install or run
|
||||
modified versions of the software inside them, although the manufacturer
|
||||
can do so. This is fundamentally incompatible with the aim of
|
||||
protecting users' freedom to change the software. The systematic
|
||||
pattern of such abuse occurs in the area of products for individuals to
|
||||
use, which is precisely where it is most unacceptable. Therefore, we
|
||||
have designed this version of the GPL to prohibit the practice for those
|
||||
products. If such problems arise substantially in other domains, we
|
||||
stand ready to extend this provision to those domains in future versions
|
||||
of the GPL, as needed to protect the freedom of users.
|
||||
|
||||
Finally, every program is threatened constantly by software patents.
|
||||
States should not allow patents to restrict development and use of
|
||||
software on general-purpose computers, but in those that do, we wish to
|
||||
avoid the special danger that patents applied to a free program could
|
||||
make it effectively proprietary. To prevent this, the GPL assures that
|
||||
patents cannot be used to render the program non-free.
|
||||
|
||||
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 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. Use with the GNU Affero General Public License.
|
||||
|
||||
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 Affero 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 special requirements of the GNU Affero General Public License,
|
||||
section 13, concerning interaction through a network will apply to the
|
||||
combination as such.
|
||||
|
||||
14. Revised Versions of this License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of
|
||||
the GNU 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 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 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 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.
|
||||
|
||||
<one line to give the program's name and a brief idea of what it does.>
|
||||
Copyright (C) <year> <name of author>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU 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 General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
Also add information on how to contact you by electronic and paper mail.
|
||||
|
||||
If the program does terminal interaction, make it output a short
|
||||
notice like this when it starts in an interactive mode:
|
||||
|
||||
<program> Copyright (C) <year> <name of author>
|
||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
||||
This is free software, and you are welcome to redistribute it
|
||||
under certain conditions; type `show c' for details.
|
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
||||
parts of the General Public License. Of course, your program's commands
|
||||
might be different; for a GUI interface, you would use an "about box".
|
||||
|
||||
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 GPL, see
|
||||
<https://www.gnu.org/licenses/>.
|
||||
|
||||
The GNU General Public License does not permit incorporating your program
|
||||
into proprietary programs. If your program is a subroutine library, you
|
||||
may consider it more useful to permit linking proprietary applications with
|
||||
the library. If this is what you want to do, use the GNU Lesser General
|
||||
Public License instead of this License. But first, please read
|
||||
<https://www.gnu.org/licenses/why-not-lgpl.html>.
|
335
README.md
@ -1,290 +1,83 @@
|
||||
# GenshinUID / 原神UID查询
|
||||
<p align="center">
|
||||
<a href="https://github.com/KimigaiiWuyi/GenshinUID/"><img src="https://s2.loli.net/2022/01/31/kwCIl3cF1Z2GxnR.png" width="256" height="256" alt="GenshinUID"></a>
|
||||
</p>
|
||||
<h1 align = "center">GenshinUID</h1>
|
||||
<h4 align = "center">♾️基于<a href="https://github.com/Ice-Cirno/HoshinoBot" target="_blank">HoshinoBot</a>/<a href="https://github.com/nonebot/nonebot2" target="_blank">NoneBot2</a>/<a href="https://bot.q.qq.com/wiki/#" target="_blank">QQ官方频道Bot</a>的原神多功能插件♾️</h4>
|
||||
<div align = "center">
|
||||
<a href="https://github.com/KimigaiiWuyi/GenshinUID/wiki" target="_blank">安装文档</a> ·
|
||||
<a href="https://github.com/KimigaiiWuyi/GenshinUID/wiki#%E4%B8%A8%E6%9F%A5%E8%AF%A2%E6%A8%A1%E5%9D%97%E6%8C%87%E4%BB%A4%E5%88%97%E8%A1%A8" target="_blank">指令列表</a> ·
|
||||
<a href="https://github.com/KimigaiiWuyi/GenshinUID/wiki#%E4%B8%A8%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98qa">常见问题</a>
|
||||
</div>
|
||||
<p align="center">
|
||||
<a><img src="https://s2.loli.net/2022/02/01/QlS4piWXw5rZO3D.png"></a>
|
||||
</p>
|
||||
|
||||
一个HoshinoBot插件,用于查询原神UID信息,用于查询树脂/探索派遣状态,推送树脂快满了,每日签到。
|
||||
|
||||
**一定要读更新记录和指令!!**
|
||||
## 丨我该如何安装该插件?
|
||||
|
||||
注意:本插件不包含本体,您应该配合[Mrs4s](https://github.com/Mrs4s) / [go-cqhttp](https://github.com/Mrs4s/go-cqhttp) 和 [HoshinoBot](https://github.com/Ice-Cirno/HoshinoBot) 使用,本插件的作用是利用米游社API查询指定原神UID信息(Cookies获取可前往[YuanShen_User_Info](https://github.com/Womsxd/YuanShen_User_Info)查看教程)
|
||||
+ 如果你使用的是[Go-cqhttp](https://github.com/Mrs4s/go-cqhttp) & [HoshinoBot](https://github.com/Ice-Cirno/HoshinoBot),**安装方法查看[此处](https://github.com/KimigaiiWuyi/GenshinUID/wiki#%E4%B8%A8%E5%AE%89%E8%A3%85hoshinobot-)**。
|
||||
+ 如果你使用的是[Go-cqhttp](https://github.com/Mrs4s/go-cqhttp) & [NoneBot2](https://github.com/nonebot/nonebot2),**安装方法查看[此处](https://github.com/KimigaiiWuyi/GenshinUID/wiki#%E4%B8%A8%E5%AE%89%E8%A3%85nonebot2)**。(**开发者正在使用**)
|
||||
|
||||
再次提醒:**Cookies是重要信息,请不要随意泄露!!!**
|
||||
+ 如果你想在QQ官方的频道Bot使用此插件,你需要**做好以下准备**:
|
||||
- 拥有QQ频道机器人的开发者账号(类型:私域)
|
||||
- 拥有已经备案好的服务器地址(视情况后期官方放开本地图片发送而定)
|
||||
- **腾讯频道Bot官方的文档**,查看[此处](https://bot.q.qq.com/wiki/#)
|
||||
- 安装方法:基于官方的[PythonSDK](https://github.com/tencent-connect/botpy),本插件的安装方法可自行摸索。
|
||||
|
||||
示例:
|
||||
## 丨我该如何获取Cookies?[#92](https://github.com/KimigaiiWuyi/GenshinUID/issues/92)([@RemKeeper](https://github.com/RemKeeper))
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
- [安装(HoshinoBot)](#安装(HoshinoBot))
|
||||
- [更新记录](#更新记录)
|
||||
- [指令](#指令)
|
||||
- [相关仓库](#相关仓库)
|
||||
- [其他](#其他)
|
||||
|
||||
## 安装(HoshinoBot)
|
||||
|
||||
基于[Mrs4s](https://github.com/Mrs4s) / [go-cqhttp](https://github.com/Mrs4s/go-cqhttp) 和 [HoshinoBot](https://github.com/Ice-Cirno/HoshinoBot) 的插件,请确保你知晓HoshinoBot的插件安装方法和go-cqhttp的使用方法。
|
||||
|
||||
1、在hoshino/modules目录下执行
|
||||
|
||||
```sh
|
||||
$ git clone https://github.com/KimigaiiWuyi/GenshinUID.git
|
||||
```
|
||||
var cookie=document.cookie;
|
||||
var Str_Num = cookie.indexOf('_MHYUUID=');
|
||||
cookie ='添加 '+cookie.substring(Str_Num);
|
||||
var ask=confirm('Cookie:'+cookie+'\n\n按确认,然后粘贴发送给机器人');
|
||||
if(ask==true)
|
||||
{copy(cookie);
|
||||
msg=cookie}
|
||||
else
|
||||
{msg='Cancel'}
|
||||
```
|
||||
|
||||
2、进入GenshinUID文件夹内,安装依赖库
|
||||
1. 复制上面全部代码,然后打开https://bbs.mihoyo.com/ys/
|
||||
2. 在页面上右键检查或者Ctrl+Shift+i
|
||||
3. 选择控制台(Console),粘贴,回车,在弹出的窗口点确认(点完自动复制)
|
||||
4. 然后在和机器人的私聊窗口,粘贴发送即可
|
||||
|
||||
**警告:Cookies属于个人隐私,其效用相当于账号密码,请勿随意公开!**
|
||||
|
||||
## 丨获取米游社Stoken([AutoMihoyoBBS](https://github.com/Womsxd/AutoMihoyoBBS#%E8%8E%B7%E5%8F%96%E7%B1%B3%E6%B8%B8%E7%A4%BECookie))
|
||||
**前提**:已经添加过米游社Cookies,并且已经绑定过uid(仅用于米游社币的获取)
|
||||
```sh
|
||||
$ pip3 install -r requirements.txt
|
||||
var cookie=document.cookie;
|
||||
var ask=confirm('Cookie:'+cookie+'\n\nDo you want to copy the cookie to the clipboard?');
|
||||
if(ask==true){copy("添加 stoken" + cookie);msg=cookie}else{msg='Cancel'}
|
||||
```
|
||||
|
||||
3、在hoshino/config的`__bot__.py`文件中,添加GenshinUID
|
||||
1. 复制上面全部代码,然后打开http://user.mihoyo.com/
|
||||
2. 在页面上右键检查或者Ctrl+Shift+i
|
||||
3. 选择控制台(Console),粘贴,回车,在弹出的窗口点确认(点完自动复制)
|
||||
4. 然后在和机器人的私聊窗口,粘贴发送即可
|
||||
|
||||
4、启动HoshinoBot后,私聊机器人,发送
|
||||
**警告:Cookies属于个人隐私,其效用相当于账号密码,请勿随意公开!**
|
||||
|
||||
```sh
|
||||
添加 cookies
|
||||
```
|
||||
|
||||
注意事项:可以添加多条,但一次只能添加一条,添加两个字的之后必须带有空格,cookies填入你自己的,**并且不要泄露给任何人**,~~如果添加了错误的cookies,会导致一系列问题,如果想删除错误的cookies,请操作sqlite数据库完成~~,目前已实现Cookies校验,如果校验失败,请检查Cookies是否按照格式输入。
|
||||
|
||||
5、进入机器人在的群聊,即可正常使用本插件。
|
||||
|
||||
## 更新记录
|
||||
|
||||
**(作者已经转用NoneBot2,Hoshino的更新可能未经测试,有bug及时提Issues!)**
|
||||
|
||||
#### 2021-12-20
|
||||
|
||||
新增:8角色查询UI,全角色查询UI将会随背景图片改变而改变主题色。
|
||||
|
||||
新增:`角色xx<数字>`命令,例如`角色钟离84`,可以查看84级钟离基本属性。
|
||||
|
||||
新增:`角色xx`命令的类型匹配,例如`角色长柄武器`,可以查看所有长柄武器的角色,例如`角色火`,`角色火元素伤害加成`,`角色琉璃袋`,`角色燃愿玛瑙`等等……
|
||||
|
||||
新增:`材料xx`命令,例如`材料可莉`,可以查看可莉的材料列表。
|
||||
|
||||
新增:`活动列表`命令,第一次使用可能输出时间略久,需等待一段时间。
|
||||
|
||||
新增:`御神签`命令,随机抽签。
|
||||
|
||||
修复:若干bug
|
||||
|
||||
#### 2021-12-04
|
||||
|
||||
修复:`查询词云`功能失效的问题。
|
||||
|
||||
修复:`查询`功能只能查到8个角色的问题(经测试应该BanIP概率极低,默认生效)。
|
||||
|
||||
修复:`校验全部Cookies`命令错误的问题(**由于API返回字段变化的缘故,旧版本使用该命令会清空所有Ck,旧版本请不要使用该命令**),该问题同时导致`添加`命令不可用,均已修复。
|
||||
|
||||
优化:查询时优先从数据库中调用主人的Cookies。
|
||||
|
||||
优化:错误Cookies将在`NewCookiesTable`中的`Extra`标记为`error`(失效)或者`limit30`(今天达到30人限制),其中`limit30`将在每日零点清空。
|
||||
|
||||
#### 2021-11-24
|
||||
|
||||
新增:超级管理员`全部重签`功能
|
||||
|
||||
#### 2021-11-21
|
||||
|
||||
新增:`查询词云`功能
|
||||
|
||||
优化:`命座\dxx`
|
||||
|
||||
修改:默认背景图
|
||||
|
||||
#### 2021-11-18
|
||||
|
||||
修复:最新的深渊查询返回数据
|
||||
|
||||
修复:wiki百科接口
|
||||
|
||||
调整:默认背景图
|
||||
|
||||
#### 2021-11-14
|
||||
|
||||
新增:NoneBot2分支(前往NoneBot分支查看)
|
||||
|
||||
新增:原神wiki功能(beta),特别感谢[minigg](https://www.minigg.cn/)提供的Api调用,使用方式查看[指令](#指令)。
|
||||
|
||||
#### 2021-10-24
|
||||
|
||||
修复:Cookies池中存在失效Cookies时可能导致自动签到不正常运作
|
||||
|
||||
新增:每月统计的命令(该功能需要Cookies),具体使用可以前往[指令](#指令)处查阅。
|
||||
|
||||
优化:添加了部分代码的注释
|
||||
|
||||
#### 2021-10-24
|
||||
|
||||
**重要:目前Cookies池又采用了新的方式(去除冗余),如果你是上个版本的使用者,请在更新后使用群聊命令:优化Cookies,无损迁移旧版本全部Cookies;(如果你是上上个版本的使用者,更新后使用命令:迁移Cookies)**
|
||||
|
||||
修复:可能会导致的添加cookies问题
|
||||
|
||||
新增:绑定Cookies后可以实现米游社签到,如果开启自动签到之后,可以每天0:30准时签到,具体使用可以前往[指令](#指令)处查阅。
|
||||
|
||||
#### 2021-10-17
|
||||
|
||||
**重要:目前Cookies池采用了新的方式,如果你是之前版本的使用者,请在更新后使用群聊命令:迁移Cookies,无损迁移旧版本全部Cookies**
|
||||
|
||||
新增:奇馈宝箱的支持,以及新UI的调整。
|
||||
|
||||
新增:绑定Cookies可以实现基于当前绑定uid信息的树脂查询,以及推送,具体使用可以前往[指令](#指令)处查阅。
|
||||
|
||||
新增:可以查询深渊总览信息(beta),具体使用可以前往[指令](#指令)处查阅。
|
||||
|
||||
新增:可以群内@某人查询(角色信息、深渊总览、深渊固定层数),具体使用可以前往[指令](#指令)处查阅。
|
||||
|
||||
优化:更换了背景图,更新了readme的指令表格。
|
||||
|
||||
优化:支持群内命令:校验全部Cookies,以此判断是否Cookies池有失效CK。
|
||||
|
||||
修复:在查询深渊时背景图片无法正确缩放的问题。
|
||||
|
||||
修复:极少数情况下,查询功能失效的实例(先uid查询后mys查询)。
|
||||
|
||||
#### 2021-9-27
|
||||
|
||||
新增:Cookies次数防浪费机制(查过的mysid/uid会锁定使用过的cookies,当天再查时会使用同样的cookies防止次数浪费,每日零点清空。)
|
||||
|
||||
优化:Cookies填入现在需要私聊bot,可以设置多条,并且不会随着git pull而需要重新设置。
|
||||
|
||||
优化:白色底图现在的透明度会更高。
|
||||
|
||||
修复:使用心海刷新深渊记录时,尝试查询深渊时无法输出正确的结果。
|
||||
|
||||
#### 2021-9-20
|
||||
|
||||
新增:米游社id查询(指令示例:mys123456789),该方法同样支持深渊查询,(指令示例:mys123456789深渊12).
|
||||
|
||||
新增:支持绑定(指令示例:绑定uid123456789;指令示例:绑定mys123456789),二选一绑定或者都绑定也可,自动优先调用mys命令。
|
||||
|
||||
新增:绑定后可查询(指令示例:查询),同时支持深渊查询(指令示例:查询深渊12),该指令同时支持自定义图片,(指令示例:查询[此处应有图片])
|
||||
|
||||
修复:修复图片拉伸比例不正确等问题。
|
||||
|
||||
优化:现在输出的图片质量默认为90%,优化发送速度。
|
||||
|
||||
优化:文件夹目录的bg文件夹可自由添加背景随机图库。
|
||||
|
||||
优化:优化代码结构
|
||||
|
||||
#### 2021-9-7
|
||||
|
||||
修改了米游社的salt值[@Azure](https://github.com/Azure99),修复了米游社ds算法[@lulu666lululu](https://github.com/lulu666lulu)
|
||||
|
||||
更换了新ui+新背景画面。
|
||||
|
||||
添加了自动下载拼接头像、武器的程序,以后理论上游戏更新也通用。
|
||||
|
||||
uid命令现在可以根据角色数量自动设定长宽,并且自定义背景仍然适用!并且添加了角色当前携带的武器ui界面。
|
||||
|
||||
UID命令在uid命令的基础上删除了武器的ui界面。
|
||||
|
||||
添加了深渊查询,指令:uidxxxxxx深渊xx,例如uid123456789深渊12,只能查指定楼层(beta)
|
||||
|
||||
删除角色命令。
|
||||
|
||||
#### 2021-8-14
|
||||
|
||||
修复宵宫和早柚可能导致的输入错误bug。
|
||||
|
||||
增加了简易的cookies池,现在填写cookies的方法在函数cache_Cookie()中的cookie_list中,支持多个cookies共同使用。
|
||||
|
||||
增加了新功能(beta),使用uid+九位数字+角色的方式触发,获取全部角色+武器信息。
|
||||
|
||||
增加了新的默认随机图,简单修改了部分ui。
|
||||
|
||||
#### 2021-8-05
|
||||
|
||||
修复自定义图片时,竖屏图片可能造成黑边问题。
|
||||
|
||||
降低高斯模糊值。
|
||||
|
||||
#### 2021-8-01
|
||||
|
||||
添加自定义背景图。
|
||||
|
||||
#### 2021-7-29
|
||||
|
||||
优化排序算法。
|
||||
|
||||
#### 2021-7-28
|
||||
|
||||
添加排序算法。
|
||||
|
||||
#### 2021-7-26
|
||||
|
||||
完成主体。
|
||||
|
||||
#### 2021-7-18
|
||||
|
||||
本项目开坑。
|
||||
|
||||
## 指令
|
||||
|
||||
(**括号内为可选词缀**,以下所有可以输出图片的,**命令后跟图可自定义背景图片**):
|
||||
|
||||
| 触发前缀 | 触发后缀/备注 | 效果 | 举例 | 备注 |
|
||||
| :--------------------- | ---------------------- | -------------------------------------- | ------------------ | ---------------------------------------- |
|
||||
| uid | | 获取角色信息一览(带武器信息) | uid123456789 | |
|
||||
| uid | (上期)深渊 | 获取角色深渊总览(层数为最后一层) | uid123456789深渊 | |
|
||||
| uid | (上期)深渊9/10/11/12 | 获取角色深渊某一层数据 | uid123456789深渊12 | |
|
||||
| mys | | 角色信息(带武器信息,冒险等级) | mys123456 | 米游社通行证 |
|
||||
| mys | (上期)深渊 | 获取角色深渊总览(层数为最后一层) | mys123456深渊 | 米游社通行证 |
|
||||
| mys | (上期)深渊9/10/11/12 | 获取角色深渊某一层数据 | mys123456深渊12 | 米游社通行证 |
|
||||
| 活动列表 | | 输出活动列表 | 活动列表 | |
|
||||
| 御神签 | | 抽一张御神签 | 御神签 | |
|
||||
| 绑定uid | | 当前qq号关联绑定uid | 绑定uid123456789 | 查询前缀前置条件 |
|
||||
| 绑定mys | | 当前qq号关联绑定米游社通行证 | 绑定mys12345678 | 查询前缀前置条件 |
|
||||
| 查询 | | 查询当前绑定角色信息一览 | 查询 | **必须**绑定过mys/uid |
|
||||
| 查询(上期)深渊 | | 查询当前绑定角色深渊总览 | 查询深渊 | **必须**绑定过mys/uid |
|
||||
| 查询(上期)深渊\d | | 查询当前绑定角色深渊某一层数据 | 查询深渊10 | **必须**绑定过mys/uid |
|
||||
| 添加 | | 向cookies池添加cookies | 添加 _ga=balabala | **私聊**bot,注意空格 |
|
||||
| 查询 @人 | | 获取@的群友的角色信息一览 | 查询 @Wuyi | |
|
||||
| 查询(上期)深渊 @人 | | 获取@的群友的深渊信息一览 | 查询深渊 @Wuyi | |
|
||||
| 查询(上期)深渊\d @人 | | 获取@的群友的深渊某一层数据 | 查询深渊10 @Wuyi | |
|
||||
| 当前状态 | | 获取树脂、每日委托、派遣等信息 | 当前状态 | **必须**绑定过CK和uid |
|
||||
| 开启推送 | | 开启推送,超过140树脂提醒旅行者 | 开启推送 | 群聊/私聊都可<br />**必须**绑定过CK和uid |
|
||||
| 关闭推送 | | 关闭树脂快满的提醒 | 关闭推送 | 都可以 |
|
||||
| 校验全部Cookies | | 校验当前池内全部Cookies状态 | 校验全部Cookies | **群聊** |
|
||||
| 迁移Cookies | | 迁移旧版本(上上个版本)全部Cookies | 迁移Cookies | **群聊** |
|
||||
| 优化Cookies | | 优化上个版本全部Cookies | 优化Cookies | **群聊** |
|
||||
| 签到 | | 米游社签到 | 签到 | **必须**绑定过CK和uid |
|
||||
| 开启自动签到 | | 开启每日米游社签到 | 开启自动签到 | 群聊/私聊都可<br />**必须**绑定过CK和uid |
|
||||
| 关闭自动签到 | | 关闭每日米游社签到 | 关闭自动签到 | 群聊/私聊都可<br />**必须**绑定过CK和uid |
|
||||
| 全部重签 | | 手动重新签到所有人 | 重新自动签到 | **群聊** <br />**必须**由超级管理员执行 |
|
||||
| 每月统计 | | 查询当前绑定账号的每月/每日的原石/莫拉 | | 仅限群聊,**必须**绑定Cookies和uid |
|
||||
| 武器 | | 查询武器信息 | 武器天空之卷 | |
|
||||
| 命座\d | | 查询角色命座信息 | 命座6可莉 | |
|
||||
| 角色 | | 查询角色简略信息 | 角色可莉 | |
|
||||
| 角色 | \d | 查询角色某个等级的属性 | 角色可莉64 | |
|
||||
| 角色 | <某种类型> | 匹配一整类角色 | 角色燃愿玛瑙 | |
|
||||
| 材料 | | 输出角色材料列表 | 材料可莉 | |
|
||||
| 查询词云 | | 查询绑定角色的词云 | 查询词云 | 必须绑定过UID/MYSID |
|
||||
|
||||
### 深渊查询:
|
||||
|
||||

|
||||
|
||||
### 当前状态:
|
||||
|
||||

|
||||
|
||||
### 签到:
|
||||
|
||||

|
||||
|
||||
### 查询词云:
|
||||
|
||||

|
||||
|
||||
## 相关仓库
|
||||
## 丨感谢
|
||||
|
||||
- [PaimonBot](https://github.com/XiaoMiku01/PaimonBot) - 插件原始代码来自于它
|
||||
- [YuanShen_User_Info](https://github.com/Womsxd/YuanShen_User_Info) - 米游社API来自于它
|
||||
- *[MiniGG](https://www.minigg.cn/)* - Wiki API来自于它
|
||||
- [@MingxuanGame](https://github.com/MingxuanGame) - [Nonebot2-beta1](https://github.com/KimigaiiWuyi/GenshinUID/tree/nonebot2-beta1)分支新建与维护
|
||||
- [@shirokurakana](https://github.com/shirokurakana) - [Nonebot2-beta1分支的修复与优化](https://github.com/KimigaiiWuyi/GenshinUID/pull/118)
|
||||
- [@AMEKENN](https://github.com/AMEKENN) - 米游社签到部分的代码指导
|
||||
- [@lgc233](https://github.com/lgc2333) - 众多优秀PR贡献
|
||||
- [@RemKeeper](https://github.com/RemKeeper) - 简易Cookies获取文档
|
||||
- [@珊瑚宫千花](https://space.bilibili.com/398528056) - 角色别名Json提供
|
||||
- [@wudifeixue](https://github.com/wudifeixue) - PR贡献 & Bug报告
|
||||
- [@ZhouYingSASA](https://github.com/ZhouYingSASA) - PR贡献 & Bug报告
|
||||
|
||||
## 其他
|
||||
## 丨其他
|
||||
|
||||
代码写的很烂,勿喷,有问题可以发issues/Pull Requests~
|
||||
|
||||
顺便求个star~
|
||||
+ 如果对本插件有功能建议&Bug报告,欢迎提Issuse & Pr,每一条都会详细看过
|
||||
+ 如果本插件对你有帮助,不要忘了点个Star~
|
||||
+ 本项目仅供学习使用,请勿用于商业用途
|
||||
+ [爱发电](https://afdian.net/@KimigaiiWuyi)
|
||||
+ [GPL-3.0 License](https://github.com/KimigaiiWuyi/GenshinUID/blob/main/LICENSE) © [@KimigaiiWuyi](https://github.com/KimigaiiWuyi)
|
||||
|
735
__init__.py
@ -1,735 +0,0 @@
|
||||
from .getImg import draw_pic,draw_abyss_pic,draw_abyss0_pic,draw_wordcloud,draw_event_pic
|
||||
from .getDB import (CheckDB, GetAward, GetCharInfo, GetDaily, GetMysInfo,
|
||||
GetSignInfo, GetSignList, GetWeaponInfo, MysSign, OpenPush,
|
||||
connectDB, cookiesDB, deletecache, selectDB, get_alots)
|
||||
from nonebot import *
|
||||
from hoshino import Service,R,priv,util
|
||||
from hoshino.typing import MessageSegment,CQEvent, HoshinoBot
|
||||
|
||||
import requests,random,os,json,re,time,datetime,string,base64,math
|
||||
|
||||
import threading
|
||||
import hoshino
|
||||
import asyncio
|
||||
import hashlib
|
||||
import sqlite3
|
||||
from io import BytesIO
|
||||
import urllib
|
||||
|
||||
sv = Service('genshinuid')
|
||||
bot = get_bot()
|
||||
|
||||
FILE_PATH = os.path.dirname(__file__)
|
||||
FILE2_PATH = os.path.join(FILE_PATH,'mys')
|
||||
Texture_PATH = os.path.join(FILE2_PATH,'texture2d')
|
||||
|
||||
avatar_json = {
|
||||
"Albedo": "阿贝多",
|
||||
"Ambor": "安柏",
|
||||
"Barbara": "芭芭拉",
|
||||
"Beidou": "北斗",
|
||||
"Bennett": "班尼特",
|
||||
"Chongyun": "重云",
|
||||
"Diluc": "迪卢克",
|
||||
"Diona": "迪奥娜",
|
||||
"Eula": "优菈",
|
||||
"Fischl": "菲谢尔",
|
||||
"Ganyu": "甘雨",
|
||||
"Hutao": "胡桃",
|
||||
"Jean": "琴",
|
||||
"Kazuha": "枫原万叶",
|
||||
"Kaeya": "凯亚",
|
||||
"Ayaka": "神里绫华",
|
||||
"Keqing": "刻晴",
|
||||
"Klee": "可莉",
|
||||
"Lisa": "丽莎",
|
||||
"Mona": "莫娜",
|
||||
"Ningguang": "凝光",
|
||||
"Noel": "诺艾尔",
|
||||
"Qiqi": "七七",
|
||||
"Razor": "雷泽",
|
||||
"Rosaria": "罗莎莉亚",
|
||||
"Sucrose": "砂糖",
|
||||
"Tartaglia": "达达利亚",
|
||||
"Venti": "温迪",
|
||||
"Xiangling": "香菱",
|
||||
"Xiao": "魈",
|
||||
"Xingqiu": "行秋",
|
||||
"Xinyan": "辛焱",
|
||||
"Yanfei": "烟绯",
|
||||
"Zhongli": "钟离",
|
||||
"Yoimiya": "宵宫",
|
||||
"Sayu": "早柚",
|
||||
"Shogun": "雷电将军",
|
||||
"Aloy": "埃洛伊",
|
||||
"Sara": "九条裟罗",
|
||||
"Kokomi": "珊瑚宫心海"
|
||||
}
|
||||
|
||||
daily_im = '''
|
||||
*数据刷新可能存在一定延迟,请以当前游戏实际数据为准{}
|
||||
==============
|
||||
原粹树脂:{}/{}{}
|
||||
每日委托:{}/{} 奖励{}领取
|
||||
周本减半:{}/{}
|
||||
探索派遣:
|
||||
总数/完成/上限:{}/{}/{}
|
||||
{}'''
|
||||
|
||||
month_im = '''
|
||||
==============
|
||||
{}
|
||||
UID:{}
|
||||
==============
|
||||
本日获取原石:{}
|
||||
本日获取摩拉:{}
|
||||
==============
|
||||
昨日获取原石:{}
|
||||
昨日获取摩拉:{}
|
||||
==============
|
||||
本月获取原石:{}
|
||||
本月获取摩拉:{}
|
||||
==============
|
||||
上月获取原石:{}
|
||||
上月获取摩拉:{}
|
||||
==============
|
||||
原石收入组成:
|
||||
{}=============='''
|
||||
|
||||
weapon_im = '''【名称】:{}
|
||||
【类型】:{}
|
||||
【稀有度】:{}
|
||||
【介绍】:{}
|
||||
【攻击力】:{}{}{}'''
|
||||
|
||||
char_info_im = '''{}
|
||||
【稀有度】:{}
|
||||
【武器】:{}
|
||||
【元素】:{}
|
||||
【突破加成】:{}
|
||||
【生日】:{}
|
||||
【命之座】:{}
|
||||
【cv】:{}
|
||||
【介绍】:{}'''
|
||||
|
||||
@sv.on_fullmatch('活动列表')
|
||||
async def _(bot:HoshinoBot, ev: CQEvent):
|
||||
img_path = os.path.join(FILE2_PATH,"event.jpg")
|
||||
while(1):
|
||||
if os.path.exists(img_path):
|
||||
f=open(img_path,'rb')
|
||||
ls_f = base64.b64encode(f.read()).decode()
|
||||
imgmes = 'base64://' + ls_f
|
||||
f.close()
|
||||
im = f"[CQ:image,file={imgmes}]"
|
||||
break
|
||||
else:
|
||||
await draw_event_pic()
|
||||
await bot.send(ev,im)
|
||||
|
||||
@sv.on_fullmatch('御神签')
|
||||
async def _(bot:HoshinoBot, ev: CQEvent):
|
||||
qid = ev.sender["user_id"]
|
||||
raw_data = await get_alots(qid)
|
||||
im = base64.b64decode(raw_data).decode("utf-8")
|
||||
await bot.send(ev,im)
|
||||
|
||||
@sv.on_prefix('材料')
|
||||
async def _(bot:HoshinoBot, ev: CQEvent):
|
||||
message = ev.message.extract_plain_text()
|
||||
message = message.replace(' ', "")
|
||||
im = await char_wiki(message,extra="cost")
|
||||
await bot.send(ev,im)
|
||||
|
||||
@sv.on_prefix('武器')
|
||||
async def _(bot:HoshinoBot, ev: CQEvent):
|
||||
message = ev.message.extract_plain_text()
|
||||
im = await weapon_wiki(message)
|
||||
await bot.send(ev,im,at_sender=True)
|
||||
|
||||
@sv.on_prefix('角色')
|
||||
async def _(bot:HoshinoBot, ev: CQEvent):
|
||||
message = ev.message.extract_plain_text()
|
||||
message = message.replace(' ', "")
|
||||
name = ''.join(re.findall('[\u4e00-\u9fa5]', message))
|
||||
level = re.findall(r"[0-9]+", message)
|
||||
if len(level) == 1:
|
||||
im = await char_wiki(name,extra="stats",num=level[0])
|
||||
else:
|
||||
im = await char_wiki(name)
|
||||
await bot.send(ev,im)
|
||||
|
||||
@sv.on_prefix('命座')
|
||||
async def _(bot:HoshinoBot, ev: CQEvent):
|
||||
message = ev.message.extract_plain_text()
|
||||
num = int(re.findall(r"\d+", message)[0])
|
||||
m = ''.join(re.findall('[\u4e00-\u9fa5]',message))
|
||||
if num<= 0 or num >6:
|
||||
await bot.send(ev,"你家{}有{}命?".format(m,num),at_sender = True)
|
||||
else:
|
||||
im = await char_wiki(m,2,num)
|
||||
await bot.send(ev,im,at_sender=True)
|
||||
|
||||
#每日零点清空cookies使用缓存
|
||||
@sv.scheduled_job('cron', hour='0')
|
||||
async def delete():
|
||||
deletecache()
|
||||
|
||||
@sv.scheduled_job('cron', hour='2')
|
||||
async def delete():
|
||||
await draw_event_pic()
|
||||
|
||||
@sv.on_fullmatch('全部重签')
|
||||
async def _(bot:HoshinoBot, ev: CQEvent):
|
||||
if ev.user_id not in bot.config.SUPERUSERS:
|
||||
return
|
||||
await bot.send(ev,"已开始执行")
|
||||
await dailysign()
|
||||
|
||||
#每日零点半进行米游社签到
|
||||
@sv.scheduled_job('cron', hour='0',minute="30")
|
||||
async def dailysign():
|
||||
await dailysign()
|
||||
|
||||
async def dailysign():
|
||||
conn = sqlite3.connect('ID_DATA.db')
|
||||
c = conn.cursor()
|
||||
cursor = c.execute(
|
||||
"SELECT * FROM NewCookiesTable WHERE StatusB != ?", ("off",))
|
||||
c_data = cursor.fetchall()
|
||||
|
||||
for row in c_data:
|
||||
|
||||
im = await sign(str(row[0]))
|
||||
if row[4] == "on":
|
||||
await bot.send_private_msg(user_id = row[2],message = im)
|
||||
else:
|
||||
await bot.send_group_msg(group_id = row[4],message = f"[CQ:at,qq={row[2]}]" + "\n" + im)
|
||||
|
||||
await asyncio.sleep(7)
|
||||
|
||||
#每隔半小时检测树脂是否超过设定值
|
||||
@sv.scheduled_job('interval', minutes=30)
|
||||
async def push():
|
||||
daily_data = await daily()
|
||||
if daily_data != None:
|
||||
for i in daily_data:
|
||||
if i['gid'] == "on":
|
||||
await bot.send_private_msg(user_id = i['qid'],message = i['message'])
|
||||
else:
|
||||
await bot.send_group_msg(group_id = i['gid'],message = f"[CQ:at,qq={i['qid']}]" + "\n" + i['message'])
|
||||
else:
|
||||
pass
|
||||
|
||||
#私聊事件
|
||||
@bot.on_message('private')
|
||||
async def setting(ctx):
|
||||
message = ctx['raw_message']
|
||||
sid=int(ctx["self_id"])
|
||||
userid=int(ctx["sender"]["user_id"])
|
||||
gid=0
|
||||
if '添加 ' in message:
|
||||
try:
|
||||
mes = message.replace('添加 ','')
|
||||
aid = re.search(r"account_id=(\d*)", mes)
|
||||
mysid_data = aid.group(0).split('=')
|
||||
mysid = mysid_data[1]
|
||||
cookie = ';'.join(filter(lambda x: x.split('=')[0] in ["cookie_token", "account_id"], [i.strip() for i in mes.split(';')]))
|
||||
mys_data = await GetMysInfo(mysid,cookie)
|
||||
for i in mys_data['data']['list']:
|
||||
if i['game_id'] != 2:
|
||||
mys_data['data']['list'].remove(i)
|
||||
uid = mys_data['data']['list'][0]['game_role_id']
|
||||
await cookiesDB(uid,cookie,userid)
|
||||
await bot.send_msg(self_id=sid, user_id=userid, group_id=gid, message=f'添加Cookies成功!Cookies属于个人重要信息,如果你是在不知情的情况下添加,请马上修改米游社账户密码,保护个人隐私!')
|
||||
except:
|
||||
await bot.send_msg(self_id=sid, user_id=userid, group_id=gid, message=f'校验失败!请输入正确的Cookies!')
|
||||
elif '开启推送' in message:
|
||||
try:
|
||||
uid = await selectDB(userid,mode = "uid")
|
||||
im = await OpenPush(int(uid[0]),userid,"on","StatusA")
|
||||
await bot.send_msg(self_id=sid, user_id=userid, group_id=gid, message=im)
|
||||
except:
|
||||
await bot.send_msg(self_id=sid, user_id=userid, group_id=gid, message="未找到uid绑定记录。")
|
||||
elif '关闭推送' in message:
|
||||
try:
|
||||
uid = await selectDB(userid,mode = "uid")
|
||||
im = await OpenPush(int(uid[0]),userid,"off","StatusA")
|
||||
await bot.send_msg(self_id=sid, user_id=userid, group_id=gid, message=im)
|
||||
except:
|
||||
await bot.send_msg(self_id=sid, user_id=userid, group_id=gid, message="未找到uid绑定记录。")
|
||||
elif '开启自动签到' in message:
|
||||
try:
|
||||
uid = await selectDB(userid,mode = "uid")
|
||||
im = await OpenPush(int(uid[0]),userid,"on","StatusB")
|
||||
await bot.send_msg(self_id=sid, user_id=userid, group_id=gid, message=im)
|
||||
except:
|
||||
await bot.send_msg(self_id=sid, user_id=userid, group_id=gid, message="未找到uid绑定记录。")
|
||||
elif '关闭自动签到' in message:
|
||||
try:
|
||||
uid = await selectDB(userid,mode = "uid")
|
||||
im = await OpenPush(int(uid[0]),userid,"off","StatusA")
|
||||
await bot.send_msg(self_id=sid, user_id=userid, group_id=gid, message=im)
|
||||
except:
|
||||
await bot.send_msg(self_id=sid, user_id=userid, group_id=gid, message="未找到uid绑定记录。")
|
||||
|
||||
#群聊开启 自动签到 和 推送树脂提醒 功能
|
||||
@sv.on_prefix('开启')
|
||||
async def _(bot:HoshinoBot, ev: CQEvent):
|
||||
message = ev.message.extract_plain_text()
|
||||
m = ''.join(re.findall('[\u4e00-\u9fa5]',message))
|
||||
if m == "自动签到":
|
||||
try:
|
||||
gid = ev.group_id
|
||||
qid = ev.sender["user_id"]
|
||||
uid = await selectDB(ev.sender['user_id'],mode = "uid")
|
||||
im = await OpenPush(int(uid[0]),ev.sender['user_id'],str(gid),"StatusB")
|
||||
await bot.send(ev,im,at_sender=True)
|
||||
except:
|
||||
await bot.send(ev,"未绑定uid信息!",at_sender=True)
|
||||
elif m == "推送":
|
||||
try:
|
||||
gid = ev.group_id
|
||||
qid = ev.sender["user_id"]
|
||||
uid = await selectDB(ev.sender['user_id'],mode = "uid")
|
||||
im = await OpenPush(int(uid[0]),ev.sender['user_id'],str(gid),"StatusA")
|
||||
await bot.send(ev,im,at_sender=True)
|
||||
except:
|
||||
await bot.send(ev,"未绑定uid信息!",at_sender=True)
|
||||
|
||||
#群聊关闭 自动签到 和 推送树脂提醒 功能
|
||||
@sv.on_prefix('关闭')
|
||||
async def _(bot:HoshinoBot, ev: CQEvent):
|
||||
message = ev.message.extract_plain_text()
|
||||
m = ''.join(re.findall('[\u4e00-\u9fa5]',message))
|
||||
if m == "自动签到":
|
||||
try:
|
||||
gid = ev.group_id
|
||||
qid = ev.sender["user_id"]
|
||||
uid = await selectDB(ev.sender['user_id'],mode = "uid")
|
||||
im = await OpenPush(int(uid[0]),ev.sender['user_id'],"off","StatusB")
|
||||
await bot.send(ev,im,at_sender=True)
|
||||
except:
|
||||
await bot.send(ev,"未绑定uid信息!",at_sender=True)
|
||||
elif m == "推送":
|
||||
try:
|
||||
gid = ev.group_id
|
||||
qid = ev.sender["user_id"]
|
||||
uid = await selectDB(ev.sender['user_id'],mode = "uid")
|
||||
im = await OpenPush(int(uid[0]),ev.sender['user_id'],"off","StatusA")
|
||||
await bot.send(ev,im,at_sender=True)
|
||||
except:
|
||||
await bot.send(ev,"未绑定uid信息!",at_sender=True)
|
||||
|
||||
#群聊内 每月统计 功能
|
||||
@sv.on_fullmatch('每月统计')
|
||||
async def _(bot:HoshinoBot, ev: CQEvent):
|
||||
try:
|
||||
qid = ev.sender["user_id"]
|
||||
uid = await selectDB(ev.sender['user_id'],mode = "uid")
|
||||
uid = uid[0]
|
||||
data = await GetAward(uid)
|
||||
nickname = data['data']['nickname']
|
||||
day_stone = data['data']['day_data']['current_primogems']
|
||||
day_mora = data['data']['day_data']['current_mora']
|
||||
lastday_stone = data['data']['day_data']['last_primogems']
|
||||
lastday_mora = data['data']['day_data']['last_mora']
|
||||
month_stone = data['data']['month_data']['current_primogems']
|
||||
month_mora = data['data']['month_data']['current_mora']
|
||||
lastmonth_stone = data['data']['month_data']['last_primogems']
|
||||
lastmonth_mora = data['data']['month_data']['last_mora']
|
||||
group_str = ''
|
||||
for i in data['data']['month_data']['group_by']:
|
||||
group_str = group_str + i['action'] + ":" + str(i['num']) + "(" + str(i['percent']) + "%)" + '\n'
|
||||
|
||||
im = month_im.format(nickname,uid,day_stone,day_mora,lastday_stone,lastday_mora,month_stone,month_mora,lastmonth_stone,lastmonth_mora,group_str)
|
||||
await bot.send(ev,im,at_sender=True)
|
||||
except:
|
||||
await bot.send(ev,'未找到绑定信息',at_sender=True)
|
||||
|
||||
#群聊内 签到 功能
|
||||
@sv.on_fullmatch('签到')
|
||||
async def _(bot:HoshinoBot, ev: CQEvent):
|
||||
try:
|
||||
qid = ev.sender["user_id"]
|
||||
uid = await selectDB(ev.sender['user_id'],mode = "uid")
|
||||
uid = uid[0]
|
||||
im = await sign(uid)
|
||||
await bot.send(ev,im,at_sender=True)
|
||||
except:
|
||||
await bot.send(ev,'未找到绑定信息',at_sender=True)
|
||||
|
||||
#群聊内 数据库v2 迁移至 数据库v3 的命令,一般只需要更新时执行一次
|
||||
@sv.on_fullmatch('优化Cookies')
|
||||
async def _(bot:HoshinoBot, ev: CQEvent):
|
||||
try:
|
||||
im = await OpCookies()
|
||||
await bot.send(ev,im,at_sender=True)
|
||||
except:
|
||||
pass
|
||||
|
||||
#群聊内 校验Cookies 是否正常的功能,不正常自动删掉
|
||||
@sv.on_fullmatch('校验全部Cookies')
|
||||
async def _(bot:HoshinoBot, ev: CQEvent):
|
||||
im = await CheckDB()
|
||||
await bot.send(ev,im)
|
||||
|
||||
#群聊内 数据库v1 迁移至 数据库v2 的命令,一般只需要更新时执行一次
|
||||
@sv.on_fullmatch('迁移Cookies')
|
||||
async def _(bot:HoshinoBot, ev: CQEvent):
|
||||
im = await TransDB()
|
||||
await bot.send(ev,im)
|
||||
|
||||
#群聊内 查询当前树脂状态以及派遣状态 的命令
|
||||
@sv.on_fullmatch('当前状态')
|
||||
async def _(bot:HoshinoBot, ev: CQEvent):
|
||||
try:
|
||||
uid = await selectDB(ev.sender['user_id'],mode = "uid")
|
||||
uid = uid[0]
|
||||
mes = await daily("ask",uid)
|
||||
im = mes[0]['message']
|
||||
except:
|
||||
im = "没有找到绑定信息。"
|
||||
|
||||
await bot.send(ev,im, at_sender=True)
|
||||
|
||||
#群聊内 查询uid 的命令
|
||||
@sv.on_prefix('uid')
|
||||
async def _(bot:HoshinoBot, ev: CQEvent):
|
||||
image = re.search(r"\[CQ:image,file=(.*),url=(.*)\]", str(ev.message))
|
||||
message = ev.message.extract_plain_text()
|
||||
uid = re.findall(r"\d+", message)[0] # str
|
||||
m = ''.join(re.findall('[\u4e00-\u9fa5]',message))
|
||||
if m == "深渊":
|
||||
try:
|
||||
if len(re.findall(r"\d+", message)) == 2:
|
||||
floor_num = re.findall(r"\d+", message)[1]
|
||||
im = await draw_abyss_pic(uid,ev.sender['nickname'],floor_num,image)
|
||||
await bot.send(ev, im, at_sender=True)
|
||||
else:
|
||||
im = await draw_abyss0_pic(uid,ev.sender['nickname'],image)
|
||||
await bot.send(ev, im, at_sender=True)
|
||||
except:
|
||||
await bot.send(ev,'深渊输入错误!')
|
||||
elif m == "上期深渊":
|
||||
try:
|
||||
if len(re.findall(r"\d+", message)) == 2:
|
||||
floor_num = re.findall(r"\d+", message)[1]
|
||||
im = await draw_abyss_pic(uid,ev.sender['nickname'],floor_num,image,2,"2")
|
||||
await bot.send(ev, im, at_sender=True)
|
||||
else:
|
||||
im = await draw_abyss0_pic(uid,ev.sender['nickname'],image,2,"2")
|
||||
await bot.send(ev, im, at_sender=True)
|
||||
except:
|
||||
await bot.send(ev,'深渊输入错误!')
|
||||
else:
|
||||
try:
|
||||
im = await draw_pic(uid,ev.sender['nickname'],image,2)
|
||||
await bot.send(ev, im, at_sender=True)
|
||||
except:
|
||||
await bot.send(ev,'输入错误!')
|
||||
|
||||
#群聊内 绑定uid 的命令,会绑定至当前qq号上
|
||||
@sv.on_prefix('绑定uid')
|
||||
async def _(bot:HoshinoBot, ev: CQEvent):
|
||||
message = ev.message.extract_plain_text()
|
||||
uid = re.findall(r"\d+", message)[0] # str
|
||||
await connectDB(ev.sender['user_id'],uid)
|
||||
await bot.send(ev,'绑定uid成功!', at_sender=True)
|
||||
|
||||
#群聊内 绑定米游社通行证 的命令,会绑定至当前qq号上,和绑定uid不冲突,两者可以同时绑定
|
||||
@sv.on_prefix('绑定mys')
|
||||
async def _(bot:HoshinoBot, ev: CQEvent):
|
||||
message = ev.message.extract_plain_text()
|
||||
mys = re.findall(r"\d+", message)[0] # str
|
||||
await connectDB(ev.sender['user_id'],None,mys)
|
||||
await bot.send(ev,'绑定米游社id成功!', at_sender=True)
|
||||
|
||||
#群聊内 绑定过uid/mysid的情况下,可以查询,默认优先调用米游社通行证,多出世界等级一个参数
|
||||
@sv.on_prefix('查询')
|
||||
async def _(bot, ev):
|
||||
image = re.search(r"\[CQ:image,file=(.*),url=(.*)\]", str(ev.message))
|
||||
at = re.search(r"\[CQ:at,qq=(\d*)\]", str(ev.raw_message.strip()))
|
||||
message = ev.message.extract_plain_text()
|
||||
if at:
|
||||
qid = at.group(1)
|
||||
mi =await bot.get_group_member_info(group_id=ev.group_id, user_id=qid)
|
||||
nickname = mi["nickname"]
|
||||
uid = await selectDB(qid)
|
||||
else:
|
||||
nickname = ev.sender['nickname']
|
||||
uid = await selectDB(ev.sender['user_id'])
|
||||
|
||||
m = ''.join(re.findall('[\u4e00-\u9fa5]',message))
|
||||
if uid:
|
||||
if m == "深渊":
|
||||
try:
|
||||
if len(re.findall(r"\d+", message)) == 1:
|
||||
floor_num = re.findall(r"\d+", message)[0]
|
||||
im = await draw_abyss_pic(uid[0],nickname,floor_num,image,uid[1])
|
||||
await bot.send(ev, im, at_sender=True)
|
||||
else:
|
||||
im = await draw_abyss0_pic(uid[0],nickname,image,uid[1])
|
||||
await bot.send(ev, im, at_sender=True)
|
||||
except:
|
||||
await bot.send(ev,'输入错误!')
|
||||
elif m == "上期深渊":
|
||||
try:
|
||||
if len(re.findall(r"\d+", message)) == 1:
|
||||
floor_num = re.findall(r"\d+", message)[0]
|
||||
im = await draw_abyss_pic(uid[0],nickname,floor_num,image,uid[1],"2")
|
||||
await bot.send(ev, im, at_sender=True)
|
||||
else:
|
||||
im = await draw_abyss0_pic(uid[0],nickname,image,uid[1],"2")
|
||||
await bot.send(ev, im, at_sender=True)
|
||||
except:
|
||||
await bot.send(ev,'深渊输入错误!')
|
||||
elif m == "词云":
|
||||
try:
|
||||
im = await draw_wordcloud(uid[0],image,uid[1])
|
||||
await bot.send(ev,im, at_sender=True)
|
||||
except:
|
||||
await bot.send(ev,'遇到错误!')
|
||||
elif m == "":
|
||||
try:
|
||||
bg = await draw_pic(uid[0],nickname,image,uid[1])
|
||||
await bot.send(ev, bg, at_sender=True)
|
||||
except:
|
||||
await bot.send(ev,'输入错误!')
|
||||
else:
|
||||
pass
|
||||
else:
|
||||
await bot.send(ev,'未找到绑定记录!')
|
||||
|
||||
#群聊内 查询米游社通行证 的命令
|
||||
@sv.on_prefix('mys')
|
||||
async def _(bot:HoshinoBot, ev: CQEvent):
|
||||
image = re.search(r"\[CQ:image,file=(.*),url=(.*)\]", str(ev.message))
|
||||
message = ev.message.extract_plain_text()
|
||||
uid = re.findall(r"\d+", message)[0] # str
|
||||
m = ''.join(re.findall('[\u4e00-\u9fa5]',message))
|
||||
if m == "深渊":
|
||||
try:
|
||||
if len(re.findall(r"\d+", message)) == 2:
|
||||
floor_num = re.findall(r"\d+", message)[1]
|
||||
im = await draw_abyss_pic(uid,ev.sender['nickname'],floor_num,image,3)
|
||||
await bot.send(ev, im, at_sender=True)
|
||||
else:
|
||||
im = await draw_abyss0_pic(uid,ev.sender['nickname'],image,3)
|
||||
await bot.send(ev, im, at_sender=True)
|
||||
except:
|
||||
await bot.send(ev,'深渊输入错误!')
|
||||
elif m == "上期深渊":
|
||||
try:
|
||||
if len(re.findall(r"\d+", message)) == 1:
|
||||
floor_num = re.findall(r"\d+", message)[0]
|
||||
im = await draw_abyss_pic(uid,ev.sender['nickname'],floor_num,image,3,"2")
|
||||
await bot.send(ev, im, at_sender=True)
|
||||
else:
|
||||
im = await draw_abyss0_pic(uid,ev.sender['nickname'],image,3,"2")
|
||||
await bot.send(ev, im, at_sender=True)
|
||||
except:
|
||||
await bot.send(ev,'深渊输入错误!')
|
||||
else:
|
||||
try:
|
||||
im = await draw_pic(uid,ev.sender['nickname'],image,3)
|
||||
await bot.send(ev, im, at_sender=True)
|
||||
except:
|
||||
await bot.send(ev,'输入错误!')
|
||||
|
||||
#签到函数
|
||||
async def sign(uid):
|
||||
try:
|
||||
sign_data = await MysSign(uid)
|
||||
status = sign_data['message']
|
||||
im = "\n"
|
||||
sign_info = await GetSignInfo(uid)
|
||||
sign_info_data = sign_info['data']
|
||||
if status == "OK" and sign_info_data['is_sign'] == True:
|
||||
mes_im = "签到成功"
|
||||
else:
|
||||
mes_im = status
|
||||
im = im + mes_im +"!" + "\n"
|
||||
|
||||
sign_missed = sign_info_data['sign_cnt_missed']
|
||||
sign_list = await GetSignList()
|
||||
getitem = sign_list['data']['awards'][int(sign_info_data['total_sign_day'])-1]['name']
|
||||
getnum = sign_list['data']['awards'][int(sign_info_data['total_sign_day'])-1]['cnt']
|
||||
get_im = f"本次签到获得{getitem}x{getnum}"
|
||||
im = "\n" + mes_im +"!" + "\n" + get_im + "\n" + f"本月漏签次数:{sign_missed}"
|
||||
#im = im + "\n" + "本次签到获取物品请求失败"
|
||||
|
||||
except:
|
||||
im = im + "签到失败,请检查Cookies是否失效。"
|
||||
return im
|
||||
|
||||
#统计状态函数
|
||||
async def daily(mode="push", uid=None):
|
||||
def seconds2hours(seconds: int) -> str:
|
||||
m, s = divmod(int(seconds), 60)
|
||||
h, m = divmod(m, 60)
|
||||
return "%02d:%02d:%02d" % (h, m, s)
|
||||
|
||||
temp_list = []
|
||||
conn = sqlite3.connect('ID_DATA.db')
|
||||
c = conn.cursor()
|
||||
if mode == "push":
|
||||
cursor = c.execute(
|
||||
"SELECT * FROM NewCookiesTable WHERE StatusA != ?", ("off",))
|
||||
c_data = cursor.fetchall()
|
||||
elif mode == "ask":
|
||||
c_data = ([uid, 0, 0, 0, 0, 0, 0],)
|
||||
|
||||
for row in c_data:
|
||||
raw_data = await GetDaily(str(row[0]))
|
||||
dailydata = raw_data["data"]
|
||||
current_resin = dailydata['current_resin']
|
||||
|
||||
if current_resin >= row[6]:
|
||||
tip = ''
|
||||
if row[1] != 0:
|
||||
tip = "\n==============\n你的树脂快满了!"
|
||||
|
||||
max_resin = dailydata['max_resin']
|
||||
rec_time = ''
|
||||
# print(dailydata)
|
||||
if current_resin < 160:
|
||||
resin_recovery_time = seconds2hours(
|
||||
dailydata['resin_recovery_time'])
|
||||
next_resin_rec_time = seconds2hours(
|
||||
8 * 60 - ((dailydata['max_resin'] - dailydata['current_resin']) * 8 * 60 - int(dailydata['resin_recovery_time'])))
|
||||
rec_time = f' ({next_resin_rec_time}/{resin_recovery_time})'
|
||||
|
||||
finished_task_num = dailydata['finished_task_num']
|
||||
total_task_num = dailydata['total_task_num']
|
||||
is_extra_got = '已' if dailydata['is_extra_task_reward_received'] else '未'
|
||||
|
||||
resin_discount_num_limit = dailydata['resin_discount_num_limit']
|
||||
used_resin_discount_num = resin_discount_num_limit - \
|
||||
dailydata['remain_resin_discount_num']
|
||||
|
||||
current_expedition_num = dailydata['current_expedition_num']
|
||||
max_expedition_num = dailydata['max_expedition_num']
|
||||
finished_expedition_num = 0
|
||||
expedition_info: list[str] = []
|
||||
for expedition in dailydata['expeditions']:
|
||||
avatar: str = expedition['avatar_side_icon'][89:-4]
|
||||
try:
|
||||
avatar_name: str = avatar_json[avatar]
|
||||
except KeyError:
|
||||
avatar_name: str = avatar
|
||||
|
||||
if expedition['status'] == 'Finished':
|
||||
expedition_info.append(f"{avatar_name} 探索完成")
|
||||
finished_expedition_num += 1
|
||||
else:
|
||||
remained_timed: str = seconds2hours(
|
||||
expedition['remained_time'])
|
||||
expedition_info.append(
|
||||
f"{avatar_name} 剩余时间{remained_timed}")
|
||||
expedition_data = "\n".join(expedition_info)
|
||||
|
||||
send_mes = daily_im.format(tip, current_resin, max_resin, rec_time, finished_task_num, total_task_num, is_extra_got, used_resin_discount_num,
|
||||
resin_discount_num_limit, current_expedition_num, finished_expedition_num, max_expedition_num, expedition_data)
|
||||
|
||||
temp_list.append(
|
||||
{"qid": row[2], "gid": row[3], "message": send_mes})
|
||||
return temp_list
|
||||
|
||||
async def weapon_wiki(name):
|
||||
data = await GetWeaponInfo(name)
|
||||
name = data['name']
|
||||
type = data['weapontype']
|
||||
star = data['rarity'] + "星"
|
||||
info = data['description']
|
||||
atk = str(data['baseatk'])
|
||||
sub_name = data['substat']
|
||||
if data['subvalue'] != "":
|
||||
sub_val = (data['subvalue'] +
|
||||
'%') if sub_name != '元素精通' else data['subvalue']
|
||||
sub = "\n" + "【" + sub_name + "】" + sub_val
|
||||
else:
|
||||
sub = ""
|
||||
|
||||
if data['effectname'] != "":
|
||||
raw_effect = data['effect']
|
||||
rw_ef = []
|
||||
for i in range(len(data['r1'])):
|
||||
now = ''
|
||||
for j in range(1, 6):
|
||||
now = now + data['r{}'.format(j)][i] + "/"
|
||||
now = now[:-1]
|
||||
rw_ef.append(now)
|
||||
raw_effect = raw_effect.format(*rw_ef)
|
||||
effect = "\n" + "【" + data['effectname'] + "】" + ":" + raw_effect
|
||||
else:
|
||||
effect = ""
|
||||
im = weapon_im.format(name, type, star, info, atk,
|
||||
sub, effect)
|
||||
return im
|
||||
|
||||
async def char_wiki(name, mode=0, num="", extra=""):
|
||||
data = await GetCharInfo(name, mode)
|
||||
if mode == 0:
|
||||
if isinstance(data,str):
|
||||
raw_data = data.replace("[","").replace("\n","").replace("]","").replace(" ","").replace("'","").split(',')
|
||||
if data.replace("\n","").replace(" ","") == "undefined":
|
||||
im = "不存在该角色或类型。"
|
||||
else:
|
||||
im = ','.join(raw_data)
|
||||
else:
|
||||
if extra == "cost":
|
||||
talent_data = await GetCharInfo(name, 1)
|
||||
|
||||
im = "【天赋材料(一份)】\n{}\n【突破材料】\n{}"
|
||||
im1 = ""
|
||||
im2 = ""
|
||||
|
||||
talent_temp = {}
|
||||
talent_cost = talent_data["costs"]
|
||||
for i in talent_cost.values():
|
||||
for j in i:
|
||||
if j["name"] not in talent_temp:
|
||||
talent_temp[j["name"]] = j["count"]
|
||||
else:
|
||||
talent_temp[j["name"]] = talent_temp[j["name"]] + j["count"]
|
||||
for k in talent_temp:
|
||||
im1 = im1 + k + ":" + str(talent_temp[k]) + "\n"
|
||||
|
||||
temp = {}
|
||||
cost = data["costs"]
|
||||
for i in range(1,7):
|
||||
for j in cost["ascend{}".format(i)]:
|
||||
if j["name"] not in temp:
|
||||
temp[j["name"]] = j["count"]
|
||||
else:
|
||||
temp[j["name"]] = temp[j["name"]] + j["count"]
|
||||
|
||||
for k in temp:
|
||||
im2 = im2 + k + ":" + str(temp[k]) + "\n"
|
||||
|
||||
im = im.format(im1,im2)
|
||||
|
||||
elif extra == "stats":
|
||||
data2 = await GetCharInfo(name, mode, num)
|
||||
im = (name + "\n等级:" + str(data2["level"]) + "\n血量:" + str(math.floor(data2["hp"])) +
|
||||
"\n攻击力:" + str(math.floor(data2["attack"])) + "\n防御力:" + str(math.floor(data2["defense"])) +
|
||||
"\n" + data["substat"] + ":" + '%.1f%%' % (data2["specialized"] * 100))
|
||||
else:
|
||||
name = data['title'] + ' — ' + data['name']
|
||||
star = data['rarity']
|
||||
type = data["weapontype"]
|
||||
element = data['element']
|
||||
up_val = data['substat']
|
||||
bdday = data['birthday']
|
||||
polar = data['constellation']
|
||||
cv = data['cv']['chinese']
|
||||
info = data['description']
|
||||
im = char_info_im.format(
|
||||
name, star, type, element, up_val, bdday, polar, cv, info)
|
||||
elif mode == 1:
|
||||
im = '暂不支持'
|
||||
elif mode == 2:
|
||||
im = "【" + data["c{}".format(num)]['name'] + "】" + ":" + \
|
||||
"\n" + data["c{}".format(num)]['effect'].replace("*", "")
|
||||
return im
|
864
genshinuid.py
Normal file
@ -0,0 +1,864 @@
|
||||
import asyncio,os,sys
|
||||
import base64
|
||||
import traceback
|
||||
|
||||
from aiocqhttp.exceptions import ActionFailed
|
||||
from hoshino import Service
|
||||
from hoshino.typing import CQEvent, HoshinoBot
|
||||
from nonebot import get_bot, logger
|
||||
|
||||
sys.path.append(os.path.dirname(os.path.realpath(__file__)))
|
||||
from mihoyo_libs.get_data import *
|
||||
from mihoyo_libs.get_image import *
|
||||
from mihoyo_libs.get_mihoyo_bbs_data import *
|
||||
|
||||
sv = Service('genshinuid')
|
||||
hoshino_bot = get_bot()
|
||||
|
||||
FILE_PATH = os.path.join(os.path.join(os.path.dirname(__file__), 'mihoyo_libs'),'mihoyo_bbs')
|
||||
INDEX_PATH = os.path.join(FILE_PATH, 'index')
|
||||
Texture_PATH = os.path.join(FILE_PATH, 'texture2d')
|
||||
|
||||
@sv.on_rex('[\u4e00-\u9fa5]+(用什么|能用啥|怎么养)')
|
||||
async def send_char_adv(bot: HoshinoBot, ev: CQEvent):
|
||||
try:
|
||||
name = str(ev.message).strip().replace(" ","")[:-3]
|
||||
im = await char_adv(name)
|
||||
await bot.send(ev, im)
|
||||
except Exception as e:
|
||||
logger.exception("获取建议失败。")
|
||||
|
||||
@sv.on_rex('[\u4e00-\u9fa5]+(能给谁|给谁用|要给谁|谁能用)')
|
||||
async def send_weapon_adv(bot: HoshinoBot, ev: CQEvent):
|
||||
try:
|
||||
name = str(ev.message).strip().replace(" ","")[:-3]
|
||||
im = await weapon_adv(name)
|
||||
await bot.send(ev, im)
|
||||
except Exception as e:
|
||||
logger.exception("获取建议失败。")
|
||||
|
||||
@sv.on_prefix('语音')
|
||||
async def send_audio(bot: HoshinoBot, ev: CQEvent):
|
||||
try:
|
||||
message = ev.message.extract_plain_text()
|
||||
message = message.replace(' ', "")
|
||||
name = ''.join(re.findall('[\u4e00-\u9fa5]', message))
|
||||
im = await audio_wiki(name, message)
|
||||
if name == "列表":
|
||||
await bot.send(ev, f"[CQ:image,file={im}]")
|
||||
else:
|
||||
await bot.send(ev, f"[CQ:recode,file={im}]")
|
||||
except ActionFailed as e:
|
||||
logger.exception("获取语音失败")
|
||||
await bot.send(ev, "机器人发送消息失败:{}".format(e))
|
||||
except Exception as e:
|
||||
logger.exception("获取语音失败")
|
||||
await bot.send(ev, "发生错误 {},请检查后台输出。".format(e))
|
||||
|
||||
|
||||
@sv.on_fullmatch('活动列表')
|
||||
async def send_polar(bot: HoshinoBot, ev: CQEvent):
|
||||
try:
|
||||
img_path = os.path.join(FILE_PATH, "event.jpg")
|
||||
while 1:
|
||||
if os.path.exists(img_path):
|
||||
f = open(img_path, 'rb')
|
||||
ls_f = base64.b64encode(f.read()).decode()
|
||||
img_mihoyo_bbs = 'base64://' + ls_f
|
||||
f.close()
|
||||
im = f"[CQ:image,file={img_mihoyo_bbs}]"
|
||||
break
|
||||
else:
|
||||
await draw_event_pic()
|
||||
await bot.send(ev, im)
|
||||
except ActionFailed as e:
|
||||
await bot.send(ev, "机器人发送消息失败:{}".format(e))
|
||||
logger.exception("发送活动列表失败")
|
||||
except Exception as e:
|
||||
await bot.send(ev, "发生错误 {},请检查后台输出。".format(e))
|
||||
logger.exception("获取活动列表错误")
|
||||
|
||||
|
||||
@sv.on_fullmatch('御神签')
|
||||
async def send_lots(bot: HoshinoBot, ev: CQEvent):
|
||||
try:
|
||||
qid = ev.sender["user_id"]
|
||||
raw_data = await get_a_lots(qid)
|
||||
im = base64.b64decode(raw_data).decode("utf-8")
|
||||
await bot.send(ev, im)
|
||||
except ActionFailed as e:
|
||||
await bot.send(ev, "机器人发送消息失败:{}".format(e))
|
||||
logger.exception("发送御神签失败")
|
||||
except Exception as e:
|
||||
await bot.send(ev, "发生错误 {},请检查后台输出。".format(e))
|
||||
logger.exception("获取御神签错误")
|
||||
|
||||
|
||||
@sv.on_prefix('材料')
|
||||
async def send_cost(bot: HoshinoBot, ev: CQEvent):
|
||||
try:
|
||||
message = ev.message.extract_plain_text()
|
||||
message = message.replace(' ', "")
|
||||
im = await char_wiki(message, "costs")
|
||||
await bot.send(ev, im)
|
||||
except ActionFailed as e:
|
||||
await bot.send(ev, "机器人发送消息失败:{}".format(e))
|
||||
logger.exception("发送材料信息失败")
|
||||
except Exception as e:
|
||||
await bot.send(ev, "发生错误 {},请检查后台输出。".format(e))
|
||||
logger.exception("获取材料信息错误")
|
||||
|
||||
|
||||
@sv.on_prefix('原魔')
|
||||
async def send_enemies(bot: HoshinoBot, ev: CQEvent):
|
||||
try:
|
||||
message = ev.message.extract_plain_text()
|
||||
im = await enemies_wiki(message)
|
||||
await bot.send(ev, im)
|
||||
except ActionFailed as e:
|
||||
await bot.send(ev, "机器人发送消息失败:{}".format(e))
|
||||
logger.exception("发送怪物信息失败")
|
||||
except Exception as e:
|
||||
await bot.send(ev, "发生错误 {},请检查后台输出。".format(e))
|
||||
logger.exception("获取怪物信息错误")
|
||||
|
||||
|
||||
@sv.on_prefix('食物')
|
||||
async def send_food(bot: HoshinoBot, ev: CQEvent):
|
||||
try:
|
||||
message = ev.message.extract_plain_text()
|
||||
im = await foods_wiki(message)
|
||||
await bot.send(ev, im)
|
||||
except ActionFailed as e:
|
||||
await bot.send(ev, "机器人发送消息失败:{}".format(e))
|
||||
logger.exception("发送食物信息失败")
|
||||
except Exception as e:
|
||||
await bot.send(ev, "发生错误 {},请检查后台输出。".format(e))
|
||||
logger.exception("获取食物信息错误")
|
||||
|
||||
|
||||
@sv.on_prefix('圣遗物')
|
||||
async def send_artifacts(bot: HoshinoBot, ev: CQEvent):
|
||||
try:
|
||||
message = ev.message.extract_plain_text()
|
||||
im = await artifacts_wiki(message)
|
||||
await bot.send(ev, im)
|
||||
except ActionFailed as e:
|
||||
await bot.send(ev, "机器人发送消息失败:{}".format(e))
|
||||
logger.exception("发送圣遗物信息失败")
|
||||
except Exception as e:
|
||||
await bot.send(ev, "发生错误 {},请检查后台输出。".format(e))
|
||||
logger.exception("获取圣遗物信息错误")
|
||||
|
||||
|
||||
@sv.on_prefix('天赋')
|
||||
async def send_talents(bot: HoshinoBot, ev: CQEvent):
|
||||
try:
|
||||
message = ev.message.extract_plain_text()
|
||||
name = ''.join(re.findall('[\u4e00-\u9fa5]', message))
|
||||
num = re.findall(r"[0-9]+", message)
|
||||
if len(num) == 1:
|
||||
im = await char_wiki(name, "talents", num[0])
|
||||
if isinstance(im,list):
|
||||
await hoshino_bot.send_group_forward_msg(group_id=ev.group_id, messages=im)
|
||||
return
|
||||
else:
|
||||
im = "参数不正确。"
|
||||
await bot.send(ev, im)
|
||||
except ActionFailed as e:
|
||||
await bot.send(ev, "机器人发送消息失败:{}".format(e))
|
||||
logger.exception("发送天赋信息失败")
|
||||
except Exception as e:
|
||||
await bot.send(ev, "发生错误 {},请检查后台输出。".format(e))
|
||||
logger.exception("获取天赋信息错误")
|
||||
|
||||
|
||||
@sv.on_prefix('武器')
|
||||
async def send_weapon(bot: HoshinoBot, ev: CQEvent):
|
||||
try:
|
||||
message = ev.message.extract_plain_text()
|
||||
name = ''.join(re.findall('[\u4e00-\u9fa5]', message))
|
||||
level = re.findall(r"[0-9]+", message)
|
||||
if len(level) == 1:
|
||||
im = await weapon_wiki(name, level=level[0])
|
||||
else:
|
||||
im = await weapon_wiki(name)
|
||||
await bot.send(ev, im, at_sender=True)
|
||||
except ActionFailed as e:
|
||||
await bot.send(ev, "机器人发送消息失败:{}".format(e))
|
||||
logger.exception("发送武器信息失败")
|
||||
except Exception as e:
|
||||
await bot.send(ev, "发生错误 {},请检查后台输出。".format(e))
|
||||
logger.exception("获取武器信息错误")
|
||||
|
||||
|
||||
@sv.on_prefix('角色')
|
||||
async def send_char(bot: HoshinoBot, ev: CQEvent):
|
||||
try:
|
||||
message = ev.message.extract_plain_text()
|
||||
message = message.replace(' ', "")
|
||||
name = ''.join(re.findall('[\u4e00-\u9fa5]', message))
|
||||
level = re.findall(r"[0-9]+", message)
|
||||
if len(level) == 1:
|
||||
im = await char_wiki(name, "char", level=level[0])
|
||||
else:
|
||||
im = await char_wiki(name)
|
||||
await bot.send(ev, im)
|
||||
except ActionFailed as e:
|
||||
await bot.send(ev, "机器人发送消息失败:{}".format(e))
|
||||
logger.exception("发送角色信息失败")
|
||||
except Exception as e:
|
||||
await bot.send(ev, "发生错误 {},请检查后台输出。".format(e))
|
||||
logger.exception("获取角色信息错误")
|
||||
|
||||
|
||||
@sv.on_prefix('命座')
|
||||
async def send_polar(bot: HoshinoBot, ev: CQEvent):
|
||||
try:
|
||||
message = ev.message.extract_plain_text()
|
||||
num = int(re.findall(r"\d+", message)[0]) # str
|
||||
m = ''.join(re.findall('[\u4e00-\u9fa5]', message))
|
||||
if num <= 0 or num > 6:
|
||||
await bot.send(ev, "你家{}有{}命?".format(m, num), at_sender=True)
|
||||
else:
|
||||
im = await char_wiki(m, "constellations", num)
|
||||
await bot.send(ev, im, at_sender=True)
|
||||
except ActionFailed as e:
|
||||
await bot.send(ev, "机器人发送消息失败:{}".format(e))
|
||||
logger.exception("发送命座信息失败")
|
||||
except Exception as e:
|
||||
await bot.send(ev, "发生错误 {},请检查后台输出。".format(e))
|
||||
logger.exception("获取命座信息错误")
|
||||
|
||||
|
||||
# 每日零点清空cookies使用缓存
|
||||
@sv.scheduled_job('cron', hour='0')
|
||||
async def clean_cache():
|
||||
await delete_cache()
|
||||
|
||||
|
||||
@sv.scheduled_job('cron', hour='2')
|
||||
async def draw_event():
|
||||
await draw_event_pic()
|
||||
|
||||
@sv.on_fullmatch('开始获取米游币')
|
||||
async def send_mihoyo_coin(bot: HoshinoBot, ev: CQEvent):
|
||||
await bot.send(ev, "开始操作……", at_sender=True)
|
||||
try:
|
||||
qid = ev.sender["user_id"]
|
||||
im_mes = await mihoyo_coin(int(qid))
|
||||
im = im_mes
|
||||
except TypeError or AttributeError:
|
||||
im = "没有找到绑定信息。"
|
||||
logger.exception("获取米游币失败")
|
||||
except Exception as e:
|
||||
im = "发生错误 {},请检查后台输出。".format(e)
|
||||
logger.exception("获取米游币失败")
|
||||
finally:
|
||||
try:
|
||||
await bot.send(ev, im, at_sender=True)
|
||||
except ActionFailed as e:
|
||||
await bot.send(ev, "机器人发送消息失败:{}".format(e.info['wording']))
|
||||
logger.exception("发送签到信息失败")
|
||||
|
||||
@sv.on_fullmatch('全部重签')
|
||||
async def _(bot: HoshinoBot, ev: CQEvent):
|
||||
try:
|
||||
if ev.user_id not in bot.config.SUPERUSERS:
|
||||
return
|
||||
await bot.send(ev, "已开始执行")
|
||||
await daily_sign()
|
||||
except ActionFailed as e:
|
||||
await bot.send(ev, "机器人发送消息失败:{}".format(e))
|
||||
except Exception as e:
|
||||
traceback.print_exc()
|
||||
await bot.send(ev, "发生错误 {},请检查后台输出。".format(e))
|
||||
|
||||
|
||||
# 每隔半小时检测树脂是否超过设定值
|
||||
@sv.scheduled_job('cron', minute="*/30")
|
||||
async def push():
|
||||
daily_data = await daily()
|
||||
if daily_data is not None:
|
||||
for i in daily_data:
|
||||
if i['gid'] == "on":
|
||||
await hoshino_bot.send_private_msg(user_id=i['qid'], message=i['message'])
|
||||
else:
|
||||
await hoshino_bot.send_group_msg(group_id=i['gid'], message=f"[CQ:at,qq={i['qid']}]"
|
||||
+ "\n" + i['message'])
|
||||
else:
|
||||
pass
|
||||
|
||||
|
||||
# 每日零点半进行米游社签到
|
||||
@sv.scheduled_job('cron', hour='0', minute="30")
|
||||
async def daily_sign_schedule():
|
||||
await daily_sign()
|
||||
|
||||
|
||||
async def daily_sign():
|
||||
conn = sqlite3.connect('ID_DATA.db')
|
||||
c = conn.cursor()
|
||||
cursor = c.execute(
|
||||
"SELECT * FROM NewCookiesTable WHERE StatusB != ?", ("off",))
|
||||
c_data = cursor.fetchall()
|
||||
temp_list = []
|
||||
for row in c_data:
|
||||
im = await sign(str(row[0]))
|
||||
if row[4] == "on":
|
||||
try:
|
||||
await hoshino_bot.send_private_msg(user_id=row[2], message=im)
|
||||
except:
|
||||
logger.exception(f"{im} Error")
|
||||
else:
|
||||
message = f"[CQ:at,qq={row[2]}]\n{im}"
|
||||
if await config_check("SignReportSimple"):
|
||||
for i in temp_list:
|
||||
if row[4] == i["push_group"]:
|
||||
if im == "签到失败,请检查Cookies是否失效。" or im.startswith("网络有点忙,请稍后再试~!"):
|
||||
i["failed"] += 1
|
||||
i["push_message"] += "\n" + message
|
||||
else:
|
||||
i["success"] += 1
|
||||
break
|
||||
else:
|
||||
if im == "签到失败,请检查Cookies是否失效。":
|
||||
temp_list.append({"push_group": row[4], "push_message": message, "success": 0, "failed": 1})
|
||||
else:
|
||||
temp_list.append({"push_group": row[4], "push_message": "", "success": 1, "failed": 0})
|
||||
else:
|
||||
for i in temp_list:
|
||||
if row[4] == i["push_group"] and i["num"] < 4:
|
||||
i["push_message"] += "\n" + message
|
||||
i["num"] += 1
|
||||
break
|
||||
else:
|
||||
temp_list.append({"push_group": row[4], "push_message": message, "num": 1})
|
||||
await asyncio.sleep(6 + random.randint(1, 3))
|
||||
if await config_check("SignReportSimple"):
|
||||
for i in temp_list:
|
||||
try:
|
||||
report = "以下为签到失败报告:{}".format(i["push_message"]) if i["push_message"] != "" else ""
|
||||
await hoshino_bot.send_group_msg(group_id=i["push_group"],
|
||||
message="今日自动签到已完成!\n本群共签到成功{}人,"
|
||||
"共签到失败{}人。{}".format(i["success"], i["failed"], report))
|
||||
except:
|
||||
logger.exception("签到报告发送失败:{}".format(i["push_message"]))
|
||||
await asyncio.sleep(4 + random.randint(1, 3))
|
||||
else:
|
||||
for i in temp_list:
|
||||
try:
|
||||
await hoshino_bot.send_group_msg(group_id=i["push_group"], message=i["push_message"])
|
||||
except:
|
||||
logger.exception("签到报告发送失败:{}".format(i["push_message"]))
|
||||
await asyncio.sleep(4 + random.randint(1, 3))
|
||||
conn.close()
|
||||
return
|
||||
|
||||
|
||||
# 私聊事件
|
||||
@hoshino_bot.on_message('private')
|
||||
async def setting(ctx):
|
||||
message = ctx['raw_message']
|
||||
sid = int(ctx["self_id"])
|
||||
userid = int(ctx["sender"]["user_id"])
|
||||
gid = 0
|
||||
if '添加 ' in message:
|
||||
try:
|
||||
mes = message.replace('添加 ', '')
|
||||
im = await deal_ck(mes, userid)
|
||||
await hoshino_bot.send_msg(self_id=sid, user_id=userid, group_id=gid,
|
||||
message=im)
|
||||
except ActionFailed as e:
|
||||
await hoshino_bot.send_msg(self_id=sid, user_id=userid, group_id=gid,
|
||||
message="机器人发送消息失败:{}".format(e))
|
||||
logger.exception("发送Cookie校验信息失败")
|
||||
except Exception as e:
|
||||
await hoshino_bot.send_msg(self_id=sid, user_id=userid, group_id=gid,
|
||||
message='校验失败!请输入正确的Cookies!\n错误信息为{}'.format(e))
|
||||
logger.exception("Cookie校验失败")
|
||||
elif '开启推送' in message:
|
||||
try:
|
||||
uid = await select_db(userid, mode="uid")
|
||||
im = await open_push(int(uid[0]), userid, "on", "StatusA")
|
||||
await hoshino_bot.send_msg(self_id=sid, user_id=userid, group_id=gid, message=im)
|
||||
except ActionFailed as e:
|
||||
await hoshino_bot.send_msg(self_id=sid, user_id=userid, group_id=gid,
|
||||
message="机器人发送消息失败:{}".format(e))
|
||||
logger.exception("私聊)发送开启推送信息失败")
|
||||
except Exception:
|
||||
await hoshino_bot.send_msg(self_id=sid, user_id=userid, group_id=gid, message="未找到uid绑定记录。")
|
||||
logger.exception("开启推送失败")
|
||||
elif '关闭推送' in message:
|
||||
try:
|
||||
uid = await select_db(userid, mode="uid")
|
||||
im = await open_push(int(uid[0]), userid, "off", "StatusA")
|
||||
await hoshino_bot.send_msg(self_id=sid, user_id=userid, group_id=gid, message=im)
|
||||
except ActionFailed as e:
|
||||
await hoshino_bot.send_msg(self_id=sid, user_id=userid, group_id=gid,
|
||||
message="机器人发送消息失败:{}".format(e))
|
||||
logger.exception("私聊)发送关闭推送信息失败")
|
||||
except Exception:
|
||||
await hoshino_bot.send_msg(self_id=sid, user_id=userid, group_id=gid, message="未找到uid绑定记录。")
|
||||
logger.exception("关闭推送失败")
|
||||
elif '开启自动签到' in message:
|
||||
try:
|
||||
uid = await select_db(userid, mode="uid")
|
||||
im = await open_push(int(uid[0]), userid, "on", "StatusB")
|
||||
await hoshino_bot.send_msg(self_id=sid, user_id=userid, group_id=gid, message=im)
|
||||
except ActionFailed as e:
|
||||
await hoshino_bot.send_msg(self_id=sid, user_id=userid, group_id=gid,
|
||||
message="机器人发送消息失败:{}".format(e))
|
||||
logger.exception("私聊)发送开启自动签到信息失败")
|
||||
except Exception:
|
||||
traceback.print_exc()
|
||||
await hoshino_bot.send_msg(self_id=sid, user_id=userid, group_id=gid, message="未找到uid绑定记录。")
|
||||
logger.exception("开启自动签到失败")
|
||||
elif '关闭自动签到' in message:
|
||||
try:
|
||||
uid = await select_db(userid, mode="uid")
|
||||
im = await open_push(int(uid[0]), userid, "off", "StatusA")
|
||||
await hoshino_bot.send_msg(self_id=sid, user_id=userid, group_id=gid, message=im)
|
||||
except ActionFailed as e:
|
||||
await hoshino_bot.send_msg(self_id=sid, user_id=userid, group_id=gid,
|
||||
message="机器人发送消息失败:{}".format(e))
|
||||
logger.exception("私聊)发送关闭自动签到信息失败")
|
||||
except Exception:
|
||||
traceback.print_exc()
|
||||
await hoshino_bot.send_msg(self_id=sid, user_id=userid, group_id=gid, message="未找到uid绑定记录。")
|
||||
logger.exception("关闭自动签到失败")
|
||||
|
||||
|
||||
# 群聊开启 自动签到 和 推送树脂提醒 功能
|
||||
@sv.on_prefix('开启')
|
||||
async def open_switch_func(bot: HoshinoBot, ev: CQEvent):
|
||||
try:
|
||||
message = ev.message.extract_plain_text()
|
||||
m = ''.join(re.findall('[\u4e00-\u9fa5]', message))
|
||||
|
||||
qid = ev.sender["user_id"]
|
||||
at = re.search(r"\[CQ:at,qq=(\d*)]", message)
|
||||
|
||||
if m == "自动签到":
|
||||
try:
|
||||
if at:
|
||||
if at and at.group(1) != qid:
|
||||
await bot.send(ev, "你没有权限。", at_sender=True)
|
||||
return
|
||||
gid = ev.group_id
|
||||
uid = await select_db(ev.sender['user_id'], mode="uid")
|
||||
im = await open_push(int(uid[0]), ev.sender['user_id'], str(gid), "StatusB")
|
||||
await bot.send(ev, im, at_sender=True)
|
||||
except ActionFailed as e:
|
||||
await bot.send(ev, "机器人发送消息失败:{}".format(e))
|
||||
logger.exception("发送开启自动签到信息失败")
|
||||
except Exception:
|
||||
await bot.send(ev, "未绑定uid信息!", at_sender=True)
|
||||
logger.exception("开启自动签到失败")
|
||||
elif m == "推送":
|
||||
try:
|
||||
if at:
|
||||
if at and at.group(1) != qid:
|
||||
await bot.send(ev, "你没有权限。", at_sender=True)
|
||||
return
|
||||
gid = ev.group_id
|
||||
uid = await select_db(ev.sender['user_id'], mode="uid")
|
||||
im = await open_push(int(uid[0]), ev.sender['user_id'], str(gid), "StatusA")
|
||||
await bot.send(ev, im, at_sender=True)
|
||||
except ActionFailed as e:
|
||||
await bot.send(ev, "机器人发送消息失败:{}".format(e))
|
||||
logger.exception("发送开启推送信息失败")
|
||||
except Exception:
|
||||
await bot.send(ev, "未绑定uid信息!", at_sender=True)
|
||||
logger.exception("开启推送失败")
|
||||
elif m == "简洁签到报告":
|
||||
try:
|
||||
if qid in bot.config.SUPERUSERS:
|
||||
_ = await config_check("SignReportSimple", "OPEN")
|
||||
await bot.send(ev, "成功!", at_sender=True)
|
||||
else:
|
||||
return
|
||||
except ActionFailed as e:
|
||||
await bot.send(ev, "机器人发送消息失败:{}".format(e))
|
||||
logger.exception("发送设置成功信息失败")
|
||||
except Exception as e:
|
||||
await bot.send(ev, "发生错误 {},请检查后台输出。".format(e))
|
||||
logger.exception("设置简洁签到报告失败")
|
||||
except Exception as e:
|
||||
await bot.send(ev, "发生错误 {},请检查后台输出。".format(e))
|
||||
logger.exception("开启功能失败")
|
||||
|
||||
|
||||
# 群聊关闭 自动签到 和 推送树脂提醒 功能
|
||||
@sv.on_prefix('关闭')
|
||||
async def close_switch_func(bot: HoshinoBot, ev: CQEvent):
|
||||
try:
|
||||
message = ev.message.extract_plain_text()
|
||||
m = ''.join(re.findall('[\u4e00-\u9fa5]', message))
|
||||
|
||||
qid = ev.sender["user_id"]
|
||||
at = re.search(r"\[CQ:at,qq=(\d*)]", message)
|
||||
|
||||
if m == "自动签到":
|
||||
try:
|
||||
if at:
|
||||
if at and at.group(1) != qid:
|
||||
await bot.send(ev, "你没有权限。", at_sender=True)
|
||||
return
|
||||
uid = await select_db(ev.sender['user_id'], mode="uid")
|
||||
im = await open_push(int(uid[0]), ev.sender['user_id'], "off", "StatusB")
|
||||
await bot.send(ev, im, at_sender=True)
|
||||
except ActionFailed as e:
|
||||
await bot.send(ev, "机器人发送消息失败:{}".format(e))
|
||||
logger.exception("发送关闭自动签到信息失败")
|
||||
except Exception:
|
||||
await bot.send(ev, "未绑定uid信息!", at_sender=True)
|
||||
logger.exception("关闭自动签到失败")
|
||||
elif m == "推送":
|
||||
try:
|
||||
if at:
|
||||
if at and at.group(1) != qid:
|
||||
await bot.send(ev, "你没有权限。", at_sender=True)
|
||||
return
|
||||
uid = await select_db(ev.sender['user_id'], mode="uid")
|
||||
im = await open_push(int(uid[0]), ev.sender['user_id'], "off", "StatusA")
|
||||
await bot.send(ev, im, at_sender=True)
|
||||
except ActionFailed as e:
|
||||
await bot.send(ev, "机器人发送消息失败:{}".format(e))
|
||||
logger.exception("发送关闭推送信息失败")
|
||||
except Exception:
|
||||
await bot.send(ev, "未绑定uid信息!", at_sender=True)
|
||||
logger.exception("关闭推送失败")
|
||||
elif m == "简洁签到报告":
|
||||
try:
|
||||
if qid in bot.config.SUPERUSERS:
|
||||
_ = await config_check("SignReportSimple", "CLOSED")
|
||||
await bot.send(ev, "成功!", at_sender=True)
|
||||
else:
|
||||
return
|
||||
except ActionFailed as e:
|
||||
await bot.send("机器人发送消息失败:{}".format(e))
|
||||
logger.exception("发送设置成功信息失败")
|
||||
except Exception as e:
|
||||
await bot.send("发生错误 {},请检查后台输出。".format(e))
|
||||
logger.exception("设置简洁签到报告失败")
|
||||
except Exception as e:
|
||||
await bot.send(ev, "发生错误 {},请检查后台输出。".format(e))
|
||||
logger.exception("关闭功能失败")
|
||||
|
||||
|
||||
# 群聊内 每月统计 功能
|
||||
@sv.on_fullmatch('每月统计')
|
||||
async def send_monthly_data(bot: HoshinoBot, ev: CQEvent):
|
||||
try:
|
||||
uid = await select_db(ev.sender['user_id'], mode="uid")
|
||||
uid = uid[0]
|
||||
im = await award(uid)
|
||||
await bot.send(ev, im, at_sender=True)
|
||||
except ActionFailed as e:
|
||||
await bot.send(ev, "机器人发送消息失败:{}".format(e))
|
||||
logger.exception("发送每月统计信息失败")
|
||||
except Exception:
|
||||
await bot.send(ev, '未找到绑定信息', at_sender=True)
|
||||
logger.exception("获取每月统计失败")
|
||||
|
||||
|
||||
# 群聊内 签到 功能
|
||||
@sv.on_fullmatch('签到')
|
||||
async def get_sing_func(bot: HoshinoBot, ev: CQEvent):
|
||||
try:
|
||||
uid = await select_db(ev.sender['user_id'], mode="uid")
|
||||
uid = uid[0]
|
||||
im = await sign(uid)
|
||||
await bot.send(ev, im, at_sender=True)
|
||||
except ActionFailed as e:
|
||||
await bot.send(ev, "机器人发送消息失败:{}".format(e))
|
||||
logger.exception("发送签到信息失败")
|
||||
except Exception:
|
||||
await bot.send(ev, '未找到绑定信息', at_sender=True)
|
||||
logger.exception("签到失败")
|
||||
|
||||
|
||||
# 群聊内 校验Cookies 是否正常的功能,不正常自动删掉
|
||||
@sv.on_fullmatch('校验全部Cookies')
|
||||
async def check_cookies(bot: HoshinoBot, ev: CQEvent):
|
||||
try:
|
||||
raw_mes = await check_db()
|
||||
im = raw_mes[0]
|
||||
await bot.send(ev, im)
|
||||
for i in raw_mes[1]:
|
||||
await bot.send_private_msg(user_id=i[0],
|
||||
message="您绑定的Cookies(uid{})已失效,以下功能将会受到影响:\n查看完整信息列表\n"
|
||||
"查看深渊配队\n自动签到/当前状态/每月统计\n"
|
||||
"请及时重新绑定Cookies并重新开关相应功能。".format(i[1]))
|
||||
await asyncio.sleep(3 + random.randint(1, 3))
|
||||
except ActionFailed as e:
|
||||
await bot.send(ev, "机器人发送消息失败:{}".format(e))
|
||||
logger.exception("发送Cookie校验信息失败")
|
||||
except Exception as e:
|
||||
await bot.send(ev, "发生错误 {},请检查后台输出。".format(e))
|
||||
logger.exception("Cookie校验错误")
|
||||
|
||||
|
||||
# 群聊内 查询当前树脂状态以及派遣状态 的命令
|
||||
@sv.on_fullmatch('当前状态')
|
||||
async def send_daily_data(bot: HoshinoBot, ev: CQEvent):
|
||||
try:
|
||||
uid = await select_db(ev.sender['user_id'], mode="uid")
|
||||
uid = uid[0]
|
||||
mes = await daily("ask", uid)
|
||||
im = mes[0]['message']
|
||||
except Exception:
|
||||
im = "没有找到绑定信息。"
|
||||
logger.exception("获取当前状态失败")
|
||||
|
||||
try:
|
||||
await bot.send(ev, im, at_sender=True)
|
||||
except ActionFailed as e:
|
||||
await bot.send(ev, "机器人发送消息失败:{}".format(e))
|
||||
logger.exception("发送当前状态信息失败")
|
||||
|
||||
|
||||
# 群聊内 查询uid 的命令
|
||||
@sv.on_prefix('uid')
|
||||
async def send_uid_info(bot: HoshinoBot, ev: CQEvent):
|
||||
try:
|
||||
image = re.search(r"\[CQ:image,file=(.*),url=(.*)]", str(ev.message))
|
||||
message = ev.message.extract_plain_text()
|
||||
uid = re.findall(r"\d+", message)[0] # str
|
||||
m = ''.join(re.findall('[\u4e00-\u9fa5]', message))
|
||||
if m == "深渊":
|
||||
try:
|
||||
if len(re.findall(r"\d+", message)) == 2:
|
||||
floor_num = re.findall(r"\d+", message)[1]
|
||||
im = await draw_abyss_pic(uid, ev.sender['nickname'], floor_num, image)
|
||||
await bot.send(ev, f"[CQ:image,file={im}]")
|
||||
else:
|
||||
im = await draw_abyss0_pic(uid, ev.sender['nickname'], image)
|
||||
await bot.send(ev, f"[CQ:image,file={im}]")
|
||||
except ActionFailed as e:
|
||||
await bot.send(ev, "机器人发送消息失败:{}".format(e))
|
||||
logger.exception("发送uid深渊信息失败")
|
||||
except TypeError:
|
||||
await bot.send(ev, "获取失败,可能是Cookies失效或者未打开米游社角色详情开关。")
|
||||
logger.exception("深渊数据获取失败(Cookie失效/不公开信息)")
|
||||
except Exception as e:
|
||||
await bot.send(ev, "获取失败,有可能是数据状态有问题,\n{}\n请检查后台输出。".format(e))
|
||||
logger.exception("深渊数据获取失败(数据状态问题)")
|
||||
elif m == "上期深渊":
|
||||
try:
|
||||
if len(re.findall(r"\d+", message)) == 2:
|
||||
floor_num = re.findall(r"\d+", message)[1]
|
||||
im = await draw_abyss_pic(uid, ev.sender['nickname'], floor_num, image, 2, "2")
|
||||
await bot.send(ev, f"[CQ:image,file={im}]")
|
||||
else:
|
||||
im = await draw_abyss0_pic(uid, ev.sender['nickname'], image, 2, "2")
|
||||
await bot.send(ev, f"[CQ:image,file={im}]")
|
||||
except ActionFailed as e:
|
||||
await bot.send(ev, "机器人发送消息失败:{}".format(e))
|
||||
logger.exception("发送uid上期深渊信息失败")
|
||||
except TypeError:
|
||||
await bot.send(ev, "获取失败,可能是Cookies失效或者未打开米游社角色详情开关。")
|
||||
logger.exception("上期深渊数据获取失败(Cookie失效/不公开信息)")
|
||||
except Exception as e:
|
||||
await bot.send(ev, "获取失败,有可能是数据状态有问题,\n{}\n请检查后台输出。".format(e))
|
||||
logger.exception("上期深渊数据获取失败(数据状态问题)")
|
||||
else:
|
||||
try:
|
||||
im = await draw_pic(uid, ev.sender['nickname'], image, 2)
|
||||
await bot.send(ev, f"[CQ:image,file={im}]")
|
||||
except ActionFailed as e:
|
||||
await bot.send(ev, "机器人发送消息失败:{}".format(e))
|
||||
logger.exception("发送uid信息失败")
|
||||
except TypeError:
|
||||
await bot.send(ev, "获取失败,可能是Cookies失效或者未打开米游社角色详情开关。")
|
||||
logger.exception("数据获取失败(Cookie失效/不公开信息)")
|
||||
except Exception as e:
|
||||
await bot.send(ev, "获取失败,有可能是数据状态有问题,\n{}\n请检查后台输出。".format(e))
|
||||
logger.exception("数据获取失败(数据状态问题)")
|
||||
except Exception as e:
|
||||
await bot.send(ev, "发生错误 {},请检查后台输出。".format(e))
|
||||
logger.exception("uid查询异常")
|
||||
|
||||
|
||||
# 群聊内 绑定uid 的命令,会绑定至当前qq号上
|
||||
@sv.on_prefix('绑定uid')
|
||||
async def link_uid_to_qq(bot: HoshinoBot, ev: CQEvent):
|
||||
try:
|
||||
message = ev.message.extract_plain_text()
|
||||
uid = re.findall(r"\d+", message)[0] # str
|
||||
await connect_db(ev.sender['user_id'], uid)
|
||||
await bot.send(ev, '绑定uid成功!', at_sender=True)
|
||||
except ActionFailed as e:
|
||||
await bot.send(ev, "机器人发送消息失败:{}".format(e))
|
||||
logger.exception("发送绑定信息失败")
|
||||
except Exception as e:
|
||||
await bot.send(ev, "发生错误 {},请检查后台输出。".format(e))
|
||||
logger.exception("绑定uid异常")
|
||||
|
||||
|
||||
# 群聊内 绑定米游社通行证 的命令,会绑定至当前qq号上,和绑定uid不冲突,两者可以同时绑定
|
||||
@sv.on_prefix('绑定mys')
|
||||
async def link_mihoyo_bbs_to_qq(bot: HoshinoBot, ev: CQEvent):
|
||||
try:
|
||||
message = ev.message.extract_plain_text()
|
||||
mys = re.findall(r"\d+", message)[0] # str
|
||||
await connect_db(ev.sender['user_id'], None, mys)
|
||||
await bot.send(ev, '绑定米游社id成功!', at_sender=True)
|
||||
except ActionFailed as e:
|
||||
await bot.send(ev, "机器人发送消息失败:{}".format(e))
|
||||
logger.exception("发送绑定信息失败")
|
||||
except Exception as e:
|
||||
await bot.send(ev, "发生错误 {},请检查后台输出。".format(e))
|
||||
logger.exception("绑定米游社通行证异常")
|
||||
|
||||
|
||||
# 群聊内 绑定过uid/mysid的情况下,可以查询,默认优先调用米游社通行证,多出世界等级一个参数
|
||||
@sv.on_prefix('查询')
|
||||
async def get_info(bot, ev):
|
||||
try:
|
||||
image = re.search(r"\[CQ:image,file=(.*),url=(.*)]", str(ev.message))
|
||||
at = re.search(r"\[CQ:at,qq=(\d*)]", str(ev.raw_message.strip()))
|
||||
message = ev.message.extract_plain_text()
|
||||
if at:
|
||||
qid = at.group(1)
|
||||
mi = await bot.get_group_member_info(group_id=ev.group_id, user_id=qid)
|
||||
nickname = mi["nickname"]
|
||||
uid = await select_db(qid)
|
||||
else:
|
||||
nickname = ev.sender['nickname']
|
||||
uid = await select_db(ev.sender['user_id'])
|
||||
|
||||
m = ''.join(re.findall('[\u4e00-\u9fa5]', message))
|
||||
if uid:
|
||||
if m == "深渊":
|
||||
try:
|
||||
if len(re.findall(r"\d+", message)) == 1:
|
||||
floor_num = re.findall(r"\d+", message)[0]
|
||||
im = await draw_abyss_pic(uid[0], nickname, floor_num, image, uid[1])
|
||||
await bot.send(ev, f"[CQ:image,file={im}]")
|
||||
else:
|
||||
im = await draw_abyss0_pic(uid[0], nickname, image, uid[1])
|
||||
await bot.send(ev, f"[CQ:image,file={im}]")
|
||||
except ActionFailed as e:
|
||||
await bot.send(ev, "机器人发送消息失败:{}".format(e))
|
||||
logger.exception("发送uid深渊信息失败")
|
||||
except TypeError:
|
||||
await bot.send(ev, "获取失败,可能是Cookies失效或者未打开米游社角色详情开关。")
|
||||
logger.exception("深渊数据获取失败(Cookie失效/不公开信息)")
|
||||
except Exception as e:
|
||||
await bot.send(ev, "获取失败,有可能是数据状态有问题,\n{}\n请检查后台输出。".format(e))
|
||||
logger.exception("深渊数据获取失败(数据状态问题)")
|
||||
elif m == "上期深渊":
|
||||
try:
|
||||
if len(re.findall(r"\d+", message)) == 1:
|
||||
floor_num = re.findall(r"\d+", message)[0]
|
||||
im = await draw_abyss_pic(uid[0], nickname, floor_num, image, uid[1], "2")
|
||||
await bot.send(ev, f"[CQ:image,file={im}]")
|
||||
else:
|
||||
im = await draw_abyss0_pic(uid[0], nickname, image, uid[1], "2")
|
||||
await bot.send(ev, f"[CQ:image,file={im}]")
|
||||
except ActionFailed as e:
|
||||
await bot.send(ev, "机器人发送消息失败:{}".format(e))
|
||||
logger.exception("发送uid上期深渊信息失败")
|
||||
except TypeError:
|
||||
await bot.send(ev, "获取失败,可能是Cookies失效或者未打开米游社角色详情开关。")
|
||||
logger.exception("上期深渊数据获取失败(Cookie失效/不公开信息)")
|
||||
except Exception as e:
|
||||
await bot.send(ev, "获取失败,有可能是数据状态有问题,\n{}\n请检查后台输出。".format(e))
|
||||
logger.exception("上期深渊数据获取失败(数据状态问题)")
|
||||
elif m == "词云":
|
||||
try:
|
||||
im = await draw_word_cloud(uid[0], image, uid[1])
|
||||
await bot.send(ev, f"[CQ:image,file={im}]")
|
||||
except ActionFailed as e:
|
||||
await bot.send(ev, "机器人发送消息失败:{}".format(e))
|
||||
logger.exception("发送uid词云信息失败")
|
||||
except TypeError:
|
||||
await bot.send(ev, "获取失败,可能是Cookies失效或者未打开米游社角色详情开关。")
|
||||
logger.exception("词云数据获取失败(Cookie失效/不公开信息)")
|
||||
except Exception as e:
|
||||
await bot.send(ev, "获取失败,有可能是数据状态有问题,\n{}\n请检查后台输出。".format(e))
|
||||
logger.exception("词云数据获取失败(数据状态问题)")
|
||||
elif m == "":
|
||||
try:
|
||||
bg = await draw_pic(uid[0], nickname, image, uid[1])
|
||||
await bot.send(ev, f"[CQ:image,file={bg}]")
|
||||
except ActionFailed as e:
|
||||
await bot.send(ev, "机器人发送消息失败:{}".format(e))
|
||||
logger.exception("发送uid信息失败")
|
||||
except TypeError:
|
||||
await bot.send(ev, "获取失败,可能是Cookies失效或者未打开米游社角色详情开关。")
|
||||
logger.exception("数据获取失败(Cookie失效/不公开信息)")
|
||||
except Exception as e:
|
||||
await bot.send(ev, "获取失败,有可能是数据状态有问题,\n{}\n请检查后台输出。".format(e))
|
||||
logger.exception("数据获取失败(数据状态问题)")
|
||||
else:
|
||||
pass
|
||||
else:
|
||||
await bot.send(ev, '未找到绑定记录!')
|
||||
except Exception as e:
|
||||
await bot.send(ev, "发生错误 {},请检查后台输出。".format(e))
|
||||
logger.exception("查询异常")
|
||||
|
||||
|
||||
# 群聊内 查询米游社通行证 的命令
|
||||
@sv.on_prefix('mys')
|
||||
async def send_mihoyo_bbs_info(bot: HoshinoBot, ev: CQEvent):
|
||||
try:
|
||||
image = re.search(r"\[CQ:image,file=(.*),url=(.*)]", str(ev.message))
|
||||
message = ev.message.extract_plain_text()
|
||||
uid = re.findall(r"\d+", message)[0] # str
|
||||
m = ''.join(re.findall('[\u4e00-\u9fa5]', message))
|
||||
if m == "深渊":
|
||||
try:
|
||||
if len(re.findall(r"\d+", message)) == 2:
|
||||
floor_num = re.findall(r"\d+", message)[1]
|
||||
im = await draw_abyss_pic(uid, ev.sender['nickname'], floor_num, image, 3)
|
||||
await bot.send(ev, f"[CQ:image,file={im}]")
|
||||
else:
|
||||
im = await draw_abyss0_pic(uid, ev.sender['nickname'], image, 3)
|
||||
await bot.send(ev, f"[CQ:image,file={im}]")
|
||||
except ActionFailed as e:
|
||||
await bot.send(ev, "机器人发送消息失败:{}".format(e))
|
||||
logger.exception("发送米游社深渊信息失败")
|
||||
except TypeError:
|
||||
await bot.send(ev, "获取失败,可能是Cookies失效或者未打开米游社角色详情开关。")
|
||||
logger.exception("深渊数据获取失败(Cookie失效/不公开信息)")
|
||||
except Exception as e:
|
||||
await bot.send(ev, "获取失败,有可能是数据状态有问题,\n{}\n请检查后台输出。".format(e))
|
||||
logger.exception("深渊数据获取失败(数据状态问题)")
|
||||
elif m == "上期深渊":
|
||||
try:
|
||||
if len(re.findall(r"\d+", message)) == 1:
|
||||
floor_num = re.findall(r"\d+", message)[0]
|
||||
im = await draw_abyss_pic(uid, ev.sender['nickname'], floor_num, image, 3, "2")
|
||||
await bot.send(ev, f"[CQ:image,file={im}]")
|
||||
else:
|
||||
im = await draw_abyss0_pic(uid, ev.sender['nickname'], image, 3, "2")
|
||||
await bot.send(ev, f"[CQ:image,file={im}]")
|
||||
except ActionFailed as e:
|
||||
await bot.send(ev, "机器人发送消息失败:{}".format(e))
|
||||
logger.exception("发送米游社上期深渊信息失败")
|
||||
except TypeError:
|
||||
await bot.send(ev, "获取失败,可能是Cookies失效或者未打开米游社角色详情开关。")
|
||||
logger.exception("上期深渊数据获取失败(Cookie失效/不公开信息)")
|
||||
except Exception as e:
|
||||
await bot.send(ev, "获取失败,有可能是数据状态有问题,\n{}\n请检查后台输出。".format(e))
|
||||
logger.exception("上期深渊数据获取失败(数据状态问题)")
|
||||
else:
|
||||
try:
|
||||
im = await draw_pic(uid, ev.sender['nickname'], image, 3)
|
||||
await bot.send(ev, f"[CQ:image,file={im}]")
|
||||
except ActionFailed as e:
|
||||
await bot.send(ev, "机器人发送消息失败:{}".format(e))
|
||||
logger.exception("发送米游社信息失败")
|
||||
except TypeError:
|
||||
await bot.send(ev, "获取失败,可能是Cookies失效或者未打开米游社角色详情开关。")
|
||||
logger.exception("米游社数据获取失败(Cookie失效/不公开信息)")
|
||||
except Exception as e:
|
||||
await bot.send(ev, "获取失败,有可能是数据状态有问题,\n{}\n请检查后台输出。".format(e))
|
||||
logger.exception("米游社数据获取失败(数据状态问题)")
|
||||
except Exception as e:
|
||||
await bot.send(ev, "发生错误 {},请检查后台输出。".format(e))
|
||||
logger.exception("米游社查询异常")
|
662
getDB.py
@ -1,662 +0,0 @@
|
||||
import sqlite3
|
||||
import sys,datetime
|
||||
|
||||
from httpx import AsyncClient
|
||||
from shutil import copyfile
|
||||
|
||||
from nonebot import *
|
||||
from bs4 import BeautifulSoup
|
||||
import requests,random,os,json,re
|
||||
import hoshino
|
||||
import asyncio
|
||||
import time
|
||||
import string
|
||||
import hashlib
|
||||
import base64
|
||||
|
||||
mhyVersion = "2.11.1"
|
||||
|
||||
FILE_PATH = os.path.abspath(os.path.join(os.getcwd(), "hoshino"))
|
||||
BASE_PATH = os.path.dirname(__file__)
|
||||
BASE2_PATH = os.path.join(BASE_PATH,'mys')
|
||||
INDEX_PATH = os.path.join(BASE2_PATH,'index')
|
||||
|
||||
async def get_alots(qid):
|
||||
conn = sqlite3.connect('ID_DATA.db')
|
||||
c = conn.cursor()
|
||||
c.execute('''CREATE TABLE IF NOT EXISTS UseridDict
|
||||
(QID INT PRIMARY KEY NOT NULL,
|
||||
lots TEXT,
|
||||
cache TEXT,
|
||||
permission TEXT,
|
||||
Status TEXT,
|
||||
Subscribe TEXT,
|
||||
Extra TEXT);''')
|
||||
cursor = c.execute("SELECT * from UseridDict WHERE QID = ?",(qid,))
|
||||
c_data = cursor.fetchall()
|
||||
with open(os.path.join(INDEX_PATH,'lots.txt'),"r") as f:
|
||||
raw_data = f.read()
|
||||
raw_data = raw_data.replace(' ', "").split('-')
|
||||
|
||||
if len(c_data) == 0:
|
||||
num = random.randint(1,len(raw_data)-1)
|
||||
data = raw_data[num]
|
||||
c.execute("INSERT OR IGNORE INTO UseridDict (QID,lots) \
|
||||
VALUES (?, ?)",(qid,str(num)))
|
||||
else:
|
||||
if c_data[0][1] == None:
|
||||
num = random.randint(0,len(raw_data)-1)
|
||||
data = raw_data[num]
|
||||
c.execute("UPDATE UseridDict SET lots = ? WHERE QID=?",(str(num),qid))
|
||||
else:
|
||||
num = int(c_data[0][1])
|
||||
data = raw_data[num]
|
||||
conn.commit()
|
||||
conn.close()
|
||||
return data
|
||||
|
||||
async def OpenPush(uid,qid,status,mode):
|
||||
conn = sqlite3.connect('ID_DATA.db')
|
||||
c = conn.cursor()
|
||||
cursor = c.execute("SELECT * from NewCookiesTable WHERE UID = ?",(uid,))
|
||||
c_data = cursor.fetchall()
|
||||
if len(c_data) != 0:
|
||||
try:
|
||||
c.execute("UPDATE NewCookiesTable SET {s} = ?,QID = ? WHERE UID=?".format(s = mode),(status,qid,uid))
|
||||
conn.commit()
|
||||
conn.close()
|
||||
return "成功!"
|
||||
except:
|
||||
return "未找到Ck绑定记录。"
|
||||
else:
|
||||
return "未找到Ck绑定记录。"
|
||||
|
||||
async def CheckDB():
|
||||
str = ''
|
||||
conn = sqlite3.connect('ID_DATA.db')
|
||||
c = conn.cursor()
|
||||
cursor = c.execute("SELECT UID,Cookies from NewCookiesTable")
|
||||
c_data = cursor.fetchall()
|
||||
for row in c_data:
|
||||
try:
|
||||
aid = re.search(r"account_id=(\d*)",row[1])
|
||||
mysid_data = aid.group(0).split('=')
|
||||
mysid = mysid_data[1]
|
||||
mys_data = await GetMysInfo(mysid,row[1])
|
||||
for i in mys_data['data']['list']:
|
||||
if i['game_id'] != 2:
|
||||
mys_data['data']['list'].remove(i)
|
||||
uid = mys_data['data']['list'][0]['game_role_id']
|
||||
str = str + f"uid{row[0]}/mysid{mysid}的Cookies是正常的!\n"
|
||||
except:
|
||||
str = str + f"uid{row[0]}的Cookies是异常的!已删除该条Cookies!\n"
|
||||
c.execute("DELETE from NewCookiesTable where UID=?",(row[0],))
|
||||
test = c.execute("SELECT count(*) FROM sqlite_master WHERE type='table' AND name = 'CookiesCache'")
|
||||
if test == 0:
|
||||
pass
|
||||
else:
|
||||
c.execute("DELETE from CookiesCache where Cookies=?",(row[1],))
|
||||
conn.commit()
|
||||
conn.close()
|
||||
return str
|
||||
|
||||
async def TransDB():
|
||||
str = ''
|
||||
conn = sqlite3.connect('ID_DATA.db')
|
||||
c = conn.cursor()
|
||||
test = c.execute("SELECT count(*) FROM sqlite_master WHERE type='table' AND name = 'CookiesTable'")
|
||||
if test == 0:
|
||||
conn.commit()
|
||||
conn.close()
|
||||
return "你没有需要迁移的数据库。"
|
||||
else:
|
||||
c.execute('''CREATE TABLE IF NOT EXISTS NewCookiesTable
|
||||
(UID INT PRIMARY KEY NOT NULL,
|
||||
Cookies TEXT,
|
||||
QID INT,
|
||||
StatusA TEXT,
|
||||
StatusB TEXT,
|
||||
StatusC TEXT,
|
||||
NUM INT,
|
||||
Extra TEXT);''')
|
||||
cursor = c.execute("SELECT * from CookiesTable")
|
||||
c_data = cursor.fetchall()
|
||||
for row in c_data:
|
||||
try:
|
||||
newcookies = ';'.join(filter(lambda x: x.split('=')[0] in ["cookie_token", "account_id"], [i.strip() for i in row[0].split(';')]))
|
||||
aid = re.search(r"account_id=(\d*)", row[0])
|
||||
mysid_data = aid.group(0).split('=')
|
||||
mysid = mysid_data[1]
|
||||
mys_data = await GetMysInfo(mysid,row[0])
|
||||
mys_data = mys_data[0]
|
||||
uid = mys_data['data']['list'][0]['game_role_id']
|
||||
c.execute("INSERT OR IGNORE INTO NewCookiesTable (Cookies,UID,StatusA,StatusB,StatusC,NUM) \
|
||||
VALUES (?, ?,?,?,?,?)",(newcookies,uid,"off","off","off",140))
|
||||
str = str + f"uid{uid}/mysid{mysid}的Cookies已转移成功!\n"
|
||||
except:
|
||||
str = str + f"uid{uid}/mysid{mysid}的Cookies是异常的!已删除该条Cookies!\n"
|
||||
conn.commit()
|
||||
conn.close()
|
||||
return str
|
||||
|
||||
async def connectDB(userid,uid = None,mys = None):
|
||||
conn = sqlite3.connect('ID_DATA.db')
|
||||
c = conn.cursor()
|
||||
c.execute('''CREATE TABLE IF NOT EXISTS UIDDATA
|
||||
(USERID INT PRIMARY KEY NOT NULL,
|
||||
UID TEXT,
|
||||
MYSID TEXT);''')
|
||||
|
||||
c.execute("INSERT OR IGNORE INTO UIDDATA (USERID,UID,MYSID) \
|
||||
VALUES (?, ?,?)",(userid,uid,mys))
|
||||
|
||||
if uid:
|
||||
c.execute("UPDATE UIDDATA SET UID = ? WHERE USERID=?",(uid,userid))
|
||||
if mys:
|
||||
c.execute("UPDATE UIDDATA SET MYSID = ? WHERE USERID=?",(mys,userid))
|
||||
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
async def selectDB(userid,mode = "auto"):
|
||||
conn = sqlite3.connect('ID_DATA.db')
|
||||
c = conn.cursor()
|
||||
cursor = c.execute("SELECT * FROM UIDDATA WHERE USERID = ?",(userid,))
|
||||
for row in cursor:
|
||||
if mode == "auto":
|
||||
if row[0]:
|
||||
if row[2]:
|
||||
return [row[2],3]
|
||||
elif row[1]:
|
||||
return [row[1],2]
|
||||
else:
|
||||
return None
|
||||
else:
|
||||
return None
|
||||
elif mode == "uid":
|
||||
return [row[1],2]
|
||||
elif mode == "mys":
|
||||
return [row[2],3]
|
||||
|
||||
def deletecache():
|
||||
try:
|
||||
conn = sqlite3.connect('ID_DATA.db')
|
||||
c = conn.cursor()
|
||||
c.execute("DROP TABLE CookiesCache")
|
||||
c.execute("UPDATE NewCookiesTable SET Extra = ? WHERE Extra=?",(None,"limit30"))
|
||||
copyfile("ID_DATA.db", "ID_DATA_bak.db")
|
||||
c.execute('''CREATE TABLE IF NOT EXISTS CookiesCache
|
||||
(UID TEXT PRIMARY KEY,
|
||||
MYSID TEXT,
|
||||
Cookies TEXT);''')
|
||||
conn.commit()
|
||||
conn.close()
|
||||
except:
|
||||
print("\nerror\n")
|
||||
|
||||
try:
|
||||
conn = sqlite3.connect('ID_DATA.db')
|
||||
c = conn.cursor()
|
||||
c.execute("UPDATE UseridDict SET lots=NULL")
|
||||
conn.commit()
|
||||
conn.close()
|
||||
except:
|
||||
print("\nerror\n")
|
||||
|
||||
def errorDB(ck,err):
|
||||
conn = sqlite3.connect('ID_DATA.db')
|
||||
c = conn.cursor()
|
||||
if err == "error":
|
||||
c.execute("UPDATE NewCookiesTable SET Extra = ? WHERE Cookies=?",("error",ck))
|
||||
elif err == "limit30":
|
||||
c.execute("UPDATE NewCookiesTable SET Extra = ? WHERE Cookies=?",("limit30",ck))
|
||||
|
||||
def cacheDB(uid,mode = 1,mys = None):
|
||||
use = ''
|
||||
conn = sqlite3.connect('ID_DATA.db')
|
||||
c = conn.cursor()
|
||||
c.execute('''CREATE TABLE IF NOT EXISTS CookiesCache
|
||||
(UID TEXT PRIMARY KEY,
|
||||
MYSID TEXT,
|
||||
Cookies TEXT);''')
|
||||
|
||||
if mode == 1:
|
||||
if mys:
|
||||
cursor = c.execute("SELECT * FROM CookiesCache WHERE MYSID = ?",(mys,))
|
||||
c_data = cursor.fetchall()
|
||||
else:
|
||||
cursor = c.execute("SELECT * FROM CookiesCache WHERE UID = ?",(uid,))
|
||||
c_data = cursor.fetchall()
|
||||
elif mode == 2:
|
||||
cursor = c.execute("SELECT * FROM CookiesCache WHERE MYSID = ?",(uid,))
|
||||
c_data = cursor.fetchall()
|
||||
|
||||
if len(c_data)==0:
|
||||
if mode == 2:
|
||||
conn.create_function("REGEXP", 2, functionRegex)
|
||||
cursor = c.execute("SELECT * FROM NewCookiesTable WHERE REGEXP(Cookies, ?)",(uid,))
|
||||
d_data = cursor.fetchall()
|
||||
|
||||
elif mode == 1:
|
||||
cursor = c.execute("SELECT * FROM NewCookiesTable WHERE UID = ?",(uid,))
|
||||
d_data = cursor.fetchall()
|
||||
|
||||
if len(d_data) !=0 :
|
||||
if d_data[0][7] != "error":
|
||||
use = d_data[0][1]
|
||||
if mode == 1:
|
||||
c.execute("INSERT OR IGNORE INTO CookiesCache (Cookies,UID) \
|
||||
VALUES (?, ?)",(use,uid))
|
||||
elif mode == 2:
|
||||
c.execute("INSERT OR IGNORE INTO CookiesCache (Cookies,MYSID) \
|
||||
VALUES (?, ?)",(use,uid))
|
||||
else:
|
||||
cookiesrow = c.execute("SELECT * FROM NewCookiesTable WHERE Extra IS NULL ORDER BY RANDOM() LIMIT 1")
|
||||
e_data = cookiesrow.fetchall()
|
||||
if len(e_data) != 0:
|
||||
if mode == 1:
|
||||
c.execute("INSERT OR IGNORE INTO CookiesCache (Cookies,UID) \
|
||||
VALUES (?, ?)",(e_data[0][1],uid))
|
||||
elif mode == 2:
|
||||
c.execute("INSERT OR IGNORE INTO CookiesCache (Cookies,MYSID) \
|
||||
VALUES (?, ?)",(e_data[0][1],uid))
|
||||
use = e_data[0][1]
|
||||
else:
|
||||
return "没有可以使用的Cookies!"
|
||||
else:
|
||||
cookiesrow = c.execute("SELECT * FROM NewCookiesTable WHERE Extra IS NULL ORDER BY RANDOM() LIMIT 1")
|
||||
e_data = cookiesrow.fetchall()
|
||||
if len(e_data) != 0:
|
||||
if mode == 1:
|
||||
c.execute("INSERT OR IGNORE INTO CookiesCache (Cookies,UID) \
|
||||
VALUES (?, ?)",(e_data[0][1],uid))
|
||||
elif mode == 2:
|
||||
c.execute("INSERT OR IGNORE INTO CookiesCache (Cookies,MYSID) \
|
||||
VALUES (?, ?)",(e_data[0][1],uid))
|
||||
use = e_data[0][1]
|
||||
else:
|
||||
return "没有可以使用的Cookies!"
|
||||
else:
|
||||
use = c_data[0][2]
|
||||
if mys:
|
||||
try:
|
||||
c.execute("UPDATE CookiesCache SET UID = ? WHERE MYSID=?",(uid,mys))
|
||||
except:
|
||||
c.execute("UPDATE CookiesCache SET MYSID = ? WHERE UID=?",(mys,uid))
|
||||
|
||||
conn.commit()
|
||||
conn.close()
|
||||
return use
|
||||
|
||||
def functionRegex(value,patter):
|
||||
c_pattern = re.compile(r"account_id={}".format(patter))
|
||||
return c_pattern.search(value) is not None
|
||||
|
||||
async def cookiesDB(uid,Cookies,qid):
|
||||
conn = sqlite3.connect('ID_DATA.db')
|
||||
c = conn.cursor()
|
||||
|
||||
c.execute('''CREATE TABLE IF NOT EXISTS NewCookiesTable
|
||||
(UID INT PRIMARY KEY NOT NULL,
|
||||
Cookies TEXT,
|
||||
QID INT,
|
||||
StatusA TEXT,
|
||||
StatusB TEXT,
|
||||
StatusC TEXT,
|
||||
NUM INT,
|
||||
Extra TEXT);''')
|
||||
|
||||
cursor = c.execute("SELECT * from NewCookiesTable WHERE UID = ?",(uid,))
|
||||
c_data = cursor.fetchall()
|
||||
if len(c_data) == 0 :
|
||||
c.execute("INSERT OR IGNORE INTO NewCookiesTable (Cookies,UID,StatusA,StatusB,StatusC,NUM,QID) \
|
||||
VALUES (?, ?,?,?,?,?,?)",(Cookies,uid,"off","off","off",140,qid))
|
||||
else:
|
||||
c.execute("UPDATE NewCookiesTable SET Cookies = ? WHERE UID=?",(Cookies,uid))
|
||||
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
async def OpCookies():
|
||||
str = ""
|
||||
conn = sqlite3.connect('ID_DATA.db')
|
||||
c = conn.cursor()
|
||||
test = c.execute("SELECT count(*) FROM sqlite_master WHERE type='table' AND name = 'NewCookies'")
|
||||
if test == 0:
|
||||
conn.commit()
|
||||
conn.close()
|
||||
return "你没有需要优化的数据库。"
|
||||
else:
|
||||
c.execute('''CREATE TABLE IF NOT EXISTS NewCookiesTable
|
||||
(UID INT PRIMARY KEY NOT NULL,
|
||||
Cookies TEXT,
|
||||
QID INT,
|
||||
StatusA TEXT,
|
||||
StatusB TEXT,
|
||||
StatusC TEXT,
|
||||
NUM INT,
|
||||
Extra TEXT);''')
|
||||
cursor = c.execute("SELECT * from NewCookies")
|
||||
c_data = cursor.fetchall()
|
||||
for row in c_data:
|
||||
try:
|
||||
newcookies = ';'.join(filter(lambda x: x.split('=')[0] in ["cookie_token", "account_id"], [i.strip() for i in row[0].split(';')]))
|
||||
aid = re.search(r"account_id=(\d*)", row[0])
|
||||
mysid_data = aid.group(0).split('=')
|
||||
mysid = mysid_data[1]
|
||||
mys_data = await GetMysInfo(mysid,row[0])
|
||||
mys_data = mys_data[0]
|
||||
uid = mys_data['data']['list'][0]['game_role_id']
|
||||
c.execute("INSERT OR IGNORE INTO NewCookiesTable (Cookies,UID,StatusA,StatusB,StatusC,QID,NUM) \
|
||||
VALUES (?, ?,?,?,?,?,?)",(newcookies,row[1],row[2],row[3],"off",row[4],row[5]))
|
||||
str = str + f"uid{row[1]}的Cookies已转移成功!\n"
|
||||
except:
|
||||
str = str + f"uid{row[1]}的Cookies是异常的!已删除该条Cookies!\n"
|
||||
conn.commit()
|
||||
conn.close()
|
||||
return str
|
||||
|
||||
|
||||
async def OwnerCookies(uid):
|
||||
conn = sqlite3.connect('ID_DATA.db')
|
||||
c = conn.cursor()
|
||||
try:
|
||||
cursor = c.execute("SELECT * FROM NewCookiesTable WHERE UID = ?",(uid,))
|
||||
c_data = cursor.fetchall()
|
||||
cookies = c_data[0][1]
|
||||
except:
|
||||
return
|
||||
|
||||
return cookies
|
||||
|
||||
|
||||
def random_hex(length):
|
||||
result = hex(random.randint(0,16**length)).replace('0x','').upper()
|
||||
if len(result)<length:
|
||||
result = "0"*(length-len(result))+result
|
||||
return result
|
||||
|
||||
def md5(text):
|
||||
md5 = hashlib.md5()
|
||||
md5.update(text.encode())
|
||||
return md5.hexdigest()
|
||||
|
||||
def oldDSGet():
|
||||
n = "h8w582wxwgqvahcdkpvdhbh2w9casgfl"
|
||||
i = str(int(time.time()))
|
||||
r = ''.join(random.sample(string.ascii_lowercase + string.digits, 6))
|
||||
c = md5("salt=" + n + "&t=" + i + "&r=" + r)
|
||||
return (i + "," + r + "," + c)
|
||||
|
||||
def DSGet(q = "",b = None):
|
||||
if b:
|
||||
br = json.dumps(b)
|
||||
else:
|
||||
br = ""
|
||||
s = "xV8v4Qu54lUKrEYFZkJhB8cuOh9Asafs"
|
||||
t = str(int(time.time()))
|
||||
r = str(random.randint(100000, 200000))
|
||||
c = md5("salt=" + s + "&t=" + t + "&r=" + r + "&b=" + br + "&q=" + q)
|
||||
return t + "," + r + "," + c
|
||||
|
||||
async def GetDaily(Uid,ServerID="cn_gf01"):
|
||||
if Uid[0] == '5':
|
||||
ServerID = "cn_qd01"
|
||||
try:
|
||||
async with AsyncClient() as client:
|
||||
req = await client.get(
|
||||
url="https://api-takumi-record.mihoyo.com/game_record/app/genshin/api/dailyNote?server=" + ServerID + "&role_id=" + Uid,
|
||||
headers={
|
||||
'DS': DSGet("role_id=" + Uid + "&server=" + ServerID),
|
||||
'x-rpc-app_version': mhyVersion,
|
||||
'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) miHoYoBBS/2.11.1',
|
||||
'x-rpc-client_type': '5',
|
||||
'Referer': 'https://webstatic.mihoyo.com/',
|
||||
"Cookie": await OwnerCookies(Uid)})
|
||||
data = json.loads(req.text)
|
||||
return data
|
||||
except:
|
||||
print("访问每日信息失败,请重试!")
|
||||
sys.exit(1)
|
||||
|
||||
async def GetSignList():
|
||||
try:
|
||||
async with AsyncClient() as client:
|
||||
req = await client.get(
|
||||
url="https://api-takumi.mihoyo.com/event/bbs_sign_reward/home?act_id=e202009291139501",
|
||||
headers={
|
||||
'x-rpc-app_version': mhyVersion,
|
||||
'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) miHoYoBBS/2.11.1',
|
||||
'x-rpc-client_type': '5',
|
||||
'Referer': 'https://webstatic.mihoyo.com/'})
|
||||
data = json.loads(req.text)
|
||||
return data
|
||||
except:
|
||||
im = "获取签到奖励列表失败,请重试"
|
||||
print(im)
|
||||
|
||||
async def GetSignInfo(Uid,ServerID="cn_gf01"):
|
||||
if Uid[0] == '5':
|
||||
ServerID = "cn_qd01"
|
||||
try:
|
||||
async with AsyncClient() as client:
|
||||
req = await client.get(
|
||||
url="https://api-takumi.mihoyo.com/event/bbs_sign_reward/info?act_id=e202009291139501®ion=" + ServerID + "&uid=" + Uid,
|
||||
headers={
|
||||
'x-rpc-app_version': mhyVersion,
|
||||
"Cookie": await OwnerCookies(Uid),
|
||||
'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) miHoYoBBS/2.11.1',
|
||||
'x-rpc-client_type': '5',
|
||||
'Referer': 'https://webstatic.mihoyo.com/'})
|
||||
data = json.loads(req.text)
|
||||
return data
|
||||
except:
|
||||
im = "获取签到信息失败,请重试"
|
||||
|
||||
async def MysSign(Uid,ServerID="cn_gf01"):
|
||||
if Uid[0] == '5':
|
||||
ServerID = "cn_qd01"
|
||||
try:
|
||||
req = requests.post(
|
||||
url = "https://api-takumi.mihoyo.com/event/bbs_sign_reward/sign",
|
||||
headers={
|
||||
'User_Agent': 'Mozilla/5.0 (Linux; Android 10; MIX 2 Build/QKQ1.190825.002; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/83.0.4103.101 Mobile Safari/537.36 miHoYoBBS/2.3.0',
|
||||
"Cookie": await OwnerCookies(Uid),
|
||||
"x-rpc-device_id":random_hex(32),
|
||||
'Origin': 'https://webstatic.mihoyo.com',
|
||||
'X_Requested_With': 'com.mihoyo.hyperion',
|
||||
'DS': oldDSGet(),
|
||||
'x-rpc-client_type': '5',
|
||||
'Referer': 'https://webstatic.mihoyo.com/bbs/event/signin-ys/index.html?bbs_auth_required=true&act_id=e202009291139501&utm_source=bbs&utm_medium=mys&utm_campaign=icon',
|
||||
'x-rpc-app_version': '2.3.0'
|
||||
},
|
||||
json = {"act_id": "e202009291139501" ,"uid": Uid ,"region": ServerID}
|
||||
)
|
||||
data2 = json.loads(req.text)
|
||||
return data2
|
||||
except:
|
||||
im = { 'message' : '签到失败,请重试'}
|
||||
return im
|
||||
|
||||
async def GetAward(Uid,ServerID="cn_gf01"):
|
||||
if Uid[0] == '5':
|
||||
ServerID = "cn_qd01"
|
||||
try:
|
||||
async with AsyncClient() as client:
|
||||
req = await client.get(
|
||||
url="https://hk4e-api.mihoyo.com/event/ys_ledger/monthInfo?month={}&bind_uid={}&bind_region={}&bbs_presentation_style=fullscreen&bbs_auth_required=true&utm_source=bbs&utm_medium=mys&utm_campaign=icon".format("0",Uid,ServerID),
|
||||
headers={
|
||||
'x-rpc-app_version': mhyVersion,
|
||||
"Cookie": await OwnerCookies(Uid),
|
||||
'DS': oldDSGet(),
|
||||
"x-rpc-device_id":random_hex(32),
|
||||
'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) miHoYoBBS/2.11.1',
|
||||
'x-rpc-client_type': '5',
|
||||
'Referer': 'https://webstatic.mihoyo.com/'})
|
||||
data = json.loads(req.text)
|
||||
return data
|
||||
except:
|
||||
im = "访问每月统计失败,请重试!"
|
||||
print(im)
|
||||
return im
|
||||
#sys.exit(1)
|
||||
|
||||
async def GetInfo(Uid,ck,ServerID="cn_gf01"):
|
||||
if Uid[0] == '5':
|
||||
ServerID = "cn_qd01"
|
||||
try:
|
||||
async with AsyncClient() as client:
|
||||
req = await client.get(
|
||||
url="https://api-takumi-record.mihoyo.com/game_record/app/genshin/api/index?role_id=" + Uid + "&server=" + ServerID,
|
||||
headers={
|
||||
'DS': DSGet("role_id=" + Uid + "&server=" + ServerID),
|
||||
'x-rpc-app_version': mhyVersion,
|
||||
'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) miHoYoBBS/2.11.1',
|
||||
'x-rpc-client_type': '5',
|
||||
'Referer': 'https://webstatic.mihoyo.com/',
|
||||
"Cookie": ck})
|
||||
data = json.loads(req.text)
|
||||
return data
|
||||
except:
|
||||
print("获取信息失败,请重试!")
|
||||
#sys.exit(1)
|
||||
|
||||
async def GetSpiralAbyssInfo(Uid, ck,Schedule_type="1",ServerID="cn_gf01"):
|
||||
if Uid[0] == '5':
|
||||
ServerID = "cn_qd01"
|
||||
try:
|
||||
async with AsyncClient() as client:
|
||||
req = await client.get(
|
||||
url="https://api-takumi-record.mihoyo.com/game_record/app/genshin/api/spiralAbyss?schedule_type=" + Schedule_type + "&server="+ ServerID +"&role_id=" + Uid,
|
||||
headers={
|
||||
'DS': DSGet("role_id=" + Uid + "&schedule_type=" + Schedule_type + "&server="+ ServerID),
|
||||
'Origin': 'https://webstatic.mihoyo.com',
|
||||
'Cookie': ck,
|
||||
'x-rpc-app_version': mhyVersion,
|
||||
'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) miHoYoBBS/2.11.1',
|
||||
'x-rpc-client_type': '5',
|
||||
'Referer': 'https://webstatic.mihoyo.com/'
|
||||
}
|
||||
)
|
||||
data = json.loads(req.text)
|
||||
return data
|
||||
except:
|
||||
print("1获取深渊信息失败,请重试!")
|
||||
#sys.exit(1)
|
||||
|
||||
|
||||
def GetCharacter(Uid,Character_ids, ck,ServerID="cn_gf01"):
|
||||
if Uid[0] == '5':
|
||||
ServerID = "cn_qd01"
|
||||
try:
|
||||
req = requests.post(
|
||||
url = "https://api-takumi-record.mihoyo.com/game_record/app/genshin/api/character",
|
||||
headers={
|
||||
'DS': DSGet('',{"character_ids": Character_ids ,"role_id": Uid ,"server": ServerID}),
|
||||
'Origin': 'https://webstatic.mihoyo.com',
|
||||
'Cookie': ck,
|
||||
'x-rpc-app_version': mhyVersion,
|
||||
'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) miHoYoBBS/2.11.1',
|
||||
'x-rpc-client_type': '5',
|
||||
'Referer': 'https://webstatic.mihoyo.com/'
|
||||
},
|
||||
json = {"character_ids": Character_ids ,"role_id": Uid ,"server": ServerID}
|
||||
)
|
||||
data2 = json.loads(req.text)
|
||||
return data2
|
||||
except:
|
||||
print("获取人物信息失败,请重试!")
|
||||
#sys.exit(1)
|
||||
|
||||
async def GetMysInfo(mysid,ck):
|
||||
try:
|
||||
async with AsyncClient() as client:
|
||||
req = await client.get(
|
||||
url="https://api-takumi-record.mihoyo.com/game_record/card/wapi/getGameRecordCard?uid=" + mysid,
|
||||
headers={
|
||||
'DS': DSGet("uid="+mysid),
|
||||
'x-rpc-app_version': mhyVersion,
|
||||
'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) miHoYoBBS/2.11.1',
|
||||
'x-rpc-client_type': '5',
|
||||
'Referer': 'https://webstatic.mihoyo.com/',
|
||||
"Cookie": ck})
|
||||
data = json.loads(req.text)
|
||||
return data
|
||||
except:
|
||||
im = "err,获取米游社信息失败,请重试!"
|
||||
print(im)
|
||||
return im
|
||||
|
||||
async def GetWeaponInfo(name):
|
||||
async with AsyncClient() as client:
|
||||
req = await client.get(
|
||||
url="https://genshin.minigg.cn/?weapons=" + name,
|
||||
headers={
|
||||
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36',
|
||||
'Referer': 'https://genshin.minigg.cn/index.html'})
|
||||
soup = BeautifulSoup(req.text, "lxml")
|
||||
item = soup.select_one("pre").text
|
||||
data = json.loads(item)
|
||||
return data
|
||||
|
||||
async def GetCharInfo(name,mode = 0,level = None):
|
||||
str = ""
|
||||
if mode == 1:
|
||||
str = "&talents=1"
|
||||
elif mode == 2:
|
||||
str = "&constellations=1"
|
||||
|
||||
baseurl = "https://genshin.minigg.cn/?characters="
|
||||
|
||||
detailurl = "https://api.minigg.cn/characters?query="
|
||||
|
||||
if level:
|
||||
async with AsyncClient() as client:
|
||||
req = await client.get(
|
||||
url = detailurl + name + "&stats=" + level,
|
||||
headers={
|
||||
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36',
|
||||
'Referer': 'https://genshin.minigg.cn/index.html'})
|
||||
data = jsonfy(req.text)
|
||||
else:
|
||||
async with AsyncClient() as client:
|
||||
req = await client.get(
|
||||
url = baseurl + name + str,
|
||||
headers={
|
||||
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36',
|
||||
'Referer': 'https://genshin.minigg.cn/index.html'})
|
||||
|
||||
soup = BeautifulSoup(req.text, "lxml")
|
||||
item = soup.select_one("pre").text
|
||||
if item:
|
||||
data = json.loads(item)
|
||||
else:
|
||||
async with AsyncClient() as client:
|
||||
req = await client.get(
|
||||
url = detailurl + name + "&matchCategories=true",
|
||||
headers={
|
||||
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36',
|
||||
'Referer': 'https://genshin.minigg.cn/index.html'})
|
||||
data = req.text
|
||||
|
||||
return data
|
||||
|
||||
async def GetGenshinEvent(mode = "List"):
|
||||
if mode == "Calendar":
|
||||
now_time = datetime.datetime.now().strftime('%Y-%m-%d')
|
||||
base_url = "https://api-takumi.mihoyo.com/event/bbs_activity_calendar/getActList?time={}&game_biz=ys_cn&page=1&tag_id=0".format(now_time)
|
||||
else:
|
||||
base_url = "https://hk4e-api.mihoyo.com/common/hk4e_cn/announcement/api/getAnn" + mode + "?game=hk4e&game_biz=hk4e_cn&lang=zh-cn&bundle_id=hk4e_cn&platform=pc®ion=cn_gf01&level=55&uid=100000000"
|
||||
|
||||
async with AsyncClient() as client:
|
||||
req = await client.get(
|
||||
url = base_url,
|
||||
headers={
|
||||
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36'})
|
||||
data = json.loads(req.text)
|
||||
return data
|
||||
|
||||
def jsonfy(s:str)->object:
|
||||
#此函数将不带双引号的json的key标准化
|
||||
obj = eval(s, type('js', (dict,), dict(__getitem__=lambda s, n: n))())
|
||||
return obj
|
BIN
mihoyo_libs/Genshin All Char.xlsx
Normal file
897
mihoyo_libs/get_data.py
Normal file
@ -0,0 +1,897 @@
|
||||
import datetime
|
||||
import hashlib
|
||||
import json
|
||||
import os
|
||||
import random
|
||||
import re
|
||||
import sqlite3
|
||||
import string
|
||||
import time
|
||||
from shutil import copyfile
|
||||
|
||||
import requests
|
||||
from httpx import AsyncClient
|
||||
|
||||
mhyVersion = "2.11.1"
|
||||
|
||||
BASE_PATH = os.path.dirname(__file__)
|
||||
BASE2_PATH = os.path.join(BASE_PATH, 'mihoyo_bbs')
|
||||
INDEX_PATH = os.path.join(BASE2_PATH, 'index')
|
||||
|
||||
|
||||
async def config_check(func, mode="CHECK"):
|
||||
conn = sqlite3.connect('ID_DATA.db')
|
||||
c = conn.cursor()
|
||||
c.execute('''CREATE TABLE IF NOT EXISTS Config
|
||||
(Name TEXT PRIMARY KEY NOT NULL,
|
||||
Status TEXT,
|
||||
GroupList TEXT,
|
||||
Extra TEXT);''')
|
||||
c.execute("INSERT OR IGNORE INTO Config (Name,Status) \
|
||||
VALUES (?, ?)", (func, "on"))
|
||||
if mode == "CHECK":
|
||||
cursor = c.execute("SELECT * from Config WHERE Name = ?", (func,))
|
||||
c_data = cursor.fetchall()
|
||||
conn.close()
|
||||
if c_data[0][1] != "off":
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
elif mode == "OPEN":
|
||||
c.execute("UPDATE Config SET Status = ? WHERE Name=?", ("on", func))
|
||||
conn.commit()
|
||||
conn.close()
|
||||
return True
|
||||
elif mode == "CLOSED":
|
||||
c.execute("UPDATE Config SET Status = ? WHERE Name=?", ("off", func))
|
||||
conn.commit()
|
||||
conn.close()
|
||||
return True
|
||||
|
||||
|
||||
async def get_a_lots(qid):
|
||||
conn = sqlite3.connect('ID_DATA.db')
|
||||
c = conn.cursor()
|
||||
c.execute('''CREATE TABLE IF NOT EXISTS UseridDict
|
||||
(QID INT PRIMARY KEY NOT NULL,
|
||||
lots TEXT,
|
||||
cache TEXT,
|
||||
permission TEXT,
|
||||
Status TEXT,
|
||||
Subscribe TEXT,
|
||||
Extra TEXT);''')
|
||||
cursor = c.execute("SELECT * from UseridDict WHERE QID = ?", (qid,))
|
||||
c_data = cursor.fetchall()
|
||||
with open(os.path.join(INDEX_PATH, 'lots.txt'), "r") as f:
|
||||
raw_data = f.read()
|
||||
raw_data = raw_data.replace(' ', "").split('-')
|
||||
|
||||
if len(c_data) == 0:
|
||||
num = random.randint(1, len(raw_data) - 1)
|
||||
data = raw_data[num]
|
||||
c.execute("INSERT OR IGNORE INTO UseridDict (QID,lots) \
|
||||
VALUES (?, ?)", (qid, str(num)))
|
||||
else:
|
||||
if c_data[0][1] is None:
|
||||
num = random.randint(0, len(raw_data) - 1)
|
||||
data = raw_data[num]
|
||||
c.execute("UPDATE UseridDict SET lots = ? WHERE QID=?", (str(num), qid))
|
||||
else:
|
||||
num = int(c_data[0][1])
|
||||
data = raw_data[num]
|
||||
conn.commit()
|
||||
conn.close()
|
||||
return data
|
||||
|
||||
|
||||
async def open_push(uid, qid, status, mode):
|
||||
conn = sqlite3.connect('ID_DATA.db')
|
||||
c = conn.cursor()
|
||||
cursor = c.execute("SELECT * from NewCookiesTable WHERE UID = ?", (uid,))
|
||||
c_data = cursor.fetchall()
|
||||
if len(c_data) != 0:
|
||||
try:
|
||||
c.execute("UPDATE NewCookiesTable SET {s} = ?,QID = ? WHERE UID=?".format(s=mode), (status, qid, uid))
|
||||
conn.commit()
|
||||
conn.close()
|
||||
return "成功!"
|
||||
except:
|
||||
return "未找到Ck绑定记录。"
|
||||
else:
|
||||
return "未找到Ck绑定记录。"
|
||||
|
||||
|
||||
async def check_db():
|
||||
return_str = str()
|
||||
invalid_list = []
|
||||
conn = sqlite3.connect('ID_DATA.db')
|
||||
c = conn.cursor()
|
||||
cursor = c.execute("SELECT UID,Cookies,QID from NewCookiesTable")
|
||||
c_data = cursor.fetchall()
|
||||
for row in c_data:
|
||||
try:
|
||||
aid = re.search(r"account_id=(\d*)", row[1])
|
||||
mihoyo_id_data = aid.group(0).split('=')
|
||||
mihoyo_id = mihoyo_id_data[1]
|
||||
mys_data = await get_mihoyo_bbs_info(mihoyo_id, row[1])
|
||||
for i in mys_data['data']['list']:
|
||||
if i['game_id'] != 2:
|
||||
mys_data['data']['list'].remove(i)
|
||||
return_str = return_str + f"uid{row[0]}/mys{mihoyo_id}的Cookies是正常的!\n"
|
||||
except:
|
||||
return_str = return_str + f"uid{row[0]}的Cookies是异常的!已删除该条Cookies!\n"
|
||||
invalid_list.append([row[2], row[0]])
|
||||
c.execute("DELETE from NewCookiesTable where UID=?", (row[0],))
|
||||
try:
|
||||
c.execute("DELETE from CookiesCache where Cookies=?", (row[1],))
|
||||
except:
|
||||
pass
|
||||
conn.commit()
|
||||
conn.close()
|
||||
return [return_str, invalid_list]
|
||||
|
||||
|
||||
async def connect_db(userid, uid=None, mys=None):
|
||||
conn = sqlite3.connect('ID_DATA.db')
|
||||
c = conn.cursor()
|
||||
c.execute('''CREATE TABLE IF NOT EXISTS UIDDATA
|
||||
(USERID INT PRIMARY KEY NOT NULL,
|
||||
UID TEXT,
|
||||
MYSID TEXT);''')
|
||||
|
||||
c.execute("INSERT OR IGNORE INTO UIDDATA (USERID,UID,MYSID) \
|
||||
VALUES (?, ?,?)", (userid, uid, mys))
|
||||
|
||||
if uid:
|
||||
c.execute("UPDATE UIDDATA SET UID = ? WHERE USERID=?", (uid, userid))
|
||||
if mys:
|
||||
c.execute("UPDATE UIDDATA SET MYSID = ? WHERE USERID=?", (mys, userid))
|
||||
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
|
||||
async def select_db(userid, mode="auto"):
|
||||
conn = sqlite3.connect('ID_DATA.db')
|
||||
c = conn.cursor()
|
||||
cursor = c.execute("SELECT * FROM UIDDATA WHERE USERID = ?", (userid,))
|
||||
for row in cursor:
|
||||
if mode == "auto":
|
||||
if row[0]:
|
||||
if row[2]:
|
||||
return [row[2], 3]
|
||||
elif row[1]:
|
||||
return [row[1], 2]
|
||||
else:
|
||||
return None
|
||||
else:
|
||||
return None
|
||||
elif mode == "uid":
|
||||
return [row[1], 2]
|
||||
elif mode == "mys":
|
||||
return [row[2], 3]
|
||||
|
||||
|
||||
async def delete_cache():
|
||||
try:
|
||||
copyfile("ID_DATA.db", "ID_DATA_bak.db")
|
||||
print("————数据库成功备份————")
|
||||
except:
|
||||
print("————数据库备份失败————")
|
||||
|
||||
try:
|
||||
conn = sqlite3.connect('ID_DATA.db')
|
||||
c = conn.cursor()
|
||||
c.execute("DROP TABLE CookiesCache")
|
||||
c.execute("UPDATE NewCookiesTable SET Extra = ? WHERE Extra=?", (None, "limit30"))
|
||||
c.execute('''CREATE TABLE IF NOT EXISTS CookiesCache
|
||||
(UID TEXT PRIMARY KEY,
|
||||
MYSID TEXT,
|
||||
Cookies TEXT);''')
|
||||
conn.commit()
|
||||
conn.close()
|
||||
print("————UID查询缓存已清空————")
|
||||
except:
|
||||
print("\nerror\n")
|
||||
|
||||
try:
|
||||
conn = sqlite3.connect('ID_DATA.db')
|
||||
c = conn.cursor()
|
||||
c.execute("UPDATE UseridDict SET lots=NULL")
|
||||
conn.commit()
|
||||
conn.close()
|
||||
print("————御神签缓存已清空————")
|
||||
except:
|
||||
print("\nerror\n")
|
||||
|
||||
|
||||
def error_db(ck, err):
|
||||
conn = sqlite3.connect('ID_DATA.db')
|
||||
c = conn.cursor()
|
||||
if err == "error":
|
||||
c.execute("UPDATE NewCookiesTable SET Extra = ? WHERE Cookies=?", ("error", ck))
|
||||
elif err == "limit30":
|
||||
c.execute("UPDATE NewCookiesTable SET Extra = ? WHERE Cookies=?", ("limit30", ck))
|
||||
|
||||
|
||||
def cache_db(uid, mode=1, mys=None):
|
||||
conn = sqlite3.connect('ID_DATA.db')
|
||||
c = conn.cursor()
|
||||
c.execute('''CREATE TABLE IF NOT EXISTS CookiesCache
|
||||
(UID TEXT PRIMARY KEY,
|
||||
MYSID TEXT,
|
||||
Cookies TEXT);''')
|
||||
|
||||
if mode == 1:
|
||||
if mys:
|
||||
cursor = c.execute("SELECT * FROM CookiesCache WHERE MYSID = ?", (mys,))
|
||||
else:
|
||||
cursor = c.execute("SELECT * FROM CookiesCache WHERE UID = ?", (uid,))
|
||||
else:
|
||||
cursor = c.execute("SELECT * FROM CookiesCache WHERE MYSID = ?", (uid,))
|
||||
c_data = cursor.fetchall()
|
||||
|
||||
if len(c_data) == 0:
|
||||
if mode == 2:
|
||||
conn.create_function("REGEXP", 2, regex_func)
|
||||
cursor = c.execute("SELECT * FROM NewCookiesTable WHERE REGEXP(Cookies, ?)", (uid,))
|
||||
d_data = cursor.fetchall()
|
||||
|
||||
else:
|
||||
cursor = c.execute("SELECT * FROM NewCookiesTable WHERE UID = ?", (uid,))
|
||||
d_data = cursor.fetchall()
|
||||
|
||||
if len(d_data) != 0:
|
||||
if d_data[0][7] != "error":
|
||||
use = d_data[0][1]
|
||||
if mode == 1:
|
||||
c.execute("INSERT OR IGNORE INTO CookiesCache (Cookies,UID) \
|
||||
VALUES (?, ?)", (use, uid))
|
||||
elif mode == 2:
|
||||
c.execute("INSERT OR IGNORE INTO CookiesCache (Cookies,MYSID) \
|
||||
VALUES (?, ?)", (use, uid))
|
||||
else:
|
||||
cookies_row = c.execute("SELECT * FROM NewCookiesTable WHERE Extra IS NULL ORDER BY RANDOM() LIMIT 1")
|
||||
e_data = cookies_row.fetchall()
|
||||
if len(e_data) != 0:
|
||||
if mode == 1:
|
||||
c.execute("INSERT OR IGNORE INTO CookiesCache (Cookies,UID) \
|
||||
VALUES (?, ?)", (e_data[0][1], uid))
|
||||
elif mode == 2:
|
||||
c.execute("INSERT OR IGNORE INTO CookiesCache (Cookies,MYSID) \
|
||||
VALUES (?, ?)", (e_data[0][1], uid))
|
||||
use = e_data[0][1]
|
||||
else:
|
||||
return "没有可以使用的Cookies!"
|
||||
else:
|
||||
cookies_row = c.execute("SELECT * FROM NewCookiesTable WHERE Extra IS NULL ORDER BY RANDOM() LIMIT 1")
|
||||
e_data = cookies_row.fetchall()
|
||||
if len(e_data) != 0:
|
||||
if mode == 1:
|
||||
c.execute("INSERT OR IGNORE INTO CookiesCache (Cookies,UID) \
|
||||
VALUES (?, ?)", (e_data[0][1], uid))
|
||||
elif mode == 2:
|
||||
c.execute("INSERT OR IGNORE INTO CookiesCache (Cookies,MYSID) \
|
||||
VALUES (?, ?)", (e_data[0][1], uid))
|
||||
use = e_data[0][1]
|
||||
else:
|
||||
return "没有可以使用的Cookies!"
|
||||
else:
|
||||
use = c_data[0][2]
|
||||
if mys:
|
||||
try:
|
||||
c.execute("UPDATE CookiesCache SET UID = ? WHERE MYSID=?", (uid, mys))
|
||||
except:
|
||||
c.execute("UPDATE CookiesCache SET MYSID = ? WHERE UID=?", (mys, uid))
|
||||
|
||||
conn.commit()
|
||||
conn.close()
|
||||
return use
|
||||
|
||||
|
||||
def regex_func(value, patter):
|
||||
c_pattern = re.compile(r"account_id={}".format(patter))
|
||||
return c_pattern.search(value) is not None
|
||||
|
||||
|
||||
async def cookies_db(uid, cookies, qid):
|
||||
conn = sqlite3.connect('ID_DATA.db')
|
||||
c = conn.cursor()
|
||||
|
||||
c.execute('''CREATE TABLE IF NOT EXISTS NewCookiesTable
|
||||
(UID INT PRIMARY KEY NOT NULL,
|
||||
Cookies TEXT,
|
||||
QID INT,
|
||||
StatusA TEXT,
|
||||
StatusB TEXT,
|
||||
StatusC TEXT,
|
||||
NUM INT,
|
||||
Extra TEXT);''')
|
||||
|
||||
cursor = c.execute("SELECT * from NewCookiesTable WHERE UID = ?", (uid,))
|
||||
c_data = cursor.fetchall()
|
||||
if len(c_data) == 0:
|
||||
c.execute("INSERT OR IGNORE INTO NewCookiesTable (Cookies,UID,StatusA,StatusB,StatusC,NUM,QID) \
|
||||
VALUES (?, ?,?,?,?,?,?)", (cookies, uid, "off", "off", "off", 140, qid))
|
||||
else:
|
||||
c.execute("UPDATE NewCookiesTable SET Cookies = ? WHERE UID=?", (cookies, uid))
|
||||
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
async def stoken_db(s_cookies,uid):
|
||||
conn = sqlite3.connect('ID_DATA.db')
|
||||
c = conn.cursor()
|
||||
columns = [i[1] for i in c.execute('PRAGMA table_info(NewCookiesTable)')]
|
||||
|
||||
if "Stoken" not in columns:
|
||||
c.execute('ALTER TABLE NewCookiesTable ADD COLUMN Stoken TEXT')
|
||||
|
||||
c.execute("UPDATE NewCookiesTable SET Stoken = ? WHERE UID=?", (s_cookies, int(uid)))
|
||||
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
async def get_stoken(uid):
|
||||
conn = sqlite3.connect('ID_DATA.db')
|
||||
c = conn.cursor()
|
||||
try:
|
||||
cursor = c.execute("SELECT * FROM NewCookiesTable WHERE UID = ?", (uid,))
|
||||
c_data = cursor.fetchall()
|
||||
stoken = c_data[0][8]
|
||||
except:
|
||||
return
|
||||
|
||||
return stoken
|
||||
|
||||
async def owner_cookies(uid):
|
||||
conn = sqlite3.connect('ID_DATA.db')
|
||||
c = conn.cursor()
|
||||
try:
|
||||
cursor = c.execute("SELECT * FROM NewCookiesTable WHERE UID = ?", (uid,))
|
||||
c_data = cursor.fetchall()
|
||||
cookies = c_data[0][1]
|
||||
except:
|
||||
return
|
||||
|
||||
return cookies
|
||||
|
||||
|
||||
def random_hex(length):
|
||||
result = hex(random.randint(0, 16 ** length)).replace('0x', '').upper()
|
||||
if len(result) < length:
|
||||
result = "0" * (length - len(result)) + result
|
||||
return result
|
||||
|
||||
|
||||
def md5(text):
|
||||
md5_func = hashlib.md5()
|
||||
md5_func.update(text.encode())
|
||||
return md5_func.hexdigest()
|
||||
|
||||
|
||||
def old_version_get_ds_token(mysbbs = False):
|
||||
if mysbbs:
|
||||
n = "fd3ykrh7o1j54g581upo1tvpam0dsgtf"
|
||||
else:
|
||||
n = "h8w582wxwgqvahcdkpvdhbh2w9casgfl"
|
||||
i = str(int(time.time()))
|
||||
r = ''.join(random.sample(string.ascii_lowercase + string.digits, 6))
|
||||
c = md5("salt=" + n + "&t=" + i + "&r=" + r)
|
||||
return i + "," + r + "," + c
|
||||
|
||||
|
||||
def get_ds_token(q="", b=None):
|
||||
if b:
|
||||
br = json.dumps(b)
|
||||
else:
|
||||
br = ""
|
||||
s = "xV8v4Qu54lUKrEYFZkJhB8cuOh9Asafs"
|
||||
t = str(int(time.time()))
|
||||
r = str(random.randint(100000, 200000))
|
||||
c = md5("salt=" + s + "&t=" + t + "&r=" + r + "&b=" + br + "&q=" + q)
|
||||
return t + "," + r + "," + c
|
||||
|
||||
async def get_stoken_by_login_ticket(loginticket,mys_id):
|
||||
async with AsyncClient() as client:
|
||||
req = await client.get(
|
||||
url="https://api-takumi.mihoyo.com/auth/api/getMultiTokenByLoginTicket",
|
||||
params={
|
||||
"login_ticket": loginticket,
|
||||
"token_types": "3",
|
||||
"uid": mys_id
|
||||
}
|
||||
)
|
||||
return req.json()
|
||||
|
||||
async def get_daily_data(uid, server_id="cn_gf01"):
|
||||
if uid[0] == '5':
|
||||
server_id = "cn_qd01"
|
||||
try:
|
||||
async with AsyncClient() as client:
|
||||
req = await client.get(
|
||||
url="https://api-takumi.mihoyo.com/game_record/app/genshin/api/dailyNote",
|
||||
headers={
|
||||
'DS': get_ds_token("role_id=" + uid + "&server=" + server_id),
|
||||
'x-rpc-app_version': mhyVersion,
|
||||
'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 ('
|
||||
'KHTML, like Gecko) miHoYoBBS/2.11.1',
|
||||
'x-rpc-client_type': '5',
|
||||
'Referer': 'https://webstatic.mihoyo.com/',
|
||||
"Cookie": await owner_cookies(uid)},
|
||||
params={
|
||||
"server": server_id,
|
||||
"role_id": uid
|
||||
}
|
||||
)
|
||||
data = json.loads(req.text)
|
||||
return data
|
||||
except requests.exceptions.SSLError:
|
||||
try:
|
||||
async with AsyncClient() as client:
|
||||
req = await client.get(
|
||||
url="https://api-takumi-record.mihoyo.com/game_record/app/genshin/api/dailyNote",
|
||||
headers={
|
||||
'DS': get_ds_token("role_id=" + uid + "&server=" + server_id),
|
||||
'x-rpc-app_version': mhyVersion,
|
||||
'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 '
|
||||
'(KHTML, like Gecko) miHoYoBBS/2.11.1',
|
||||
'x-rpc-client_type': '5',
|
||||
'Referer': 'https://webstatic.mihoyo.com/',
|
||||
"Cookie": await owner_cookies(uid)},
|
||||
params={
|
||||
"server": server_id,
|
||||
"role_id": uid
|
||||
}
|
||||
)
|
||||
data = json.loads(req.text)
|
||||
return data
|
||||
except json.decoder.JSONDecodeError:
|
||||
print("当前状态读取Api失败!")
|
||||
except Exception as e:
|
||||
print("访问每日信息失败,请重试!")
|
||||
print(e.with_traceback)
|
||||
|
||||
|
||||
async def get_sign_list():
|
||||
try:
|
||||
async with AsyncClient() as client:
|
||||
req = await client.get(
|
||||
url="https://api-takumi.mihoyo.com/event/bbs_sign_reward/home",
|
||||
headers={
|
||||
'x-rpc-app_version': mhyVersion,
|
||||
'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 ('
|
||||
'KHTML, like Gecko) miHoYoBBS/2.11.1',
|
||||
'x-rpc-client_type': '5',
|
||||
'Referer': 'https://webstatic.mihoyo.com/'},
|
||||
params={
|
||||
"act_id": "e202009291139501"
|
||||
}
|
||||
)
|
||||
data = json.loads(req.text)
|
||||
return data
|
||||
except:
|
||||
print("获取签到奖励列表失败,请重试")
|
||||
|
||||
|
||||
async def get_sign_info(uid, server_id="cn_gf01"):
|
||||
if uid[0] == '5':
|
||||
server_id = "cn_qd01"
|
||||
try:
|
||||
async with AsyncClient() as client:
|
||||
req = await client.get(
|
||||
url="https://api-takumi.mihoyo.com/event/bbs_sign_reward/info",
|
||||
headers={
|
||||
'x-rpc-app_version': mhyVersion,
|
||||
"Cookie": await owner_cookies(uid),
|
||||
'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 ('
|
||||
'KHTML, like Gecko) miHoYoBBS/2.11.1',
|
||||
'x-rpc-client_type': '5',
|
||||
'Referer': 'https://webstatic.mihoyo.com/'},
|
||||
params={
|
||||
"act_id": "e202009291139501",
|
||||
"region": server_id,
|
||||
"uid": uid
|
||||
}
|
||||
)
|
||||
data = json.loads(req.text)
|
||||
return data
|
||||
except:
|
||||
print("获取签到信息失败,请重试")
|
||||
|
||||
|
||||
async def mihoyo_bbs_sign(uid, server_id="cn_gf01"):
|
||||
if uid[0] == '5':
|
||||
server_id = "cn_qd01"
|
||||
try:
|
||||
req = requests.post(
|
||||
url="https://api-takumi.mihoyo.com/event/bbs_sign_reward/sign",
|
||||
headers={
|
||||
'User_Agent': 'Mozilla/5.0 (Linux; Android 10; MIX 2 Build/QKQ1.190825.002; wv) AppleWebKit/537.36 ('
|
||||
'KHTML, like Gecko) Version/4.0 Chrome/83.0.4103.101 Mobile Safari/537.36 '
|
||||
'miHoYoBBS/2.3.0',
|
||||
"Cookie": await owner_cookies(uid),
|
||||
"x-rpc-device_id": random_hex(32),
|
||||
'Origin': 'https://webstatic.mihoyo.com',
|
||||
'X_Requested_With': 'com.mihoyo.hyperion',
|
||||
'DS': old_version_get_ds_token(),
|
||||
'x-rpc-client_type': '5',
|
||||
'Referer': 'https://webstatic.mihoyo.com/bbs/event/signin-ys/index.html?bbs_auth_required=true&act_id'
|
||||
'=e202009291139501&utm_source=bbs&utm_medium=mys&utm_campaign=icon',
|
||||
'x-rpc-app_version': '2.3.0'
|
||||
},
|
||||
json={"act_id": "e202009291139501", "uid": uid, "region": server_id}
|
||||
)
|
||||
data2 = json.loads(req.text)
|
||||
return data2
|
||||
except:
|
||||
print("签到失败,请重试")
|
||||
|
||||
|
||||
async def get_award(uid, server_id="cn_gf01"):
|
||||
if uid[0] == '5':
|
||||
server_id = "cn_qd01"
|
||||
try:
|
||||
async with AsyncClient() as client:
|
||||
req = await client.get(
|
||||
url="https://hk4e-api.mihoyo.com/event/ys_ledger/monthInfo",
|
||||
headers={
|
||||
'x-rpc-app_version': mhyVersion,
|
||||
"Cookie": await owner_cookies(uid),
|
||||
'DS': old_version_get_ds_token(),
|
||||
"x-rpc-device_id": random_hex(32),
|
||||
'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 ('
|
||||
'KHTML, like Gecko) miHoYoBBS/2.11.1',
|
||||
'x-rpc-client_type': '5',
|
||||
'Referer': 'https://webstatic.mihoyo.com/'},
|
||||
params={
|
||||
"act_id": "e202009291139501",
|
||||
"bind_region": server_id,
|
||||
"bind_uid": uid,
|
||||
"month": "0",
|
||||
"bbs_presentation_style": "fullscreen",
|
||||
"bbs_auth_required": True,
|
||||
"utm_source": "bbs",
|
||||
"utm_medium": "mys",
|
||||
"utm_campaign": "icon"
|
||||
}
|
||||
)
|
||||
data = json.loads(req.text)
|
||||
return data
|
||||
except:
|
||||
print("访问失败,请重试!")
|
||||
# sys.exit(1)
|
||||
|
||||
|
||||
async def get_info(uid, ck, server_id="cn_gf01"):
|
||||
if uid[0] == '5':
|
||||
server_id = "cn_qd01"
|
||||
try:
|
||||
async with AsyncClient() as client:
|
||||
req = await client.get(
|
||||
url="https://api-takumi.mihoyo.com/game_record/app/genshin/api/index",
|
||||
headers={
|
||||
'DS': get_ds_token("role_id=" + uid + "&server=" + server_id),
|
||||
'x-rpc-app_version': mhyVersion,
|
||||
'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 ('
|
||||
'KHTML, like Gecko) miHoYoBBS/2.11.1',
|
||||
'x-rpc-client_type': '5',
|
||||
'Referer': 'https://webstatic.mihoyo.com/',
|
||||
"Cookie": ck},
|
||||
params={
|
||||
"role_id": uid,
|
||||
"server": server_id
|
||||
}
|
||||
)
|
||||
data = json.loads(req.text)
|
||||
return data
|
||||
except requests.exceptions.SSLError:
|
||||
try:
|
||||
async with AsyncClient() as client:
|
||||
req = await client.get(
|
||||
url="https://api-takumi-record.mihoyo.com/game_record/app/genshin/api/index",
|
||||
headers={
|
||||
'DS': get_ds_token("role_id=" + uid + "&server=" + server_id),
|
||||
'x-rpc-app_version': mhyVersion,
|
||||
'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 '
|
||||
'(KHTML, like Gecko) miHoYoBBS/2.11.1',
|
||||
'x-rpc-client_type': '5',
|
||||
'Referer': 'https://webstatic.mihoyo.com/',
|
||||
"Cookie": ck},
|
||||
params={
|
||||
"role_id": uid,
|
||||
"server": server_id
|
||||
}
|
||||
)
|
||||
data = json.loads(req.text)
|
||||
return data
|
||||
except json.decoder.JSONDecodeError:
|
||||
print("米游社基础信息读取新Api失败!")
|
||||
except Exception as e:
|
||||
print("米游社基础信息读取旧Api失败!")
|
||||
print(e.with_traceback)
|
||||
|
||||
|
||||
async def get_spiral_abyss_info(uid, ck, schedule_type="1", server_id="cn_gf01"):
|
||||
if uid[0] == '5':
|
||||
server_id = "cn_qd01"
|
||||
try:
|
||||
async with AsyncClient() as client:
|
||||
req = await client.get(
|
||||
url="https://api-takumi.mihoyo.com/game_record/app/genshin/api/spiralAbyss",
|
||||
headers={
|
||||
'DS': get_ds_token("role_id=" + uid + "&schedule_type=" + schedule_type + "&server=" + server_id),
|
||||
'Origin': 'https://webstatic.mihoyo.com',
|
||||
'Cookie': ck,
|
||||
'x-rpc-app_version': mhyVersion,
|
||||
'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS '
|
||||
'X) AppleWebKit/605.1.15 (KHTML, like Gecko) miHoYoBBS/2.11.1',
|
||||
'x-rpc-client_type': '5',
|
||||
'Referer': 'https://webstatic.mihoyo.com/'
|
||||
},
|
||||
params={
|
||||
"schedule_type": schedule_type,
|
||||
"role_id": uid,
|
||||
"server": server_id
|
||||
}
|
||||
)
|
||||
data = json.loads(req.text)
|
||||
return data
|
||||
except requests.exceptions.SSLError:
|
||||
try:
|
||||
async with AsyncClient() as client:
|
||||
req = await client.get(
|
||||
url="https://api-takumi-record.mihoyo.com/game_record/app/genshin/api/spiralAbyss",
|
||||
headers={
|
||||
'DS': get_ds_token(
|
||||
"role_id=" + uid + "&schedule_type=" + schedule_type + "&server=" + server_id),
|
||||
'Origin': 'https://webstatic.mihoyo.com',
|
||||
'Cookie': ck,
|
||||
'x-rpc-app_version': mhyVersion,
|
||||
'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 '
|
||||
'(KHTML, like Gecko) miHoYoBBS/2.11.1',
|
||||
'x-rpc-client_type': '5',
|
||||
'Referer': 'https://webstatic.mihoyo.com/'
|
||||
},
|
||||
params={
|
||||
"role_id": uid,
|
||||
"server": server_id,
|
||||
"bbs_presentation_style": "fullscreen",
|
||||
"bbs_auth_required": "true",
|
||||
"utm_source": "bbs",
|
||||
"utm_medium": "mys",
|
||||
"utm_campaign": "icon"
|
||||
}
|
||||
)
|
||||
data = json.loads(req.text)
|
||||
return data
|
||||
except json.decoder.JSONDecodeError:
|
||||
print("深渊信息读取新Api失败!")
|
||||
except Exception as e:
|
||||
print("深渊信息读取老Api失败!")
|
||||
print(e.with_traceback)
|
||||
|
||||
|
||||
def get_character(uid, character_ids, ck, server_id="cn_gf01"):
|
||||
if uid[0] == '5':
|
||||
server_id = "cn_qd01"
|
||||
try:
|
||||
req = requests.post(
|
||||
url="https://api-takumi.mihoyo.com/game_record/app/genshin/api/character",
|
||||
headers={
|
||||
'DS': get_ds_token('', {"character_ids": character_ids, "role_id": uid, "server": server_id}),
|
||||
'Origin': 'https://webstatic.mihoyo.com',
|
||||
'Cookie': ck,
|
||||
'x-rpc-app_version': mhyVersion,
|
||||
'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, '
|
||||
'like Gecko) miHoYoBBS/2.11.1',
|
||||
'x-rpc-client_type': '5',
|
||||
'Referer': 'https://webstatic.mihoyo.com/'
|
||||
},
|
||||
json={"character_ids": character_ids, "role_id": uid, "server": server_id}
|
||||
)
|
||||
data2 = json.loads(req.text)
|
||||
return data2
|
||||
except requests.exceptions.SSLError:
|
||||
try:
|
||||
req = requests.post(
|
||||
url="https://api-takumi-record.mihoyo.com/game_record/app/genshin/api/character",
|
||||
headers={
|
||||
'DS': get_ds_token('', {"character_ids": character_ids, "role_id": uid, "server": server_id}),
|
||||
'Origin': 'https://webstatic.mihoyo.com',
|
||||
'Cookie': ck,
|
||||
'x-rpc-app_version': mhyVersion,
|
||||
'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 ('
|
||||
'KHTML, like Gecko) miHoYoBBS/2.11.1',
|
||||
'x-rpc-client_type': '5',
|
||||
'Referer': 'https://webstatic.mihoyo.com/'
|
||||
},
|
||||
json={"character_ids": character_ids, "role_id": uid, "server": server_id}
|
||||
)
|
||||
data = json.loads(req.text)
|
||||
return data
|
||||
except json.decoder.JSONDecodeError:
|
||||
print("深渊信息读取新Api失败!")
|
||||
except Exception as e:
|
||||
print("深渊信息读取老Api失败!")
|
||||
print(e.with_traceback)
|
||||
|
||||
|
||||
async def get_mihoyo_bbs_info(mysid, ck):
|
||||
try:
|
||||
async with AsyncClient() as client:
|
||||
req = await client.get(
|
||||
url="https://api-takumi.mihoyo.com/game_record/card/wapi/getGameRecordCard",
|
||||
headers={
|
||||
'DS': get_ds_token("uid=" + mysid),
|
||||
'x-rpc-app_version': mhyVersion,
|
||||
'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 ('
|
||||
'KHTML, like Gecko) miHoYoBBS/2.11.1',
|
||||
'x-rpc-client_type': '5',
|
||||
'Referer': 'https://webstatic.mihoyo.com/',
|
||||
"Cookie": ck},
|
||||
params={"uid": mysid}
|
||||
)
|
||||
data = json.loads(req.text)
|
||||
return data
|
||||
except requests.exceptions.SSLError:
|
||||
try:
|
||||
async with AsyncClient() as client:
|
||||
req = await client.get(
|
||||
url="https://api-takumi-record.mihoyo.com/game_record/card/wapi/getGameRecordCard?uid=" + mysid,
|
||||
headers={
|
||||
'DS': get_ds_token("uid=" + mysid),
|
||||
'x-rpc-app_version': mhyVersion,
|
||||
'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 13_2_3 like Mac OS X) AppleWebKit/605.1.15 '
|
||||
'(KHTML, like Gecko) miHoYoBBS/2.11.1',
|
||||
'x-rpc-client_type': '5',
|
||||
'Referer': 'https://webstatic.mihoyo.com/',
|
||||
"Cookie": ck},
|
||||
params={"uid": mysid}
|
||||
)
|
||||
data = json.loads(req.text)
|
||||
return data
|
||||
except json.decoder.JSONDecodeError:
|
||||
print("米游社信息读取新Api失败!")
|
||||
except Exception as e:
|
||||
print("米游社信息读取老Api失败!")
|
||||
print(e.with_traceback)
|
||||
|
||||
|
||||
async def get_audio_info(name, audioid, language="cn"):
|
||||
url = "https://genshin.minigg.cn/?characters=" + name + "&audioid=" + audioid + "&language=" + language
|
||||
async with AsyncClient() as client:
|
||||
req = await client.get(
|
||||
url=url,
|
||||
headers={
|
||||
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) '
|
||||
'Chrome/95.0.4638.69 Safari/537.36',
|
||||
'Referer': 'https://genshin.minigg.cn/index.html'},
|
||||
params={"characters": name, "audioid": audioid, "language": language}
|
||||
)
|
||||
return req.text
|
||||
|
||||
|
||||
async def get_weapon_info(name, level=None):
|
||||
if level:
|
||||
params = {"query": name, "stats": level}
|
||||
else:
|
||||
params = {"query": name}
|
||||
async with AsyncClient() as client:
|
||||
req = await client.get(
|
||||
url="https://info.minigg.cn/weapons",
|
||||
headers={
|
||||
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) '
|
||||
'Chrome/95.0.4638.69 Safari/537.36'},
|
||||
params=params
|
||||
)
|
||||
data = json.loads(req.text)
|
||||
return data
|
||||
|
||||
|
||||
async def get_misc_info(mode, name):
|
||||
url = "https://info.minigg.cn/{}".format(mode)
|
||||
async with AsyncClient() as client:
|
||||
req = await client.get(
|
||||
url=url,
|
||||
headers={
|
||||
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) '
|
||||
'Chrome/97.0.4692.71 Safari/537.36'},
|
||||
params={"query": name}
|
||||
)
|
||||
data = json.loads(req.text)
|
||||
return data
|
||||
|
||||
|
||||
async def get_char_info(name, mode="char", level=None):
|
||||
url2 = None
|
||||
data2 = None
|
||||
baseurl = "https://info.minigg.cn/characters?query="
|
||||
if mode == "talents":
|
||||
url = "https://info.minigg.cn/talents?query=" + name
|
||||
elif mode == "constellations":
|
||||
url = "https://info.minigg.cn/constellations?query=" + name
|
||||
elif mode == "costs":
|
||||
url = baseurl + name + "&costs=1"
|
||||
url2 = "https://info.minigg.cn/talents?query=" + name + "&costs=1"
|
||||
url3 = "https://info.minigg.cn/talents?query=" + name + "&matchCategories=true"
|
||||
elif level:
|
||||
url = baseurl + name + "&stats=" + level
|
||||
else:
|
||||
url = baseurl + name
|
||||
|
||||
if url2:
|
||||
async with AsyncClient() as client:
|
||||
req = await client.get(
|
||||
url=url2,
|
||||
headers={
|
||||
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) '
|
||||
'Chrome/95.0.4638.69 Safari/537.36',
|
||||
'Referer': 'https://genshin.minigg.cn/index.html'})
|
||||
data2 = json.loads(req.text)
|
||||
if "errcode" in data2:
|
||||
async with AsyncClient() as client_:
|
||||
req = await client_.get(
|
||||
url=url3,
|
||||
headers={
|
||||
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, '
|
||||
'like Gecko) Chrome/95.0.4638.69 Safari/537.36',
|
||||
'Referer': 'https://genshin.minigg.cn/index.html'})
|
||||
data2 = json.loads(req.text)
|
||||
|
||||
async with AsyncClient() as client:
|
||||
req = await client.get(
|
||||
url=url,
|
||||
headers={
|
||||
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) '
|
||||
'Chrome/95.0.4638.69 Safari/537.36',
|
||||
'Referer': 'https://genshin.minigg.cn/index.html'})
|
||||
try:
|
||||
data = json.loads(req.text)
|
||||
if "errcode" in data:
|
||||
async with AsyncClient() as client_:
|
||||
req = await client_.get(
|
||||
url=url + "&matchCategories=true",
|
||||
headers={
|
||||
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, '
|
||||
'like Gecko) Chrome/95.0.4638.69 Safari/537.36',
|
||||
'Referer': 'https://genshin.minigg.cn/index.html'})
|
||||
data = json.loads(req.text)
|
||||
except:
|
||||
data = None
|
||||
return data if data2 is None else [data, data2]
|
||||
|
||||
|
||||
async def get_genshin_events(mode="List"):
|
||||
if mode == "Calendar":
|
||||
now_time = datetime.datetime.now().strftime('%Y-%m-%d')
|
||||
base_url = "https://api-takumi.mihoyo.com/event/bbs_activity_calendar/getActList"
|
||||
params = {
|
||||
"time": now_time,
|
||||
"game_biz": "ys_cn",
|
||||
"page": 1,
|
||||
"tag_id": 0
|
||||
}
|
||||
else:
|
||||
base_url = "https://hk4e-api.mihoyo.com/common/hk4e_cn/announcement/api/getAnn{}".format(mode)
|
||||
params = {
|
||||
"game": "hk4e",
|
||||
"game_biz": "hk4e_cn",
|
||||
"lang": "zh-cn",
|
||||
"bundle_id": "hk4e_cn",
|
||||
"platform": "pc",
|
||||
"region": "cn_gf01",
|
||||
"level": 55,
|
||||
"uid": 100000000
|
||||
}
|
||||
|
||||
async with AsyncClient() as client:
|
||||
req = await client.get(
|
||||
url=base_url,
|
||||
headers={
|
||||
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) '
|
||||
'Chrome/95.0.4638.69 Safari/537.36'},
|
||||
params=params
|
||||
)
|
||||
data = json.loads(req.text)
|
||||
return data
|
1606
mihoyo_libs/get_image.py
Normal file
232
mihoyo_libs/get_mihoyo_bbs_coin.py
Normal file
@ -0,0 +1,232 @@
|
||||
import time
|
||||
import random
|
||||
import string
|
||||
|
||||
from httpx import AsyncClient
|
||||
|
||||
from get_data import old_version_get_ds_token,random_hex
|
||||
|
||||
# 米游社的API列表
|
||||
bbs_Cookieurl = "https://webapi.account.mihoyo.com/Api/cookie_accountinfo_by_loginticket?login_ticket={}"
|
||||
bbs_Cookieurl2 = "https://api-takumi.mihoyo.com/auth/api/getMultiTokenByLoginTicket?login_ticket={}&token_types=3&uid={}"
|
||||
bbs_Taskslist = "https://bbs-api.mihoyo.com/apihub/sapi/getUserMissionsState" # 获取任务列表
|
||||
bbs_Signurl = "https://bbs-api.mihoyo.com/apihub/sapi/signIn?gids={}" # post
|
||||
bbs_Listurl = "https://bbs-api.mihoyo.com/post/api/getForumPostList?forum_id={}&is_good=false&is_hot=false&page_size=20&sort_type=1"
|
||||
bbs_Detailurl = "https://bbs-api.mihoyo.com/post/api/getPostFull?post_id={}"
|
||||
bbs_Shareurl = "https://bbs-api.mihoyo.com/apihub/api/getShareConf?entity_id={}&entity_type=1"
|
||||
bbs_Likeurl = "https://bbs-api.mihoyo.com/apihub/sapi/upvotePost" # post json
|
||||
|
||||
mihoyobbs_List = [{
|
||||
"id": "1",
|
||||
"forumId": "1",
|
||||
"name": "崩坏3",
|
||||
"url": "https://bbs.mihoyo.com/bh3/"
|
||||
}, {
|
||||
"id": "2",
|
||||
"forumId": "26",
|
||||
"name": "原神",
|
||||
"url": "https://bbs.mihoyo.com/ys/"
|
||||
}, {
|
||||
"id": "3",
|
||||
"forumId": "30",
|
||||
"name": "崩坏2",
|
||||
"url": "https://bbs.mihoyo.com/bh2/"
|
||||
}, {
|
||||
"id": "4",
|
||||
"forumId": "37",
|
||||
"name": "未定事件簿",
|
||||
"url": "https://bbs.mihoyo.com/wd/"
|
||||
}, {
|
||||
"id": "5",
|
||||
"forumId": "34",
|
||||
"name": "大别野",
|
||||
"url": "https://bbs.mihoyo.com/dby/"
|
||||
}, {
|
||||
"id": "6",
|
||||
"forumId": "52",
|
||||
"name": "崩坏:星穹铁道",
|
||||
"url": "https://bbs.mihoyo.com/sr/"
|
||||
}]
|
||||
|
||||
def random_text(num: int) -> str:
|
||||
return ''.join(random.sample(string.ascii_lowercase + string.digits, num))
|
||||
|
||||
class mihoyobbs_coin:
|
||||
def __init__(self,cookies):
|
||||
self.headers = {
|
||||
"DS": old_version_get_ds_token(True),
|
||||
"cookie": cookies,
|
||||
"x-rpc-client_type": "2",
|
||||
"x-rpc-app_version": "2.7.0",
|
||||
"x-rpc-sys_version": "6.0.1",
|
||||
"x-rpc-channel": "mihoyo",
|
||||
"x-rpc-device_id": random_hex(32),
|
||||
"x-rpc-device_name": random_text(random.randint(1, 10)),
|
||||
"x-rpc-device_model": "Mi 10",
|
||||
"Referer": "https://app.mihoyo.com",
|
||||
"Host": "bbs-api.mihoyo.com",
|
||||
"User-Agent": "okhttp/4.8.0"
|
||||
}
|
||||
self.Task_do = {
|
||||
"bbs_Sign": False,
|
||||
"bbs_Read_posts": False,
|
||||
"bbs_Read_posts_num": 3,
|
||||
"bbs_Like_posts": False,
|
||||
"bbs_Like_posts_num": 5,
|
||||
"bbs_Share": False
|
||||
}
|
||||
self.mihoyobbs_List_Use = []
|
||||
self.Today_getcoins = 0
|
||||
self.Today_have_getcoins = 0 # 这个变量以后可能会用上,先留着了
|
||||
self.Have_coins = 0
|
||||
|
||||
async def task_run(self):
|
||||
await self.Load_Mihoyobbs_List_Use()
|
||||
start = await self.Get_taskslist()
|
||||
self.postsList = await self.get_list()
|
||||
sign = await self.signing()
|
||||
read = await self.read_posts()
|
||||
like = await self.Likeposts()
|
||||
share = await self.share_post()
|
||||
im = start + "\n" + sign + "\n" + read + "\n" + like + "\n" + share
|
||||
return im
|
||||
|
||||
async def Load_Mihoyobbs_List_Use(self):
|
||||
for i in [2,5]:
|
||||
for k in mihoyobbs_List:
|
||||
if i == int(k["id"]):
|
||||
self.mihoyobbs_List_Use.append(k)
|
||||
|
||||
# 获取任务列表,用来判断做了哪些任务
|
||||
async def Get_taskslist(self):
|
||||
#log.info("正在获取任务列表")
|
||||
async with AsyncClient() as client:
|
||||
req = await client.get(url = bbs_Taskslist, headers = self.headers)
|
||||
data = req.json()
|
||||
if "err" in data["message"] or data["retcode"] == -100:
|
||||
return "你的Cookies已失效。"
|
||||
#log.error("获取任务列表失败,你的cookie可能已过期,请重新设置cookie。")
|
||||
else:
|
||||
self.Today_getcoins = data["data"]["can_get_points"]
|
||||
self.Today_have_getcoins = data["data"]["already_received_points"]
|
||||
self.Have_coins = data["data"]["total_points"]
|
||||
# 如果当日可获取米游币数量为0直接判断全部任务都完成了
|
||||
if self.Today_getcoins == 0:
|
||||
self.Task_do["bbs_Sign"] = True
|
||||
self.Task_do["bbs_Read_posts"] = True
|
||||
self.Task_do["bbs_Like_posts"] = True
|
||||
self.Task_do["bbs_Share"] = True
|
||||
else:
|
||||
# 如果第0个大于或等于62则直接判定任务没做
|
||||
if data["data"]["states"][0]["mission_id"] >= 62:
|
||||
#log.info(f"新的一天,今天可以获得{self.Today_getcoins}个米游币")
|
||||
pass
|
||||
else:
|
||||
#log.info(f"似乎还有任务没完成,今天还能获得{self.Today_getcoins}")
|
||||
for i in data["data"]["states"]:
|
||||
# 58是讨论区签到
|
||||
if i["mission_id"] == 58:
|
||||
if i["is_get_award"]:
|
||||
self.Task_do["bbs_Sign"] = True
|
||||
# 59是看帖子
|
||||
elif i["mission_id"] == 59:
|
||||
if i["is_get_award"]:
|
||||
self.Task_do["bbs_Read_posts"] = True
|
||||
else:
|
||||
self.Task_do["bbs_Read_posts_num"] -= i["happened_times"]
|
||||
# 60是给帖子点赞
|
||||
elif i["mission_id"] == 60:
|
||||
if i["is_get_award"]:
|
||||
self.Task_do["bbs_Like_posts"] = True
|
||||
else:
|
||||
self.Task_do["bbs_Like_posts_num"] -= i["happened_times"]
|
||||
# 61是分享帖子
|
||||
elif i["mission_id"] == 61:
|
||||
if i["is_get_award"]:
|
||||
self.Task_do["bbs_Share"] = True
|
||||
# 分享帖子,是最后一个任务,到这里了下面都是一次性任务,直接跳出循环
|
||||
break
|
||||
return "开始执行~"
|
||||
|
||||
# 获取要帖子列表
|
||||
async def get_list(self) -> list:
|
||||
temp_list = []
|
||||
print("正在获取帖子列表......")
|
||||
async with AsyncClient() as client:
|
||||
req = await client.get(url=bbs_Listurl.format(self.mihoyobbs_List_Use[0]["forumId"]), headers=self.headers)
|
||||
data = req.json()
|
||||
for n in range(5):
|
||||
temp_list.append([data["data"]["list"][n]["post"]["post_id"], data["data"]["list"][n]["post"]["subject"]])
|
||||
#log.info("已获取{}个帖子".format(len(temp_list)))
|
||||
return temp_list
|
||||
|
||||
# 进行签到操作
|
||||
async def signing(self):
|
||||
if self.Task_do["bbs_Sign"]:
|
||||
return "讨论区任务已经完成过了~"
|
||||
else:
|
||||
for i in self.mihoyobbs_List_Use:
|
||||
async with AsyncClient() as client:
|
||||
req = await client.post(url=bbs_Signurl.format(i["id"]), data={}, headers=self.headers)
|
||||
data = req.json()
|
||||
if "err" not in data["message"]:
|
||||
time.sleep(random.randint(2, 8))
|
||||
else:
|
||||
return "你的Cookies已失效。"
|
||||
return "已完成签到任务~"
|
||||
|
||||
|
||||
# 看帖子
|
||||
async def read_posts(self):
|
||||
if self.Task_do["bbs_Read_posts"]:
|
||||
return "看帖任务已经完成过了~"
|
||||
else:
|
||||
num_ok = 0
|
||||
for i in range(self.Task_do["bbs_Read_posts_num"]):
|
||||
async with AsyncClient() as client:
|
||||
req = await client.get(url=bbs_Detailurl.format(self.postsList[i][0]), headers=self.headers)
|
||||
data = req.json()
|
||||
if data["message"] == "OK":
|
||||
num_ok += 1
|
||||
time.sleep(random.randint(2, 8))
|
||||
return "已完成看帖任务~共计成功{}次~".format(str(num_ok))
|
||||
# 点赞
|
||||
async def Likeposts(self):
|
||||
if self.Task_do["bbs_Like_posts"]:
|
||||
return "点赞任务已经完成过了~"
|
||||
else:
|
||||
num_ok = 0
|
||||
num_cancel = 0
|
||||
for i in range(self.Task_do["bbs_Like_posts_num"]):
|
||||
async with AsyncClient() as client:
|
||||
req = await client.post(url=bbs_Likeurl, headers=self.headers,
|
||||
json={"post_id": self.postsList[i][0], "is_cancel": False})
|
||||
data = req.json()
|
||||
if data["message"] == "OK":
|
||||
num_ok += 1
|
||||
# 判断取消点赞是否打开
|
||||
if True:
|
||||
time.sleep(random.randint(2, 8))
|
||||
async with AsyncClient() as client:
|
||||
req = await client.post(url=bbs_Likeurl, headers=self.headers,
|
||||
json={"post_id": self.postsList[i][0], "is_cancel": True})
|
||||
data = req.json()
|
||||
if data["message"] == "OK":
|
||||
num_cancel += 1
|
||||
time.sleep(random.randint(2, 8))
|
||||
return "已完成点赞任务~共计点赞{}次,取消点赞{}次~".format(str(num_ok),str(num_cancel))
|
||||
# 分享操作
|
||||
|
||||
async def share_post(self):
|
||||
if self.Task_do["bbs_Share"]:
|
||||
return "分享任务已经完成过了~"
|
||||
else:
|
||||
for _ in range(3):
|
||||
async with AsyncClient() as client:
|
||||
req = await client.get(url=bbs_Shareurl.format(self.postsList[0][0]), headers=self.headers)
|
||||
data = req.json()
|
||||
if data["message"] == "OK":
|
||||
return "已完成分享任务~获得10米游币~"
|
||||
else:
|
||||
time.sleep(random.randint(2, 8))
|
||||
time.sleep(random.randint(2, 8))
|
736
mihoyo_libs/get_mihoyo_bbs_data.py
Normal file
@ -0,0 +1,736 @@
|
||||
import json
|
||||
import math
|
||||
import os
|
||||
import sys
|
||||
import random
|
||||
import re
|
||||
import sqlite3
|
||||
from base64 import b64encode
|
||||
from openpyxl import load_workbook
|
||||
from io import BytesIO
|
||||
|
||||
import requests
|
||||
|
||||
sys.path.append(os.path.dirname(os.path.abspath(__file__)))
|
||||
from .get_data import *
|
||||
from .get_image import draw_event_pic
|
||||
import get_mihoyo_bbs_coin as coin
|
||||
|
||||
FILE_PATH = os.path.dirname(__file__)
|
||||
FILE2_PATH = os.path.join(FILE_PATH, 'mihoyo_bbs')
|
||||
INDEX_PATH = os.path.join(FILE2_PATH, 'index')
|
||||
Texture_PATH = os.path.join(FILE2_PATH, 'texture2d')
|
||||
|
||||
avatar_json = {
|
||||
"Albedo": "阿贝多",
|
||||
"Ambor": "安柏",
|
||||
"Barbara": "芭芭拉",
|
||||
"Beidou": "北斗",
|
||||
"Bennett": "班尼特",
|
||||
"Chongyun": "重云",
|
||||
"Diluc": "迪卢克",
|
||||
"Diona": "迪奥娜",
|
||||
"Eula": "优菈",
|
||||
"Fischl": "菲谢尔",
|
||||
"Ganyu": "甘雨",
|
||||
"Hutao": "胡桃",
|
||||
"Jean": "琴",
|
||||
"Kazuha": "枫原万叶",
|
||||
"Kaeya": "凯亚",
|
||||
"Ayaka": "神里绫华",
|
||||
"Keqing": "刻晴",
|
||||
"Klee": "可莉",
|
||||
"Lisa": "丽莎",
|
||||
"Mona": "莫娜",
|
||||
"Ningguang": "凝光",
|
||||
"Noel": "诺艾尔",
|
||||
"Qiqi": "七七",
|
||||
"Razor": "雷泽",
|
||||
"Rosaria": "罗莎莉亚",
|
||||
"Sucrose": "砂糖",
|
||||
"Tartaglia": "达达利亚",
|
||||
"Venti": "温迪",
|
||||
"Xiangling": "香菱",
|
||||
"Xiao": "魈",
|
||||
"Xingqiu": "行秋",
|
||||
"Xinyan": "辛焱",
|
||||
"Yanfei": "烟绯",
|
||||
"Zhongli": "钟离",
|
||||
"Yoimiya": "宵宫",
|
||||
"Sayu": "早柚",
|
||||
"Shogun": "雷电将军",
|
||||
"Aloy": "埃洛伊",
|
||||
"Sara": "九条裟罗",
|
||||
"Kokomi": "珊瑚宫心海",
|
||||
"Shenhe": "申鹤"
|
||||
}
|
||||
|
||||
daily_im = '''
|
||||
*数据刷新可能存在一定延迟,请以当前游戏实际数据为准{}
|
||||
==============
|
||||
原粹树脂:{}/{}{}
|
||||
每日委托:{}/{} 奖励{}领取
|
||||
周本减半:{}/{}
|
||||
洞天宝钱:{}
|
||||
探索派遣:
|
||||
总数/完成/上限:{}/{}/{}
|
||||
{}'''
|
||||
|
||||
month_im = '''
|
||||
==============
|
||||
{}
|
||||
UID:{}
|
||||
==============
|
||||
本日获取原石:{}
|
||||
本日获取摩拉:{}
|
||||
==============
|
||||
昨日获取原石:{}
|
||||
昨日获取摩拉:{}
|
||||
==============
|
||||
本月获取原石:{}
|
||||
本月获取摩拉:{}
|
||||
==============
|
||||
上月获取原石:{}
|
||||
上月获取摩拉:{}
|
||||
==============
|
||||
原石收入组成:
|
||||
{}=============='''
|
||||
|
||||
weapon_im = '''【名称】:{}
|
||||
【类型】:{}
|
||||
【稀有度】:{}
|
||||
【介绍】:{}
|
||||
【攻击力】:{}{}{}'''
|
||||
|
||||
char_info_im = '''{}
|
||||
【稀有度】:{}
|
||||
【武器】:{}
|
||||
【元素】:{}
|
||||
【突破加成】:{}
|
||||
【生日】:{}
|
||||
【命之座】:{}
|
||||
【cv】:{}
|
||||
【介绍】:{}'''
|
||||
|
||||
artifacts_im = '''【{}】
|
||||
【稀有度】:{}
|
||||
【2件套】:{}
|
||||
【4件套】:{}
|
||||
【{}】:{}
|
||||
【{}】:{}
|
||||
【{}】:{}
|
||||
【{}】:{}
|
||||
【{}】:{}'''
|
||||
|
||||
food_im = '''【{}】
|
||||
【稀有度】:{}
|
||||
【食物类型】:{}
|
||||
【食物类别】:{}
|
||||
【效果】:{}
|
||||
【介绍】:{}
|
||||
【材料】:
|
||||
{}'''
|
||||
|
||||
audio_json = '''{
|
||||
"357":["357_01","357_02","357_03"],
|
||||
"1000000":["1000000_01","1000000_02","1000000_03","1000000_04","1000000_05","1000000_06","1000000_07"],
|
||||
"1000001":["1000001_01","1000001_02","1000001_03"],
|
||||
"1000002":["1000002_01","1000002_02","1000002_03"],
|
||||
"1000100":["1000100_01","1000100_02","1000100_03","1000100_04","1000100_05"],
|
||||
"1000101":["1000101_01","1000101_02","1000101_03","1000101_04","1000101_05","1000101_06"],
|
||||
"1000200":["1000200_01","1000200_02","1000200_03"],
|
||||
"1010201":["1010201_01"],
|
||||
"1000300":["1000300_01","1000300_02"],
|
||||
"1000400":["1000400_01","1000400_02","1000400_03"],
|
||||
"1000500":["1000500_01","1000500_02","1000500_03"],
|
||||
"1010000":["1010000_01","1010000_02","1010000_03","1010000_04","1010000_05"],
|
||||
"1010001":["1010001_01","1010001_02"],
|
||||
"1010100":["1010100_01","1010100_02","1010100_03","1010100_04","1010100_05"],
|
||||
"1010200":["1010200_01","1010200_02","1010200_03","1010200_04","1010200_05"],
|
||||
"1010300":["1010300_01","1010300_02","1010300_03","1010300_04","1010300_05"],
|
||||
"1010301":["1010301_01","1010301_02","1010301_03","1010301_04","1010301_05"],
|
||||
"1010400":["1010400_01","1010400_02","1010400_03"],
|
||||
"1020000":["1020000_01"]
|
||||
}'''
|
||||
|
||||
char_adv_im = '''【{}】
|
||||
【五星武器】:{}
|
||||
【四星武器】:{}
|
||||
【三星武器】:{}
|
||||
【圣遗物】:
|
||||
{}'''
|
||||
|
||||
async def weapon_adv(name):
|
||||
char_adv_path = os.path.join(FILE_PATH,"Genshin All Char.xlsx")
|
||||
wb = load_workbook(char_adv_path)
|
||||
ws = wb.active
|
||||
|
||||
weapon_name = ""
|
||||
char_list = []
|
||||
for c in range(2,5):
|
||||
for r in range(2,300):
|
||||
if ws.cell(r,c).value:
|
||||
#if all(i in ws.cell(r,c).value for i in name):
|
||||
if name in ws.cell(r,c).value:
|
||||
weapon_name = ws.cell(r,c).value
|
||||
char_list.append(ws.cell(2+((r-2)//5)*5,1).value)
|
||||
|
||||
if char_list != []:
|
||||
im = ','.join(char_list)
|
||||
im = im + "可能会用到【{}】".format(weapon_name)
|
||||
else:
|
||||
im = "没有角色能使用【{}】".format(weapon_name)
|
||||
return im
|
||||
|
||||
async def char_adv(name):
|
||||
char_adv_path = os.path.join(FILE_PATH,"Genshin All Char.xlsx")
|
||||
wb = load_workbook(char_adv_path)
|
||||
ws = wb.active
|
||||
char_list = ws["A"]
|
||||
index = None
|
||||
for i in char_list:
|
||||
if i.value:
|
||||
if all(g in i.value for g in name):
|
||||
#if name in i.value:
|
||||
index = i.row
|
||||
char_name = i.value
|
||||
if index:
|
||||
weapon_5star = ""
|
||||
for i in range(index,index+5):
|
||||
if ws.cell(i,2).value:
|
||||
weapon_5star += ws.cell(i,2).value + ">"
|
||||
if weapon_5star != "":
|
||||
weapon_5star = weapon_5star[:-1]
|
||||
else:
|
||||
weapon_5star = "无推荐"
|
||||
|
||||
weapon_4star = ""
|
||||
for i in range(index,index+5):
|
||||
if ws.cell(i,3).value:
|
||||
weapon_4star += ws.cell(i,3).value + ">"
|
||||
if weapon_4star != "":
|
||||
weapon_4star = weapon_4star[:-1]
|
||||
else:
|
||||
weapon_4star = "无推荐"
|
||||
|
||||
weapon_3star = ""
|
||||
for i in range(index,index+5):
|
||||
if ws.cell(i,4).value:
|
||||
weapon_3star += ws.cell(i,4).value + ">"
|
||||
if weapon_3star != "":
|
||||
weapon_3star = weapon_3star[:-1]
|
||||
else:
|
||||
weapon_3star = "无推荐"
|
||||
|
||||
artifacts = ""
|
||||
for i in range(index,index+5):
|
||||
if ws.cell(i,5).value:
|
||||
if ws.cell(i,6).value:
|
||||
artifacts += ws.cell(i,5).value + "*2" + ws.cell(i,6).value + "*2" + "\n"
|
||||
else:
|
||||
artifacts += ws.cell(i,5).value + "*4" + "\n"
|
||||
|
||||
if artifacts != "":
|
||||
artifacts = artifacts[:-1]
|
||||
else:
|
||||
artifacts = "无推荐"
|
||||
|
||||
im = char_adv_im.format(char_name,weapon_5star,weapon_4star,weapon_3star,artifacts)
|
||||
return im
|
||||
|
||||
async def deal_ck(mes, qid):
|
||||
if "stoken" in mes:
|
||||
login_ticket = re.search(r"login_ticket=([0-9a-zA-Z]+)", mes).group(0).split('=')[1]
|
||||
uid = await select_db(qid,"uid")
|
||||
#mys_id = re.search(r"login_uid=([0-9]+)", mes).group(0).split('=')[1]
|
||||
ck = await owner_cookies(uid[0])
|
||||
mys_id = re.search(r"account_id=(\d*)", ck).group(0).split('=')[1]
|
||||
raw_data = await get_stoken_by_login_ticket(login_ticket,mys_id)
|
||||
stoken = raw_data["data"]["list"][0]["token"]
|
||||
s_cookies = "stuid={};stoken={}".format(mys_id,stoken)
|
||||
await stoken_db(s_cookies,uid[0])
|
||||
return "添加Stoken成功!"
|
||||
else:
|
||||
aid = re.search(r"account_id=(\d*)", mes)
|
||||
mysid_data = aid.group(0).split('=')
|
||||
mysid = mysid_data[1]
|
||||
cookie = ';'.join(filter(lambda x: x.split('=')[0] in [
|
||||
"cookie_token", "account_id"], [i.strip() for i in mes.split(';')]))
|
||||
mys_data = await get_mihoyo_bbs_info(mysid, cookie)
|
||||
for i in mys_data['data']['list']:
|
||||
if i['game_id'] != 2:
|
||||
mys_data['data']['list'].remove(i)
|
||||
uid = mys_data['data']['list'][0]['game_role_id']
|
||||
|
||||
conn = sqlite3.connect('ID_DATA.db')
|
||||
c = conn.cursor()
|
||||
|
||||
try:
|
||||
c.execute("DELETE from CookiesCache where uid=? or mysid = ?", (uid, mysid))
|
||||
except:
|
||||
pass
|
||||
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
await cookies_db(uid, cookie, qid)
|
||||
return f'添加Cookies成功!\nCookies属于个人重要信息,如果你是在不知情的情况下添加,请马上修改米游社账户密码,保护个人隐私!\n————\n' \
|
||||
f'如果需要【开启自动签到】和【开启推送】还需要在【群聊中】使用命令“绑定uid”绑定你的uid。\n例如:绑定uid123456789。'
|
||||
|
||||
async def award(uid):
|
||||
data = await get_award(uid)
|
||||
nickname = data['data']['nickname']
|
||||
day_stone = data['data']['day_data']['current_primogems']
|
||||
day_mora = data['data']['day_data']['current_mora']
|
||||
lastday_stone = data['data']['day_data']['last_primogems']
|
||||
lastday_mora = data['data']['day_data']['last_mora']
|
||||
month_stone = data['data']['month_data']['current_primogems']
|
||||
month_mora = data['data']['month_data']['current_mora']
|
||||
lastmonth_stone = data['data']['month_data']['last_primogems']
|
||||
lastmonth_mora = data['data']['month_data']['last_mora']
|
||||
group_str = ''
|
||||
for i in data['data']['month_data']['group_by']:
|
||||
group_str = group_str + \
|
||||
i['action'] + ":" + str(i['num']) + \
|
||||
"(" + str(i['percent']) + "%)" + '\n'
|
||||
|
||||
im = month_im.format(nickname, uid, day_stone, day_mora, lastday_stone, lastday_mora,
|
||||
month_stone, month_mora, lastmonth_stone, lastmonth_mora, group_str)
|
||||
return im
|
||||
|
||||
|
||||
async def audio_wiki(name, message):
|
||||
async def get(_audioid):
|
||||
tmp_json = json.loads(audio_json)
|
||||
for _ in range(3): # 重试3次
|
||||
if _audioid in tmp_json:
|
||||
if not tmp_json[_audioid]:
|
||||
return
|
||||
audioid1 = random.choice(tmp_json[_audioid])
|
||||
else:
|
||||
audioid1 = _audioid
|
||||
url = await get_audio_info(name, audioid1)
|
||||
req = requests.get(url)
|
||||
if req.headers["Content-Type"].startswith("audio"):
|
||||
return BytesIO(req.content)
|
||||
else:
|
||||
if _audioid in tmp_json:
|
||||
tmp_json[_audioid].remove(audioid1)
|
||||
|
||||
if name == "列表":
|
||||
imgmes = 'base64://' + b64encode(open(os.path.join(INDEX_PATH, "语音.png"), "rb").read()).decode()
|
||||
return imgmes
|
||||
elif name == "":
|
||||
return "角色名不正确。"
|
||||
else:
|
||||
audioid = re.findall(r"[0-9]+", message)[0]
|
||||
try:
|
||||
audio = await get(audioid)
|
||||
except:
|
||||
return "语音获取失败"
|
||||
if audio:
|
||||
audios = 'base64://' + b64encode(audio.getvalue()).decode()
|
||||
return audios
|
||||
|
||||
|
||||
async def artifacts_wiki(name):
|
||||
data = await get_misc_info("artifacts", name)
|
||||
if "errcode" in data:
|
||||
im = "该圣遗物不存在。"
|
||||
else:
|
||||
star = ""
|
||||
for i in data["rarity"]:
|
||||
star = star + i + "星、"
|
||||
star = star[:-1]
|
||||
im = artifacts_im.format(data["name"], star, data["2pc"], data["4pc"], data["flower"]["name"],
|
||||
data["flower"]["description"],
|
||||
data["plume"]["name"], data["plume"]["description"], data["sands"]["name"],
|
||||
data["sands"]["description"],
|
||||
data["goblet"]["name"], data["goblet"]["description"], data["circlet"]["name"],
|
||||
data["circlet"]["description"])
|
||||
return im
|
||||
|
||||
|
||||
async def foods_wiki(name):
|
||||
data = await get_misc_info("foods", name)
|
||||
if "errcode" in data:
|
||||
im = "该食物不存在。"
|
||||
else:
|
||||
ingredients = ""
|
||||
food_temp = {}
|
||||
for i in data["ingredients"]:
|
||||
if i["name"] not in food_temp:
|
||||
food_temp[i["name"]] = i["count"]
|
||||
else:
|
||||
food_temp[i["name"]] = food_temp[i["name"]] + i["count"]
|
||||
for i in food_temp:
|
||||
ingredients += i + ":" + str(food_temp[i]) + "\n"
|
||||
ingredients = ingredients[:-1]
|
||||
im = food_im.format(data["name"], data["rarity"], data["foodtype"], data["foodfilter"], data["effect"],
|
||||
data["description"], ingredients)
|
||||
return im
|
||||
|
||||
|
||||
async def enemies_wiki(name):
|
||||
raw_data = await get_misc_info("enemies", name)
|
||||
if "errcode" in raw_data:
|
||||
im = "该原魔不存在。"
|
||||
else:
|
||||
reward = ""
|
||||
for i in raw_data["rewardpreview"]:
|
||||
reward += i["name"] + ":" + str(i["count"]) if "count" in i.keys() else i["name"] + ":" + "可能"
|
||||
reward += "\n"
|
||||
im = "【{}】\n——{}——\n类型:{}\n信息:{}\n掉落物:\n{}".format(raw_data["name"], raw_data["specialname"],
|
||||
raw_data["category"], raw_data["description"], reward)
|
||||
return im
|
||||
|
||||
|
||||
# 签到函数
|
||||
async def sign(uid):
|
||||
try:
|
||||
sign_data = await mihoyo_bbs_sign(uid)
|
||||
sign_info = await get_sign_info(uid)
|
||||
sign_info = sign_info['data']
|
||||
sign_list = await get_sign_list()
|
||||
status = sign_data['message']
|
||||
getitem = sign_list['data']['awards'][int(
|
||||
sign_info['total_sign_day']) - 1]['name']
|
||||
getnum = sign_list['data']['awards'][int(
|
||||
sign_info['total_sign_day']) - 1]['cnt']
|
||||
get_im = f"本次签到获得{getitem}x{getnum}"
|
||||
if status == "OK" and sign_info['is_sign'] == True:
|
||||
mes_im = "签到成功"
|
||||
else:
|
||||
mes_im = status
|
||||
sign_missed = sign_info['sign_cnt_missed']
|
||||
im = mes_im + "!" + "\n" + get_im + "\n" + f"本月漏签次数:{sign_missed}"
|
||||
except:
|
||||
im = "签到失败,请检查Cookies是否失效。"
|
||||
return im
|
||||
|
||||
|
||||
# 统计状态函数
|
||||
async def daily(mode="push", uid=None):
|
||||
def seconds2hours(seconds: int) -> str:
|
||||
m, s = divmod(int(seconds), 60)
|
||||
h, m = divmod(m, 60)
|
||||
return "%02d:%02d:%02d" % (h, m, s)
|
||||
|
||||
temp_list = []
|
||||
conn = sqlite3.connect('ID_DATA.db')
|
||||
c = conn.cursor()
|
||||
if mode == "push":
|
||||
cursor = c.execute(
|
||||
"SELECT * FROM NewCookiesTable WHERE StatusA != ?", ("off",))
|
||||
c_data = cursor.fetchall()
|
||||
elif mode == "ask":
|
||||
c_data = ([uid, 0, 0, 0, 0, 0, 0],)
|
||||
|
||||
for row in c_data:
|
||||
raw_data = await get_daily_data(str(row[0]))
|
||||
if raw_data["retcode"] != 0:
|
||||
temp_list.append(
|
||||
{"qid": row[2], "gid": row[3], "message": "你的推送状态有误;可能是uid绑定错误或没有在米游社打开“实时便筏”功能。"})
|
||||
else:
|
||||
dailydata = raw_data["data"]
|
||||
current_resin = dailydata['current_resin']
|
||||
|
||||
current_expedition_num = dailydata['current_expedition_num']
|
||||
max_expedition_num = dailydata['max_expedition_num']
|
||||
finished_expedition_num = 0
|
||||
expedition_info: list[str] = []
|
||||
for expedition in dailydata['expeditions']:
|
||||
avatar: str = expedition['avatar_side_icon'][89:-4]
|
||||
try:
|
||||
avatar_name: str = avatar_json[avatar]
|
||||
except KeyError:
|
||||
avatar_name: str = avatar
|
||||
|
||||
if expedition['status'] == 'Finished':
|
||||
expedition_info.append(f"{avatar_name} 探索完成")
|
||||
finished_expedition_num += 1
|
||||
else:
|
||||
remained_timed: str = seconds2hours(
|
||||
expedition['remained_time'])
|
||||
expedition_info.append(
|
||||
f"{avatar_name} 剩余时间{remained_timed}")
|
||||
|
||||
if current_resin >= row[6] or dailydata["max_home_coin"] - dailydata["current_home_coin"] <= 100:
|
||||
tip = ''
|
||||
|
||||
if current_resin >= row[6] != 0:
|
||||
tip += "\n==============\n你的树脂快满了!"
|
||||
if dailydata["max_home_coin"] - dailydata["current_home_coin"] <= 100:
|
||||
tip += "\n==============\n你的洞天宝钱快满了!"
|
||||
# if finished_expedition_num >0:
|
||||
# tip += "\n==============\n你有探索派遣完成了!"
|
||||
max_resin = dailydata['max_resin']
|
||||
rec_time = ''
|
||||
# print(dailydata)
|
||||
if current_resin < 160:
|
||||
resin_recovery_time = seconds2hours(
|
||||
dailydata['resin_recovery_time'])
|
||||
next_resin_rec_time = seconds2hours(
|
||||
8 * 60 - ((dailydata['max_resin'] - dailydata['current_resin']) * 8 * 60 - int(
|
||||
dailydata['resin_recovery_time'])))
|
||||
rec_time = f' ({next_resin_rec_time}/{resin_recovery_time})'
|
||||
|
||||
finished_task_num = dailydata['finished_task_num']
|
||||
total_task_num = dailydata['total_task_num']
|
||||
is_extra_got = '已' if dailydata['is_extra_task_reward_received'] else '未'
|
||||
|
||||
resin_discount_num_limit = dailydata['resin_discount_num_limit']
|
||||
used_resin_discount_num = resin_discount_num_limit - \
|
||||
dailydata['remain_resin_discount_num']
|
||||
|
||||
coin = f'{dailydata["current_home_coin"]}/{dailydata["max_home_coin"]}'
|
||||
if dailydata["current_home_coin"] < dailydata["max_home_coin"]:
|
||||
coin_rec_time = seconds2hours(int(dailydata["home_coin_recovery_time"]))
|
||||
coin_add_speed = math.ceil((dailydata["max_home_coin"] - dailydata["current_home_coin"]) / (
|
||||
int(dailydata["home_coin_recovery_time"]) / 60 / 60))
|
||||
coin += f'({coin_rec_time} 约{coin_add_speed}/h)'
|
||||
|
||||
expedition_data = "\n".join(expedition_info)
|
||||
send_mes = daily_im.format(tip, current_resin, max_resin, rec_time, finished_task_num, total_task_num,
|
||||
is_extra_got, used_resin_discount_num,
|
||||
resin_discount_num_limit, coin, current_expedition_num,
|
||||
finished_expedition_num, max_expedition_num, expedition_data)
|
||||
|
||||
temp_list.append(
|
||||
{"qid": row[2], "gid": row[3], "message": send_mes})
|
||||
return temp_list
|
||||
|
||||
async def mihoyo_coin(qid):
|
||||
uid = await select_db(qid, mode="uid")
|
||||
uid = uid[0]
|
||||
s_cookies = await get_stoken(uid)
|
||||
if s_cookies:
|
||||
get_coin = coin.mihoyobbs_coin(s_cookies)
|
||||
im = await get_coin.task_run()
|
||||
else:
|
||||
im = "你还没有绑定Stoken~"
|
||||
return im
|
||||
|
||||
async def get_event_pic():
|
||||
img_path = os.path.join(FILE2_PATH, "event.jpg")
|
||||
while True:
|
||||
if os.path.exists(img_path):
|
||||
f = open(img_path, 'rb')
|
||||
ls_f = b64encode(f.read()).decode()
|
||||
img_mes = 'base64://' + ls_f
|
||||
f.close()
|
||||
break
|
||||
else:
|
||||
await draw_event_pic()
|
||||
return img_mes
|
||||
|
||||
async def weapon_wiki(name, level=None):
|
||||
data = await get_weapon_info(name)
|
||||
if "errcode" in data:
|
||||
im = "武器不存在。"
|
||||
elif level:
|
||||
data2 = await get_weapon_info(name, level)
|
||||
if data["substat"] != "":
|
||||
sp = data["substat"] + ":" + '%.1f%%' % (data2["specialized"] * 100) \
|
||||
if data["substat"] != "元素精通" else data["substat"] + ":" + str(math.floor(data2["specialized"]))
|
||||
else:
|
||||
sp = ""
|
||||
im = (data["name"] + "\n等级:" + str(data2["level"]) + "(突破" + str(data2["ascension"]) + ")" +
|
||||
"\n攻击力:" + str(round(data2["attack"])) + "\n" + sp)
|
||||
else:
|
||||
name = data['name']
|
||||
_type = data['weapontype']
|
||||
star = data['rarity'] + "星"
|
||||
info = data['description']
|
||||
atk = str(data['baseatk'])
|
||||
sub_name = data['substat']
|
||||
if data['subvalue'] != "":
|
||||
sub_val = (data['subvalue'] +
|
||||
'%') if sub_name != '元素精通' else data['subvalue']
|
||||
sub = "\n" + "【" + sub_name + "】" + sub_val
|
||||
else:
|
||||
sub = ""
|
||||
|
||||
if data['effectname'] != "":
|
||||
raw_effect = data['effect']
|
||||
rw_ef = []
|
||||
for i in range(len(data['r1'])):
|
||||
now = ''
|
||||
for j in range(1, 6):
|
||||
now = now + data['r{}'.format(j)][i] + "/"
|
||||
now = now[:-1]
|
||||
rw_ef.append(now)
|
||||
raw_effect = raw_effect.format(*rw_ef)
|
||||
effect = "\n" + "【" + data['effectname'] + "】" + ":" + raw_effect
|
||||
else:
|
||||
effect = ""
|
||||
im = weapon_im.format(name, _type, star, info, atk,
|
||||
sub, effect)
|
||||
return im
|
||||
|
||||
|
||||
async def char_wiki(name, mode="char", level=None):
|
||||
data = await get_char_info(name, mode, level if mode == "char" else None)
|
||||
if mode == "char":
|
||||
if isinstance(data, list):
|
||||
im = ','.join(data)
|
||||
elif "errcode" in data:
|
||||
im = "不存在该角色或类型。"
|
||||
elif level:
|
||||
data2 = await get_char_info(name, mode)
|
||||
sp = data2["substat"] + ":" + '%.1f%%' % (data["specialized"] * 100) if data2["substat"] != "元素精通" else \
|
||||
data2["substat"] + ":" + str(math.floor(data["specialized"]))
|
||||
im = (data2["name"] + "\n等级:" + str(data["level"]) + "\n血量:" + str(math.floor(data["hp"])) +
|
||||
"\n攻击力:" + str(math.floor(data["attack"])) + "\n防御力:" + str(math.floor(data["defense"])) +
|
||||
"\n" + sp)
|
||||
else:
|
||||
name = data['title'] + ' — ' + data['name']
|
||||
star = data['rarity']
|
||||
_type = data["weapontype"]
|
||||
element = data['element']
|
||||
up_val = data['substat']
|
||||
bdday = data['birthday']
|
||||
polar = data['constellation']
|
||||
cv = data['cv']['chinese']
|
||||
info = data['description']
|
||||
im = char_info_im.format(
|
||||
name, star, _type, element, up_val, bdday, polar, cv, info)
|
||||
elif mode == "costs":
|
||||
if isinstance(data[1], list):
|
||||
im = ','.join(data[1])
|
||||
elif "errcode" in data[1]:
|
||||
im = "不存在该角色或类型。"
|
||||
else:
|
||||
im = "【天赋材料(一份)】\n{}\n【突破材料】\n{}"
|
||||
im1 = ""
|
||||
im2 = ""
|
||||
|
||||
talent_temp = {}
|
||||
talent_cost = data[1]
|
||||
for i in talent_cost.values():
|
||||
for j in i:
|
||||
if j["name"] not in talent_temp:
|
||||
talent_temp[j["name"]] = j["count"]
|
||||
else:
|
||||
talent_temp[j["name"]] = talent_temp[j["name"]] + j["count"]
|
||||
for k in talent_temp:
|
||||
im1 = im1 + k + ":" + str(talent_temp[k]) + "\n"
|
||||
|
||||
temp = {}
|
||||
cost = data[0]
|
||||
for i in range(1, 7):
|
||||
for j in cost["ascend{}".format(i)]:
|
||||
if j["name"] not in temp:
|
||||
temp[j["name"]] = j["count"]
|
||||
else:
|
||||
temp[j["name"]] = temp[j["name"]] + j["count"]
|
||||
|
||||
for k in temp:
|
||||
im2 = im2 + k + ":" + str(temp[k]) + "\n"
|
||||
|
||||
im = im.format(im1, im2)
|
||||
elif mode == "constellations":
|
||||
if "errcode" in data:
|
||||
im = "不存在该角色或命座数量。"
|
||||
else:
|
||||
im = "【" + data["c{}".format(level)]['name'] + "】" + ":" + \
|
||||
"\n" + data["c{}".format(level)]['effect'].replace("*", "")
|
||||
elif mode == "talents":
|
||||
if "errcode" in data:
|
||||
im = "不存在该角色。"
|
||||
else:
|
||||
if 6 >= int(level) > 0:
|
||||
if int(level) <= 3:
|
||||
if level == "1":
|
||||
data = data["combat1"]
|
||||
elif level == "2":
|
||||
data = data["combat2"]
|
||||
elif level == "3":
|
||||
data = data["combat3"]
|
||||
skill_name = data["name"]
|
||||
skill_info = data["info"]
|
||||
skill_detail = ""
|
||||
|
||||
"""
|
||||
for i in data["attributes"]["parameters"]:
|
||||
temp = ""
|
||||
for k in data["attributes"]["parameters"][i]:
|
||||
if str(k).count('.') == 1:
|
||||
temp += "%.2f%%" % (k * 100) + "/"
|
||||
else:
|
||||
temp = k
|
||||
break
|
||||
data["attributes"]["parameters"][i] = temp[:-1]
|
||||
|
||||
for i in data["attributes"]["labels"]:
|
||||
#i = i.replace("{","{{")
|
||||
i = re.sub(r':[a-zA-Z0-9]+}', "}", i)
|
||||
#i.replace(r':[a-zA-Z0-9]+}','}')
|
||||
skill_detail += i + "\n"
|
||||
|
||||
skill_detail = skill_detail.format(**data["attributes"]["parameters"])
|
||||
"""
|
||||
mes_list = []
|
||||
parameters = []
|
||||
add_switch = True
|
||||
for i in data["attributes"]["parameters"]:
|
||||
for index,j in enumerate(data["attributes"]["parameters"][i]):
|
||||
if add_switch:
|
||||
parameters.append({})
|
||||
if str(j).count('.') == 1 and j <= 20:
|
||||
parameters[index].update({i:"%.2f%%" % (j * 100)})
|
||||
elif str(j).count('.') == 1:
|
||||
parameters[index].update({i:"%.2f" % (j * 100)})
|
||||
else:
|
||||
parameters[index].update({i:j})
|
||||
add_switch = False
|
||||
|
||||
for k in data["attributes"]["labels"]:
|
||||
k = re.sub(r':[a-zA-Z0-9]+}', "}", k)
|
||||
skill_detail += k + "\n"
|
||||
|
||||
skill_detail = skill_detail[:-1]
|
||||
|
||||
for i in range(1,10):
|
||||
if i%2!=0:
|
||||
skill_info = skill_info.replace("**","「",1)
|
||||
else:
|
||||
skill_info = skill_info.replace("**","」",1)
|
||||
|
||||
mes_list.append({
|
||||
"type": "node",
|
||||
"data": {
|
||||
"name": "小仙",
|
||||
"uin": "3399214199",
|
||||
"content":"【" + skill_name + "】" + "\n" + skill_info
|
||||
}
|
||||
})
|
||||
|
||||
for index,i in enumerate(parameters):
|
||||
mes = skill_detail.format(**i)
|
||||
node_data = {
|
||||
"type": "node",
|
||||
"data": {
|
||||
"name": "小仙",
|
||||
"uin": "3399214199",
|
||||
"content":"lv." + str(index+1) + "\n" + mes
|
||||
}
|
||||
}
|
||||
mes_list.append(node_data)
|
||||
im = mes_list
|
||||
|
||||
else:
|
||||
if level == "4":
|
||||
data = data["passive1"]
|
||||
elif level == "5":
|
||||
data = data["passive2"]
|
||||
elif level == "6":
|
||||
data = data["passive3"]
|
||||
elif level == "7":
|
||||
data = data["passive4"]
|
||||
skill_name = data["name"]
|
||||
skill_info = data["info"]
|
||||
im = "【{}】\n{}".format(skill_name, skill_info)
|
||||
else:
|
||||
im = "不存在该天赋。"
|
||||
return im
|
BIN
mihoyo_libs/mihoyo_bbs/bg/default1.jpg
Normal file
After Width: | Height: | Size: 129 KiB |
BIN
mihoyo_libs/mihoyo_bbs/bg/default2.jpg
Normal file
After Width: | Height: | Size: 793 KiB |
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 26 KiB |
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 27 KiB |
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 27 KiB |
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 31 KiB |
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 28 KiB |
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 32 KiB |
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 28 KiB |
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 29 KiB |
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 28 KiB |
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 28 KiB |
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 28 KiB |
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 28 KiB |
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 29 KiB |
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 27 KiB |
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 28 KiB |
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 26 KiB |
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 28 KiB |
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 28 KiB |
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 31 KiB |
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 28 KiB |
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 28 KiB |
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 29 KiB |
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 28 KiB |
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 29 KiB |
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 31 KiB |
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 29 KiB |
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 31 KiB |
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 29 KiB |
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 27 KiB |
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 32 KiB |
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 26 KiB |
Before Width: | Height: | Size: 31 KiB After Width: | Height: | Size: 31 KiB |
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 24 KiB |
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 26 KiB |
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 25 KiB |
Before Width: | Height: | Size: 614 KiB After Width: | Height: | Size: 614 KiB |
Before Width: | Height: | Size: 508 KiB After Width: | Height: | Size: 508 KiB |
Before Width: | Height: | Size: 689 KiB After Width: | Height: | Size: 689 KiB |
Before Width: | Height: | Size: 530 KiB After Width: | Height: | Size: 530 KiB |
Before Width: | Height: | Size: 637 KiB After Width: | Height: | Size: 637 KiB |
Before Width: | Height: | Size: 590 KiB After Width: | Height: | Size: 590 KiB |
Before Width: | Height: | Size: 602 KiB After Width: | Height: | Size: 602 KiB |
Before Width: | Height: | Size: 418 KiB After Width: | Height: | Size: 418 KiB |
Before Width: | Height: | Size: 611 KiB After Width: | Height: | Size: 611 KiB |
Before Width: | Height: | Size: 595 KiB After Width: | Height: | Size: 595 KiB |
Before Width: | Height: | Size: 507 KiB After Width: | Height: | Size: 507 KiB |
Before Width: | Height: | Size: 516 KiB After Width: | Height: | Size: 516 KiB |
Before Width: | Height: | Size: 540 KiB After Width: | Height: | Size: 540 KiB |
Before Width: | Height: | Size: 712 KiB After Width: | Height: | Size: 712 KiB |
Before Width: | Height: | Size: 795 KiB After Width: | Height: | Size: 795 KiB |
Before Width: | Height: | Size: 549 KiB After Width: | Height: | Size: 549 KiB |
Before Width: | Height: | Size: 423 KiB After Width: | Height: | Size: 423 KiB |
Before Width: | Height: | Size: 489 KiB After Width: | Height: | Size: 489 KiB |
Before Width: | Height: | Size: 530 KiB After Width: | Height: | Size: 530 KiB |
Before Width: | Height: | Size: 581 KiB After Width: | Height: | Size: 581 KiB |
Before Width: | Height: | Size: 518 KiB After Width: | Height: | Size: 518 KiB |
Before Width: | Height: | Size: 561 KiB After Width: | Height: | Size: 561 KiB |
Before Width: | Height: | Size: 545 KiB After Width: | Height: | Size: 545 KiB |
Before Width: | Height: | Size: 461 KiB After Width: | Height: | Size: 461 KiB |
Before Width: | Height: | Size: 475 KiB After Width: | Height: | Size: 475 KiB |
Before Width: | Height: | Size: 589 KiB After Width: | Height: | Size: 589 KiB |
Before Width: | Height: | Size: 916 KiB After Width: | Height: | Size: 916 KiB |
Before Width: | Height: | Size: 788 KiB After Width: | Height: | Size: 788 KiB |
Before Width: | Height: | Size: 540 KiB After Width: | Height: | Size: 540 KiB |
Before Width: | Height: | Size: 465 KiB After Width: | Height: | Size: 465 KiB |
Before Width: | Height: | Size: 788 KiB After Width: | Height: | Size: 788 KiB |
Before Width: | Height: | Size: 454 KiB After Width: | Height: | Size: 454 KiB |
Before Width: | Height: | Size: 656 KiB After Width: | Height: | Size: 656 KiB |
Before Width: | Height: | Size: 651 KiB After Width: | Height: | Size: 651 KiB |
Before Width: | Height: | Size: 70 KiB After Width: | Height: | Size: 70 KiB |
Before Width: | Height: | Size: 74 KiB After Width: | Height: | Size: 74 KiB |
Before Width: | Height: | Size: 80 KiB After Width: | Height: | Size: 80 KiB |
Before Width: | Height: | Size: 104 KiB After Width: | Height: | Size: 104 KiB |
Before Width: | Height: | Size: 81 KiB After Width: | Height: | Size: 81 KiB |
Before Width: | Height: | Size: 95 KiB After Width: | Height: | Size: 95 KiB |
Before Width: | Height: | Size: 84 KiB After Width: | Height: | Size: 84 KiB |
Before Width: | Height: | Size: 91 KiB After Width: | Height: | Size: 91 KiB |
Before Width: | Height: | Size: 76 KiB After Width: | Height: | Size: 76 KiB |
Before Width: | Height: | Size: 70 KiB After Width: | Height: | Size: 70 KiB |