202 lines
7.0 KiB
Python
202 lines
7.0 KiB
Python
"""工作。お仕事"""
|
|
import logging
|
|
from typing import Literal
|
|
from datetime import timedelta
|
|
|
|
from .. import R
|
|
from ..common import conf
|
|
from ..actions.loading import wait_loading_end
|
|
from ..actions.scenes import at_home, goto_home
|
|
from kotonebot import task, device, image, action, ocr, contains, cropped, rect_expand, color, sleep, regex
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
@action('领取工作奖励')
|
|
def handle_claim_assignment():
|
|
"""
|
|
领取工作奖励
|
|
|
|
前置条件:点击了工作按钮,已进入领取页面 \n
|
|
结束状态:分配工作页面
|
|
"""
|
|
# 领取奖励 [screenshots/assignment/acquire.png]
|
|
if image.find(R.Common.ButtonCompletion):
|
|
device.click()
|
|
return True
|
|
return False
|
|
|
|
@action('重新分配工作')
|
|
def assign(type: Literal['mini', 'online']) -> bool:
|
|
"""
|
|
分配工作
|
|
|
|
前置条件:分配工作页面 \n
|
|
结束状态:分配工作页面
|
|
|
|
:param type: 工作类型。mini=ミニライブ 或 online=ライブ配信。
|
|
"""
|
|
# [kotonebot/tasks/assignment.py]
|
|
target_duration = 12
|
|
image.expect_wait(R.Daily.IconTitleAssign, timeout=10)
|
|
if type == 'mini':
|
|
target_duration = conf().assignment.mini_live_duration
|
|
if image.find(R.Daily.IconAssignMiniLive):
|
|
device.click()
|
|
else:
|
|
logger.warning('MiniLive already assigned. Skipping...')
|
|
return False
|
|
elif type == 'online':
|
|
target_duration = conf().assignment.online_live_duration
|
|
if image.find(R.Daily.IconAssignOnlineLive):
|
|
device.click()
|
|
else:
|
|
logger.warning('OnlineLive already assigned. Skipping...')
|
|
return False
|
|
else:
|
|
raise ValueError(f'Invalid type: {type}')
|
|
# MiniLive/OnlineLive 页面 [screenshots/assignment/assign_mini_live.png]
|
|
image.expect_wait(R.Common.ButtonSelect, timeout=5)
|
|
logger.info('Now at assignment idol selection scene.')
|
|
# 选择好调偶像
|
|
selected = False
|
|
max_attempts = 4
|
|
attempts = 0
|
|
while not selected:
|
|
# 寻找所有好调图标
|
|
results = image.find_all(R.Daily.IconAssignKouchou, threshold=0.8)
|
|
logger.debug(f'Found {len(results)} kouchou icons.')
|
|
if not results:
|
|
logger.warning('No kouchou icons found. Trying again...')
|
|
continue
|
|
results.sort(key=lambda r: r.position[1])
|
|
results.pop(0) # 第一个是说明文字里的图标
|
|
# 尝试点击所有目标
|
|
for target in results:
|
|
logger.debug(f'Clicking idol #{target}...')
|
|
with cropped(device, y2=0.3):
|
|
img1 = device.screenshot()
|
|
# 选择偶像并判断是否选择成功
|
|
device.click(target)
|
|
sleep(1)
|
|
img2 = device.screenshot()
|
|
if image.raw().similar(img1, img2, 0.97):
|
|
logger.info(f'Idol #{target} already assigned. Trying next.')
|
|
continue
|
|
selected = True
|
|
break
|
|
if not selected:
|
|
attempts += 1
|
|
if attempts >= max_attempts:
|
|
logger.warning('Failed to select kouchou idol. Keep using the default idol.')
|
|
break
|
|
# 说明可能在第二页
|
|
device.swipe_scaled(0.6, 0.7, 0.2, 0.7)
|
|
sleep(0.5)
|
|
else:
|
|
break
|
|
# 点击选择
|
|
sleep(0.5)
|
|
device.click(image.expect(R.Common.ButtonSelect))
|
|
# 等待页面加载
|
|
confirm = image.expect_wait(R.Common.ButtonConfirmNoIcon)
|
|
# 选择时间 [screenshots/assignment/assign_mini_live2.png]
|
|
if ocr.find(contains(f'{target_duration}時間')):
|
|
logger.info(f'{target_duration}時間 selected.')
|
|
device.click()
|
|
else:
|
|
logger.warning(f'{target_duration}時間 not found. Using default duration.')
|
|
sleep(0.5)
|
|
while not at_assignment():
|
|
# 点击 决定する
|
|
if image.find(R.Common.ButtonConfirmNoIcon):
|
|
device.click()
|
|
elif image.find(R.Common.ButtonStart):
|
|
# 点击 開始する [screenshots/assignment/assign_mini_live3.png]
|
|
device.click()
|
|
return True
|
|
|
|
@action('获取剩余时间')
|
|
def get_remaining_time() -> timedelta | None:
|
|
"""
|
|
获取剩余时间
|
|
|
|
前置条件:首页 \n
|
|
结束状态:-
|
|
"""
|
|
texts = ocr.ocr(rect=R.Daily.BoxHomeAssignment)
|
|
if not texts.where(contains('お仕事')):
|
|
logger.warning('お仕事 area not found.')
|
|
return None
|
|
time = texts.where(regex(r'\d+:\d+:\d+')).first()
|
|
if not time:
|
|
logger.warning('お仕事 remaining time not found.')
|
|
return None
|
|
logger.info(f'お仕事 remaining time: {time}')
|
|
return timedelta(hours=time.numbers()[0], minutes=time.numbers()[1], seconds=time.numbers()[2])
|
|
|
|
@action('检测工作页面')
|
|
def at_assignment():
|
|
"""
|
|
判断是否在工作页面
|
|
"""
|
|
# 不能以 R.Daily.IconTitleAssign 作为判断依据,
|
|
# 因为标题出现后还有一段动画
|
|
return image.find_multi([
|
|
R.Daily.ButtonAssignmentShortenTime,
|
|
R.Daily.IconAssignMiniLive,
|
|
R.Daily.IconAssignOnlineLive,
|
|
]) is not None
|
|
|
|
@task('工作')
|
|
def assignment():
|
|
"""领取工作奖励并重新分配工作"""
|
|
if not conf().assignment.enabled:
|
|
logger.info('Assignment is disabled.')
|
|
return
|
|
if not at_home():
|
|
goto_home()
|
|
btn_assignment = image.expect_wait(R.Daily.ButtonAssignmentPartial)
|
|
notification_rect = rect_expand(btn_assignment.rect, top=40, right=40)
|
|
complete_rect = rect_expand(btn_assignment.rect, right=40, bottom=60)
|
|
with device.pinned():
|
|
completed = color.find('#ff6085', rect=complete_rect)
|
|
if completed:
|
|
logger.info('Assignment completed. Acquiring...')
|
|
notification_dot = color.find('#ff134a', rect=notification_rect)
|
|
if not notification_dot and not completed:
|
|
logger.info('No action needed.')
|
|
# TODO: 获取剩余时间,并根据时间更新调度
|
|
return
|
|
|
|
# 点击工作按钮
|
|
logger.debug('Clicking assignment icon.')
|
|
device.click(btn_assignment)
|
|
# 等待加载、领取奖励
|
|
while not at_assignment():
|
|
if completed and handle_claim_assignment():
|
|
logger.info('Assignment acquired.')
|
|
# 重新分配
|
|
if conf().assignment.mini_live_reassign_enabled:
|
|
if image.find(R.Daily.IconAssignMiniLive):
|
|
assign('mini')
|
|
else:
|
|
logger.info('MiniLive reassign is disabled.')
|
|
while not at_assignment():
|
|
pass
|
|
if conf().assignment.online_live_reassign_enabled:
|
|
if image.find(R.Daily.IconAssignOnlineLive):
|
|
assign('online')
|
|
else:
|
|
logger.info('OnlineLive reassign is disabled.')
|
|
# 等待动画结束
|
|
while not at_assignment():
|
|
pass
|
|
|
|
if __name__ == '__main__':
|
|
import logging
|
|
logging.basicConfig(level=logging.INFO, format='[%(asctime)s] [%(levelname)s] [%(name)s] [%(funcName)s] [%(lineno)d] %(message)s')
|
|
logger.setLevel(logging.DEBUG)
|
|
# assignment()
|
|
# print(get_remaining_time())
|
|
assign('online')
|