63 Commits

Author SHA1 Message Date
f90bc5d658 Merge pull request #139 from chenchenriver/main
修复hoshino版本中成功绑定ck后因无法使用私聊绑定uid导致的描述问题
2022-03-14 16:54:32 +08:00
8b7aff98cd 修复hoshino版本中成功绑定ck后因无法使用私聊绑定uid导致的描述问题
278行添加描述需要在群聊中使用该命令
2022-03-14 16:16:45 +08:00
7a508c505b 根据PaimonBot的角色别名添加更多别名
https://github.com/XiaoMiku01/PaimonBot/blob/main/src/data/character/nickname.json
2022-03-11 18:03:24 +08:00
b919491339 Merge pull request #129 from Zoe-Wh1t3zZ/patch-1
fix
2022-03-11 01:22:02 +08:00
20e14ec7b3 fix 2022-03-11 01:20:26 +08:00
3be56e5e2c fix 2022-03-11 00:47:55 +08:00
db5d4d46f6 准备:角色别名json的加入 2022-03-10 23:52:20 +08:00
e439cd9f58 新增:开始获取米游币 & 添加Stokne;修复:活动列表 2022-03-10 23:50:35 +08:00
7e63649a55 米游币自动获取前提:Stoken获取指南fix 2022-03-09 09:52:03 +08:00
1367222266 Merge pull request #127 from 3273576540/main
相对改绝对
2022-03-09 09:36:38 +08:00
fd0a04e052 Update get_mihoyo_bbs_coin.py 2022-03-09 09:05:24 +08:00
9d1716b82d 米游币自动获取前提:Stoken获取指南 2022-03-09 00:22:10 +08:00
033eed619d fix 2022-03-09 00:18:47 +08:00
d25b05e802 Merge branch 'main' of github.com:KimigaiiWuyi/GenshinUID 2022-03-09 00:03:06 +08:00
afb9a61be2 准备:当前状态图片版 & 自动米游币获取 2022-03-09 00:00:56 +08:00
e3b8e9b8ca 修改导包问题 2022-03-07 11:54:02 +08:00
287e861d06 fix 2022-03-06 23:50:49 +08:00
41bcb89a38 修改结构 2022-03-06 23:34:05 +08:00
4edf1ccb49 fix:on_rex 2022-03-06 15:41:13 +08:00
4bb0faa49e 新增:xxx用什么|能用啥|怎么养&xxx能给谁|给谁用|要给谁|谁能用 2022-03-06 00:04:24 +08:00
4664fa805d 同步代码 2022-03-05 22:03:50 +08:00
4c9f0d9f3f 同步:新的贴图 2022-03-05 21:54:34 +08:00
d614b0bf8b 同步:接口 2022-03-05 21:53:27 +08:00
c365d7bce9 优化:统一深渊生成图 & 统一返回 (添加大量冗余代码 2022-03-05 21:50:14 +08:00
919c55adb1 ReadMe 2022-02-22 23:57:08 +08:00
2c21f035d4 优化:天赋wiki的显示(合并转发) 2022-02-22 23:49:25 +08:00
d10d9dd982 Merge branch 'main' of github.com:KimigaiiWuyi/GenshinUID 2022-02-22 23:46:49 +08:00
21607fe2a7 更新接口 2022-02-22 23:46:27 +08:00
49fdecfa25 修复:深渊查询问题 2022-02-16 16:15:46 +08:00
5d11ec7998 修复:活动列表时间 fix #116 2022-02-14 23:52:20 +08:00
47a9595785 格式化提交 2022-02-14 19:18:20 +08:00
5ca303c2f9 格式化提交(事件响应部分) 2022-02-12 19:19:48 +08:00
42bc1d68b9 修复:活动列表时间问题 2022-02-12 18:41:10 +08:00
fa143d4bf5 Fix 2022-02-12 03:32:07 +08:00
a4d948563e 修复:活动列表时间的问题 2022-02-12 00:32:36 +08:00
25bbede003 Update README.md 2022-02-09 18:20:06 +08:00
4d687770ef 修复一个bug 2022-02-09 18:18:17 +08:00
8cf1dd6b37 requirements 2022-02-06 23:27:33 +08:00
ec39704b72 优化:报错 2022-02-04 19:25:04 +08:00
e99928687c Readme 2022-02-03 20:07:00 +08:00
c7b2b14703 Readme 2022-02-03 20:05:48 +08:00
a4f8b3f12b 优化:武器的数值显示 2022-02-03 19:33:35 +08:00
a79c139077 优化:定时任务log 2022-02-03 00:07:16 +08:00
365f5eb7e3 优化:校验全部Cookies现在会私聊已失效CK的QQ账号提醒ck过期 2022-02-02 11:01:14 +08:00
0b3595f9c3 README! 2022-02-01 19:05:54 +08:00
899f0e7ce9 readme 2022-02-01 19:02:03 +08:00
b7100af0f0 优化:八角色UI信息内容 2022-02-01 18:40:12 +08:00
5ca4013639 优化:自动签到报告&新增:开启简洁签到报告 2022-02-01 00:15:09 +08:00
83b548c2f2 修复:同步新的WikiAPI接口;优化:错误提示. 2022-01-26 23:59:29 +08:00
5f3d37852a 优化:每日签到&树脂提醒 2022-01-24 00:41:12 +08:00
76b010a1bb 同步语音重试:PR #81 2022-01-23 01:49:42 +08:00
02ee0427b8 优化:添加Cookies之后的缓存问题 2022-01-23 01:29:26 +08:00
41efadd0a3 新增:食物/圣遗物命令,支持模糊查询;修复&优化:签到/添加Ck指令;移除:数据库优化命令 2022-01-23 01:12:05 +08:00
b0392fc4c7 Create LICENSE 2022-01-11 19:39:01 +08:00
8a81f51679 添加:报错信息 2022-01-08 20:58:05 +08:00
e8f4b23741 修复:补全缺失的Texture2D 2022-01-06 00:41:08 +08:00
f06a3baff9 新增:语音命令;修复:渊下宫带来的查询错误问题;新增:当前状态命令查询洞天宝钱数量 2022-01-06 00:33:49 +08:00
eadd9656b3 修复:角色命令可能出错的问题 2022-01-01 15:30:03 +08:00
12f7f2f77d 新增:开启&关闭自动签到/推送服务,可由超级管理员操作 2021-12-30 23:08:12 +08:00
089e69799f 新增:命座查询的模糊匹配;优化:代码结构 2021-12-30 22:26:08 +08:00
a95b27c181 新增:武器已支持查询某个固定等级属性 & 支持模糊查询;修复:角色查等级时元素精通数值不正确显示。 2021-12-30 00:41:24 +08:00
3d8c4b8ba2 修复:角色命令现已支持模糊查询(修复之前直接输出Json) 2021-12-30 00:01:34 +08:00
dc93f9e962 修复&优化:数据获取方式 & 推送树脂可能造成的Bug;新增:原魔、天赋指令。 2021-12-29 23:57:02 +08:00
398 changed files with 5388 additions and 3097 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/.idea/

674
LICENSE Normal file
View 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
View File

@ -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> &nbsp; · &nbsp;
<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> &nbsp; · &nbsp;
<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)
![1](https://raw.githubusercontent.com/KimigaiiWuyi/GenshinUID/main/readme/1.PNG)
![6](https://raw.githubusercontent.com/KimigaiiWuyi/GenshinUID/main/readme/6.PNG)
- [安装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、进入机器人在的群聊即可正常使用本插件。
## 更新记录
**作者已经转用NoneBot2Hoshino的更新可能未经测试有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 |
### 深渊查询:
![2](https://raw.githubusercontent.com/KimigaiiWuyi/GenshinUID/main/readme/2.png)
### 当前状态:
![3](https://raw.githubusercontent.com/KimigaiiWuyi/GenshinUID/main/readme/3.png)
### 签到:
![3](https://raw.githubusercontent.com/KimigaiiWuyi/GenshinUID/main/readme/4.PNG)
### 查询词云:
![3](https://raw.githubusercontent.com/KimigaiiWuyi/GenshinUID/main/readme/5.PNG)
## 相关仓库
## 丨感谢
- [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)

View File

@ -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
View 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="您绑定的Cookiesuid{})已失效,以下功能将会受到影响:\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
View File

@ -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&region=" + 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&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'})
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

1339
getImg.py

File diff suppressed because it is too large Load Diff

Binary file not shown.

897
mihoyo_libs/get_data.py Normal file
View 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

File diff suppressed because it is too large Load Diff

View 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))

View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 129 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 793 KiB

View File

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 26 KiB

View File

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 27 KiB

View File

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 27 KiB

View File

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 31 KiB

View File

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 28 KiB

View File

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 32 KiB

View File

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 28 KiB

View File

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 29 KiB

View File

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 28 KiB

View File

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 28 KiB

View File

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 28 KiB

View File

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 28 KiB

View File

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 29 KiB

View File

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 27 KiB

View File

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 28 KiB

View File

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 30 KiB

View File

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 30 KiB

View File

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 26 KiB

View File

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 30 KiB

View File

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 28 KiB

View File

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 28 KiB

View File

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 31 KiB

View File

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 28 KiB

View File

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 28 KiB

View File

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 29 KiB

View File

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 28 KiB

View File

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 29 KiB

View File

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 31 KiB

View File

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 29 KiB

View File

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 31 KiB

View File

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 30 KiB

View File

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 30 KiB

View File

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 29 KiB

View File

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 27 KiB

View File

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 32 KiB

View File

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 30 KiB

View File

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 30 KiB

View File

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 26 KiB

View File

Before

Width:  |  Height:  |  Size: 31 KiB

After

Width:  |  Height:  |  Size: 31 KiB

View File

Before

Width:  |  Height:  |  Size: 24 KiB

After

Width:  |  Height:  |  Size: 24 KiB

View File

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 26 KiB

View File

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 25 KiB

View File

Before

Width:  |  Height:  |  Size: 614 KiB

After

Width:  |  Height:  |  Size: 614 KiB

View File

Before

Width:  |  Height:  |  Size: 508 KiB

After

Width:  |  Height:  |  Size: 508 KiB

View File

Before

Width:  |  Height:  |  Size: 689 KiB

After

Width:  |  Height:  |  Size: 689 KiB

View File

Before

Width:  |  Height:  |  Size: 530 KiB

After

Width:  |  Height:  |  Size: 530 KiB

View File

Before

Width:  |  Height:  |  Size: 637 KiB

After

Width:  |  Height:  |  Size: 637 KiB

View File

Before

Width:  |  Height:  |  Size: 590 KiB

After

Width:  |  Height:  |  Size: 590 KiB

View File

Before

Width:  |  Height:  |  Size: 602 KiB

After

Width:  |  Height:  |  Size: 602 KiB

View File

Before

Width:  |  Height:  |  Size: 418 KiB

After

Width:  |  Height:  |  Size: 418 KiB

View File

Before

Width:  |  Height:  |  Size: 611 KiB

After

Width:  |  Height:  |  Size: 611 KiB

View File

Before

Width:  |  Height:  |  Size: 595 KiB

After

Width:  |  Height:  |  Size: 595 KiB

View File

Before

Width:  |  Height:  |  Size: 507 KiB

After

Width:  |  Height:  |  Size: 507 KiB

View File

Before

Width:  |  Height:  |  Size: 516 KiB

After

Width:  |  Height:  |  Size: 516 KiB

View File

Before

Width:  |  Height:  |  Size: 540 KiB

After

Width:  |  Height:  |  Size: 540 KiB

View File

Before

Width:  |  Height:  |  Size: 712 KiB

After

Width:  |  Height:  |  Size: 712 KiB

View File

Before

Width:  |  Height:  |  Size: 795 KiB

After

Width:  |  Height:  |  Size: 795 KiB

View File

Before

Width:  |  Height:  |  Size: 549 KiB

After

Width:  |  Height:  |  Size: 549 KiB

View File

Before

Width:  |  Height:  |  Size: 423 KiB

After

Width:  |  Height:  |  Size: 423 KiB

View File

Before

Width:  |  Height:  |  Size: 489 KiB

After

Width:  |  Height:  |  Size: 489 KiB

View File

Before

Width:  |  Height:  |  Size: 530 KiB

After

Width:  |  Height:  |  Size: 530 KiB

View File

Before

Width:  |  Height:  |  Size: 581 KiB

After

Width:  |  Height:  |  Size: 581 KiB

View File

Before

Width:  |  Height:  |  Size: 518 KiB

After

Width:  |  Height:  |  Size: 518 KiB

View File

Before

Width:  |  Height:  |  Size: 561 KiB

After

Width:  |  Height:  |  Size: 561 KiB

View File

Before

Width:  |  Height:  |  Size: 545 KiB

After

Width:  |  Height:  |  Size: 545 KiB

View File

Before

Width:  |  Height:  |  Size: 461 KiB

After

Width:  |  Height:  |  Size: 461 KiB

View File

Before

Width:  |  Height:  |  Size: 475 KiB

After

Width:  |  Height:  |  Size: 475 KiB

View File

Before

Width:  |  Height:  |  Size: 589 KiB

After

Width:  |  Height:  |  Size: 589 KiB

View File

Before

Width:  |  Height:  |  Size: 916 KiB

After

Width:  |  Height:  |  Size: 916 KiB

View File

Before

Width:  |  Height:  |  Size: 788 KiB

After

Width:  |  Height:  |  Size: 788 KiB

View File

Before

Width:  |  Height:  |  Size: 540 KiB

After

Width:  |  Height:  |  Size: 540 KiB

View File

Before

Width:  |  Height:  |  Size: 465 KiB

After

Width:  |  Height:  |  Size: 465 KiB

View File

Before

Width:  |  Height:  |  Size: 788 KiB

After

Width:  |  Height:  |  Size: 788 KiB

View File

Before

Width:  |  Height:  |  Size: 454 KiB

After

Width:  |  Height:  |  Size: 454 KiB

View File

Before

Width:  |  Height:  |  Size: 656 KiB

After

Width:  |  Height:  |  Size: 656 KiB

View File

Before

Width:  |  Height:  |  Size: 651 KiB

After

Width:  |  Height:  |  Size: 651 KiB

View File

Before

Width:  |  Height:  |  Size: 70 KiB

After

Width:  |  Height:  |  Size: 70 KiB

View File

Before

Width:  |  Height:  |  Size: 74 KiB

After

Width:  |  Height:  |  Size: 74 KiB

View File

Before

Width:  |  Height:  |  Size: 80 KiB

After

Width:  |  Height:  |  Size: 80 KiB

View File

Before

Width:  |  Height:  |  Size: 104 KiB

After

Width:  |  Height:  |  Size: 104 KiB

View File

Before

Width:  |  Height:  |  Size: 81 KiB

After

Width:  |  Height:  |  Size: 81 KiB

View File

Before

Width:  |  Height:  |  Size: 95 KiB

After

Width:  |  Height:  |  Size: 95 KiB

View File

Before

Width:  |  Height:  |  Size: 84 KiB

After

Width:  |  Height:  |  Size: 84 KiB

View File

Before

Width:  |  Height:  |  Size: 91 KiB

After

Width:  |  Height:  |  Size: 91 KiB

View File

Before

Width:  |  Height:  |  Size: 76 KiB

After

Width:  |  Height:  |  Size: 76 KiB

View File

Before

Width:  |  Height:  |  Size: 70 KiB

After

Width:  |  Height:  |  Size: 70 KiB

Some files were not shown because too many files have changed in this diff Show More