Skip to content
This repository has been archived by the owner on May 24, 2023. It is now read-only.

Commit

Permalink
增加原神便笺插件 *测试
Browse files Browse the repository at this point in the history
  • Loading branch information
yuyumoko committed Oct 15, 2021
1 parent f56f28a commit eac7190
Show file tree
Hide file tree
Showing 15 changed files with 350 additions and 41 deletions.
50 changes: 34 additions & 16 deletions egenshin/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
> pip install pyyaml -i https://pypi.tuna.tsinghua.edu.cn/simple
>
> pip install sqlitedict -i https://pypi.tuna.tsinghua.edu.cn/simple
>
> pip install xlsxwriter -i https://pypi.tuna.tsinghua.edu.cn/simple
---

Expand Down Expand Up @@ -132,23 +134,19 @@ ysa# | 和ys#一样 但是显示全部角色 | ysa#
原神成就查漏功能 (用ys#绑定 切换号直接查询另一个就好)<br>
不获取游戏内任何数据,仅仅只是记录玩家完成的成就<br>
方便查看还有什么隐藏成就尚未完成<br>
只有未完成的成就数量小于100时才有界面<br>
仅限天地万象!!<br>
<br>
如果要删除现有的成就请使用 重置原神成就<br>
重置仅仅是ys#绑定的成就<br>
如果要查看带有攻略请使用 a原神成就<br>
<br>
使用方法:<br>
(方法1): 可以直接使用命令后跟n张游戏内的截图来进行更新,例如<br>
原神成就[完成的成就截图1][完成的成就截图2][完成的成就截图3]
(方法2): 可以上传图床然后使用命令跟n个上传的图片地址更新,例如<br>
原神成就<br>
https://imgtu.com/i/h5Rq6x<br>
https://imgtu.com/i/h5RHpR<br>
https://imgtu.com/i/h5Rb11<br>
支持的图床有<br>
https://imgtu.com/<br>
https://ibb.co/<br>
<br>
可以直接使用命令后跟n张游戏内的截图来进行更新,例如<br>
原神成就[完成的成就截图1][完成的成就截图2][完成的成就截图3]<br>
<br>
*第一次需要全部截完 不用一个个发,可以一次性发完<br>
<br>
命令 | 说明 | 例
------------- | ------------- | -------------
Expand All @@ -163,4 +161,24 @@ https://ibb.co/<br>
![image](./doc/achievements.jpeg)
</details>
## 原神实时便笺
*目前测试中 <br>
这个功能需谨慎使用, 因为涉及到获取cookie, 不想使用可以直接删除`daily_note`文件夹<br>

命令 | 说明 | 例
------------- | ------------- | -------------
yss | - | -
yss# | - | -
原神状态 | - | -
原神实时 | - | -
原神便笺 | - | -

<details>
<summary>返回示例</summary>

![image](./doc/daily_note.jpeg)

</details>
Binary file added egenshin/assets/daily_note/bg.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added egenshin/assets/daily_note/expeditions_item.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added egenshin/assets/daily_note/中午.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added egenshin/assets/daily_note/夜晚.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added egenshin/assets/daily_note/早晨.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added egenshin/assets/daily_note/黄昏.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
36 changes: 36 additions & 0 deletions egenshin/daily_note/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
from hoshino import Service, priv, MessageSegment
from ..util import support_private
from .main import Daily_Note, Error_Message, Account_Error
from .info_card import draw_info_card

sv_help = '''
'''.strip()
sv = Service(
name='原神实时便笺', # 功能名
use_priv=priv.NORMAL, # 使用权限
manage_priv=priv.ADMIN, # 管理权限
visible=True, # 可见性
enable_on_default=True, # 默认启用
bundle='娱乐', #分组归类
help_=sv_help # 帮助说明
)


@support_private(sv)
@sv.on_prefix(('yss', 'yss#', '原神状态', '原神实时', '原神便笺'))
async def main(bot, ev):
text = ev.message.extract_plain_text().strip()
cookie_raw = ''
try:
if text.startswith('绑定'):
if ev.detail_type == 'group':
raise Error_Message('请撤回, 不支持在群内绑定, 请私聊机器人')
cookie_raw = text[2:]
info = await Daily_Note(ev.user_id, cookie_raw).get_info()
im = await draw_info_card(info)
await bot.send(ev, MessageSegment.image(im), at_sender=True)

except Error_Message as e:
await bot.send(ev, repr(e), at_sender=True)
except Account_Error as e:
await bot.send(ev, 'cookie信息错误, 请重新检查是否正确', at_sender=True)
27 changes: 27 additions & 0 deletions egenshin/daily_note/error.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
class Error_Message(Exception):
def __init__(self, message=''):
self.message = message

def __repr__(self):
return self.message

class Cookie_Error(Error_Message):
def __repr__(self):
t = '''
1. 打开米游社(https://bbs.mihoyo.com/ys/)
2. 登录游戏账号
3. F12打开控制台
4. 输入以下代码运行
javascript:(()=>{_=(n)=>document.cookie.match(`[;\s+]?${n}=([^;]*)`)?.pop();alert(_("account_id")+","+_("cookie_token"))})();
5. 复制提示的内容, 私聊发给机器人
私聊格式为
原神便笺绑定xxxxxxxxxxxxxx
其中xxxxxxxxxxxxxx是复制的内容
'''
return t.rstrip()


class Login_Error(Error_Message):
pass
108 changes: 108 additions & 0 deletions egenshin/daily_note/info_card.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
import datetime
from pathlib import Path

from ..imghandler import *
from ..util import cache, get_font, get_path, pil2b64
from .main import Daily_Note_Info

default_text_color = '#78818b'
success_text_color = '#669999'

assets_dir = Path(get_path('assets')) / 'daily_note'
box_bg = Image.open(assets_dir / "bg.png")
expedition_box = Image.open(assets_dir / "expeditions_item.png")
expedition_box_ok = Image.open(assets_dir / "expeditions_item_ok.png")

def in_time(time_str1, time_str2):
now = datetime.datetime.now()
day = str(now.date())
t1 = datetime.datetime.strptime(day + time_str1, '%Y-%m-%d%H:%M')
t2 = datetime.datetime.strptime(day + time_str2, '%Y-%m-%d%H:%M')
if t2 < t1:
return True
return now > t1 and now < t2


async def get_time_icon():
morning = ('6:00', '11:00', '早晨.png')
noon = ('11:00', '17:00', '中午.png')
dusk = ('17:00', '19:00', '黄昏.png')
night = ('19:00', '6:00', '夜晚.png')
for t1, t2, png in [morning, noon, dusk, night]:
if in_time(t1, t2):
return Image.open(assets_dir / png)
raise Exception('unknown time')


async def gen_expedition_items(expeditions):
for exp in expeditions:
remained_time = int(exp['remained_time'])
avatar = await get_pic(exp['avatar_side_icon'], (49, 60))

if exp['status'] == 'Finished':
bg = expedition_box_ok.copy()
s = '已完成!'
ok = True
else:
bg = expedition_box.copy()
mm, ss = divmod(remained_time, 60)
hh, mm = divmod(mm, 60)
s = "剩余%d小时%02d分%02d秒" % (hh, mm, ss)
ok = False

draw_text_by_line(bg, (0, 49.88), s, get_font(49), ok and success_text_color or default_text_color, 881, True)
yield (avatar, bg.resize((273, 76)))


async def draw_info_card(info: Daily_Note_Info):
now = datetime.datetime.now()

bg = Image.new('RGB', (box_bg.width, box_bg.height), '#f1ece6')
easy_paste(bg, box_bg.copy())

now_str = now.strftime(" %m月%d日\n%H:%M:%S")
draw_text_by_line(bg, (219.38, 59.79), now_str, get_font(21), default_text_color, 881)
easy_paste(bg, await get_time_icon(), (84, 30))

# 树脂完全回复时间
resin_recovery_time = now + datetime.timedelta(seconds=int(info.resin_recovery_time))
resin_recovery_time_day = resin_recovery_time.day > now.day and '明天' or '今天'
resin_recovery_str = f'将于{resin_recovery_time_day} {resin_recovery_time.strftime("%H:%M:%S")} 完全回复'
draw_text_by_line(bg, (173.09, 150.2), resin_recovery_str, get_font(16), default_text_color, 881)

# 树脂
resin_str = f'{info.current_resin}/{info.max_resin}'
draw_text_by_line(bg, (233.55, 196.93), resin_str, get_font(36), default_text_color, 881)

# 每日
ok = False
task_str = f'{info.finished_task_num}/{info.total_task_num}'
if info.finished_task_num == info.total_task_num:
task_str = '完成'
ok = True
draw_text_by_line(bg, (253, 327), task_str, get_font(36), ok and success_text_color or default_text_color, 881)

# 周本
ok = False
resin_discount_str = f'{info.remain_resin_discount_num}/{info.resin_discount_num_limit}'
if info.remain_resin_discount_num == 0:
resin_discount_str = '完成'
ok = True
draw_text_by_line(bg, (253, 452), resin_discount_str, get_font(36), ok and success_text_color or default_text_color, 881)

# 探索
first_expeditions_time = int(min([x['remained_time'] for x in info.expeditions]))
first_expeditions_time = now + datetime.timedelta(seconds=first_expeditions_time)
first_expeditions_time_day = first_expeditions_time.day > now.day and '明天' or '今天'
first_expeditions_str = f'最快{first_expeditions_time_day} {first_expeditions_time.strftime("%H:%M:%S")} 派遣完成'
draw_text_by_line(bg, (600, 74), first_expeditions_str, get_font(18), default_text_color, 881)

bg = bg.convert("RGBA")
exp_index = 114
async for avatar, exp_bg in gen_expedition_items(info.expeditions):
bg = easy_alpha_composite(bg, avatar, (538, exp_index))
bg = easy_alpha_composite(bg, exp_bg, (587, exp_index))

exp_index += 72

return pil2b64(bg)
62 changes: 62 additions & 0 deletions egenshin/daily_note/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
from typing import List
from dataclasses import dataclass
from http.cookies import SimpleCookie
from ..player_info import query
from .error import *

Account_Error = query.Account_Error


@dataclass
class Daily_Note_expeditions:
avatar_side_icon: str # 头像icon
status: str # 'Finished' or 'Ongoing' 状态
remained_time: str # 剩余时间


@dataclass
class Daily_Note_Info:
current_resin: int # 当前树脂
max_resin: int # 最大树脂
resin_recovery_time: str # 树脂回复时间
finished_task_num: int # 完成委托个数
total_task_num: int # 全部委托个数
is_extra_task_reward_received: bool
remain_resin_discount_num: int # 周本树脂减半剩余次数
resin_discount_num_limit: int # 周本树脂减半次数
current_expedition_num: int # 当前派遣数量
max_expedition_num: int # 最大派遣数量
expeditions: List[Daily_Note_expeditions] # 派遣列表


class Daily_Note():
def __init__(self, qid, cookie_raw=None):
self.qid = qid

self.cookie = query.get_cookie_by_qid(qid)

if not any([cookie_raw, self.cookie]):
raise Cookie_Error()

self.uid = query.get_uid_by_qid(qid)
if not self.uid:
raise Error_Message('请先使用ys#绑定')

self.cookie = SimpleCookie(self.cookie)
if cookie_raw:
self.cookie.load(
dict(zip(['account_id', 'cookie_token'],
cookie_raw.split(','))))

self.cookie_raw = self.cookie.output(header='', sep=';').strip()

async def get_info(self) -> Daily_Note_Info:
json_data = await query.daily_note(self.uid, self.cookie_raw)

if json_data.retcode == 10102:
raise Login_Error('请先在米游社角色信息那打开实时便笺功能')
if json_data.retcode != 0:
raise Login_Error(json_data.message)

query.save_cookie(self.qid, self.cookie_raw)
return Daily_Note_Info(**json_data.data)
Binary file added egenshin/doc/daily_note.jpeg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading

0 comments on commit eac7190

Please sign in to comment.