async def update_seeker(): ''' 轮询官方四格漫画更新 若有更新则推送至订阅群 ''' index_api = 'https://comic.priconne-redive.jp/api/index' index = load_index() # 获取最新漫画信息 resp = await aiorequests.get(index_api, timeout=10) data = await resp.json() id_ = data['latest_cartoon']['id'] episode = data['latest_cartoon']['episode_num'] title = data['latest_cartoon']['title'] # 检查是否已在目录中 # 同一episode可能会被更新为另一张图片(官方修正),此时episode不变而id改变 # 所以需要两步判断 if episode in index: qs = urlparse(index[episode]['link']).query old_id = parse_qs(qs)['id'][0] if id_ == old_id: sv.logger.info('未检测到官漫更新') return # 确定已有更新,下载图片 sv.logger.info(f'发现更新 id={id_}') await download_comic(id_) # 推送至各个订阅群 pic = R.img('priconne/comic', get_pic_name(episode)) msg = f'プリンセスコネクト!Re:Dive公式4コマ更新!\n第{episode}話 {title}' await sv.broadcast(pic) await sv.broadcast(msg)
async def download_comic(id_): ''' 下载指定id的官方四格漫画,同时更新漫画目录index.json episode_num可能会小于id ''' base = 'https://comic.priconne-redive.jp/api/detail/' save_dir = R.img('priconne/comic/').path index = load_index() # 先从api获取detail,其中包含图片真正的链接 sv.logger.info(f'getting comic {id_} ...') url = base + id_ sv.logger.info(f'url={url}') resp = await aiorequests.get(url) sv.logger.info(f'status_code={resp.status_code}') if 200 != resp.status_code: return data = await resp.json() data = data[0] episode = data['episode_num'] title = data['title'] link = data['cartoon'] index[episode] = {'title': title, 'link': link} sv.logger.info(f'episode={index[episode]}') # 下载图片并保存 await download_img(os.path.join(save_dir, get_pic_name(episode)), link) # 保存官漫目录信息 with open(os.path.join(save_dir, 'index.json'), 'w', encoding='utf8') as f: json.dump(index, f, ensure_ascii=False)
async def _do_show_remain(bot: KokkoroBot, ev: EventInterface, args: ParseResult, at_user: bool): bm = BattleMaster(ev.get_group_id()) clan = _check_clan(bm) if at_user: _check_admin(ev, '才能催刀。您可以用【!查刀】查询余刀') rlist = bm.list_challenge_remain( 1, datetime.now() - timedelta(days=args.get('D', 0))) rlist.sort(key=lambda x: x[3] + x[4], reverse=True) msg = [f"\n{clan['name']}今日余刀:"] sum_remain = 0 for uid, _, name, r_n, r_e in rlist: if r_n or r_e: msg.append( f"剩{r_n}刀 补时{r_e}刀 | {bot.kkr_at(uid) if at_user else name}") sum_remain += r_n if len(msg) == 1: await bot.kkr_send(ev, f"今日{clan['name']}所有成员均已下班!各位辛苦了!", at_sender=True) else: msg.append(f'共计剩余{sum_remain}刀') msg.append('若有负数说明报刀有误 请注意核对\n使用“!出刀记录 @id”可查看详细记录') if at_user: msg.append("=========\n在?阿sir喊你出刀啦!") await bot.kkr_send(ev, '\n'.join(msg), at_sender=True) if at_user: await bot.kkr_send(ev, R.img('priconne/催刀.jpg'))
async def give_okodokai(bot, ev: EventInterface): uid = ev.get_author_id() if not lmt.check(uid): await bot.kkr_send(ev, '明日はもう一つプレゼントをご用意してお待ちしますね', at_sender=True) return lmt.increase(uid) present = random.choice(login_presents) todo = random.choice(todo_list) await bot.kkr_send(ev, R.img("priconne/kokkoro_stamp.png")) await bot.kkr_send( ev, f'\nおかえりなさいませ、主さま\n{present}を獲得しました\n私からのプレゼントです\n主人今天要{todo}吗?', at_sender=True)
async def normal_map(bot, ev: EventInterface): try: number = int(ev.get_param().remain) except Exception as e: await bot.kkr_send(ev, '参数必须为数字。示例:`刷图 10`') return img = f'{NORMAL_MAP_PREFIX}-{number}.jpg' img = R.img(f'priconne/quick/{img}') if not img.exist: await bot.kkr_send(ev, f'{number} 图刷图攻略未找到呜呜呜 ┭┮﹏┭┮') else: await bot.kkr_send(ev, f'{number} 图刷图攻略:') await bot.kkr_send(ev, img)
def download_chara_icon(id_, star): url = f'https://redive.estertion.win/icon/unit/{id_}{star}1.webp' save_path = R.img(f'priconne/unit/icon_unit_{id_}{star}1.png').path logger.info(f'Downloading chara icon from {url}') try: rsp = requests.get(url, stream=True, timeout=5) except Exception as e: logger.error(f'Failed to download {url}. {type(e)}') logger.exception(e) if 200 == rsp.status_code: img = Image.open(BytesIO(rsp.content)) img.save(save_path) logger.info(f'Saved to {save_path}') else: logger.error(f'Failed to download {url}. HTTP {rsp.status_code}')
async def add_sos(bot: KokkoroBot, ev: EventInterface, args: ParseResult): bm = BattleMaster(ev.get_group_id()) uid = ev.get_author_id() clan = _check_clan(bm) _check_member(bm, uid, bm.group) sub = _load_sub(bm.group) tree = sub.get_tree_list() if uid in tree: raise AlreadyExistError("您已在树上") sub.add_tree(uid) _save_sub(sub, bm.group) msg = ["\n您已上树,本Boss被击败时将会通知您", f"目前{clan['name']}挂树人数为{len(tree)}人:"] msg.extend(_gen_namelist_text(bot, bm, tree)) await bot.kkr_send(ev, '\n'.join(msg), at_sender=True) await bot.kkr_send(ev, R.img('priconne/挂树.jpg'))
async def comic(bot: KokkoroBot, ev: EventInterface): episode = ev.get_param().remain if not re.fullmatch(r'\d{0,3}', episode): return episode = episode.lstrip('0') if not episode: await bot.kkr_send(ev, '请输入漫画集数 如:官漫132', at_sender=True) return index = load_index() if episode not in index: await bot.kkr_send(ev, f'未查找到第{episode}话,敬请期待官方更新', at_sender=True) return title = index[episode]['title'] pic = R.img('priconne/comic/', get_pic_name(episode)) msg = f'プリンセスコネクト!Re:Dive公式4コマ\n第{episode}話 {title}' await bot.kkr_send(ev, pic) await bot.kkr_send(ev, msg, at_sender=True)
def icon(self): star = '3' if 1 <= self.star <= 5 else '6' res = R.img(f'priconne/unit/icon_unit_{self.id}{star}1.png') if not res.exist: res = R.img(f'priconne/unit/icon_unit_{self.id}31.png') if not res.exist: res = R.img(f'priconne/unit/icon_unit_{self.id}11.png') if not res.exist: # FIXME: 不方便改成异步请求 download_chara_icon(self.id, 6) download_chara_icon(self.id, 3) download_chara_icon(self.id, 1) res = R.img(f'priconne/unit/icon_unit_{self.id}{star}1.png') if not res.exist: res = R.img(f'priconne/unit/icon_unit_{self.id}31.png') if not res.exist: res = R.img(f'priconne/unit/icon_unit_{self.id}11.png') if not res.exist: res = R.img(f'priconne/unit/icon_unit_{UNKNOWN}31.png') return res
async def africa(bot: KokkoroBot, ev: EventInterface): cmd = ev.get_param().plain_text if cmd in util.join_iterable(_africa, _image_suffix) or random.random() < 0.05: await bot.kkr_send(ev, R.img('非洲人.png'))
async def new_year_burst(bot: KokkoroBot, ev: EventInterface): cmd = ev.get_param().plain_text if cmd in util.join_iterable(_ch, _image_suffix) or random.random() < 0.02: await bot.kkr_send(ev, R.img('newyearburst.gif')) await bot.kkr_send(ev, nyb_player)
from kokkoro.service import Service, BroadcastTag from kokkoro import R sv9 = Service('pcr-portion-reminder-utc9', enable_on_default=False, help_='药水购买小助手(UTC+9)') sv8 = Service('pcr-portion-reminder-utc8', enable_on_default=False, help_='药水购买小助手(UTC+8)') #msg = "主人様、记得买经验药水~" img = R.img('提醒药水小助手.jpg') @sv8.scheduled_job('cron', hour='0,6,12,18', misfire_grace_time=60 * 10) async def pcr_portion_reminder_utc8(): await sv8.broadcast(img, [BroadcastTag.cn_broadcast, BroadcastTag.tw_broadcast]) @sv9.scheduled_job('cron', hour='23,5,11,17', misfire_grace_time=60 * 10) async def pcr_portion_reminder_utc9(): await sv9.broadcast(img, BroadcastTag.jp_broadcast)
import numpy as np import datetime from kokkoro.common_interface import KokkoroBot, EventInterface from kokkoro.service import Service from kokkoro.util import FreqLimiter from kokkoro import R from .. import sv, cb_cmd _time_limit = 30*60 _lmt = FreqLimiter(_time_limit) b_constellations = ["摩羯","水瓶","双鱼","白羊","金牛","双子","巨蟹","狮子","处女","天秤","天蝎","射手"] #国服的(预测) background1 = R.img('priconne/公会离职报告模板.jpg') background2 = R.img('priconne/公会本期报告模板.jpg') REPORT_RESIGN = 0 REPORT_NORMAL = 1 REPORT_UNDECLARED = -1 sv = Service('clanbattle-report') @sv.on_fullmatch(('离职报告', 'retire-report')) async def send_resign_report(bot:KokkoroBot, event:EventInterface): await send_report(bot, event, type=REPORT_RESIGN) @sv.on_fullmatch(('会战报告', 'clanbattle-report')) async def send_normal_report(bot:KokkoroBot, event:EventInterface): await send_report(bot, event, type=REPORT_NORMAL)
async def chat_queshi(bot: KokkoroBot, ev: EventInterface): cmd = ev.get_param().plain_text if cmd in ['确实.jpg'] or random.random() < 0.05: await bot.kkr_send(ev, R.img('确实.jpg'))
async def jiuzhe(bot, ev): msglist = ['这是法刀吗?', f'恁搁着挠痒痒呢?', f'就这?', R.img('就这.jpg')] index = random.randint(0, len(msglist) - 1) await bot.kkr_send(ev, msglist[index])
import itertools, re from kokkoro import util, R from kokkoro.common_interface import EventInterface from . import sv tw_1 = R.img('priconne/quick/r17-4-1-tw.png') tw_2 = R.img('priconne/quick/r17-4-2-tw.png') jp_1 = R.img('priconne/quick/r18-3-1-jp.png') jp_2 = R.img('priconne/quick/r18-3-2-jp.png') jp_3 = R.img('priconne/quick/r18-3-3-jp.png') cn_1 = R.img('priconne/quick/r10-4-1-cn.jpg') cn_2 = R.img('priconne/quick/r10-4-2-cn.jpg') cn_3 = R.img('priconne/quick/r10-4-3-cn.jpg') @sv.on_rex(r'^(\*?([日台国陆b])服?([前中后]*)卫?)?rank(表|推荐|指南)?$') async def rank_sheet(bot, ev: EventInterface): match = ev.get_param().match is_jp = match.group(2) == '日' is_tw = match.group(2) == '台' is_cn = match.group(2) and match.group(2) in '国陆b' if not is_jp and not is_tw and not is_cn: await bot.kkr_send( ev, '\n请问您要查询哪个服务器的rank表?\n*日rank表\n*台rank表\n*B服rank表\n', at_sender=True) return msg = [ '\n※表格仅供参考,升r有风险,强化需谨慎\n※一切以会长要求为准——', ] if is_jp:
def random_base() -> R.ResImg: base_dir = R.img(BASE_LUCK_IMG_DIR).path random_img = random.choice(os.listdir(base_dir)) return R.img(os.path.join(BASE_LUCK_IMG_DIR, random_img))
def get_base_by_name(filename) -> R.ResImg: return R.img(os.path.join(BASE_LUCK_IMG_DIR, filename))
import aiohttp from kokkoro.service import Service from kokkoro.common_interface import KokkoroBot, EventInterface from kokkoro import R, util sv = Service('antiqks', help_='识破骑空士的阴谋') qks_url = ["granbluefantasy.jp"] qksimg = R.img('antiqks.jpg') @sv.on_keyword(qks_url) async def qks_keyword(bot: KokkoroBot, ev: EventInterface): msg = f'骑空士爪巴\n{qksimg}' await bot.kkr_send(ev, msg, at_sender=True) await util.silence(ev, 60) # 有潜在的安全问题 # @sv.on_rex(r'[a-zA-Z0-9\.]{4,12}\/[a-zA-Z0-9]+') async def qks_rex(bot: KokkoroBot, ev: EventInterface): match = ev.get_param().match msg = f'骑空士爪巴远点\n{qksimg}' res = 'http://' + match.group(0) async with aiohttp.TCPConnector(verify_ssl=False) as connector: async with aiohttp.request( 'GET', url=res, allow_redirects=False, connector=connector, ) as resp:
from kokkoro import R, log, util from . import _pcr_data logger = log.new_logger('chara') UNKNOWN = 1000 UnavailableChara = { 1067, # 穗希 1069, # 霸瞳 1072, # 可萝爹 1073, # 拉基拉基 1102, # 泳装大眼 } try: gadget_equip = R.img('priconne/gadget/equip.png').open() gadget_star = R.img('priconne/gadget/star.png').open() gadget_star_dis = R.img('priconne/gadget/star_disabled.png').open() gadget_star_pink = R.img('priconne/gadget/star_pink.png').open() unknown_chara_icon = R.img( f'priconne/unit/icon_unit_{UNKNOWN}31.png').open() except Exception as e: logger.exception(e) class Roster: def __init__(self): self._roster = pygtrie.CharTrie() self.update() def update(self):
import itertools, re from kokkoro import util, R from kokkoro.common_interface import EventInterface from . import sv p1 = R.img('priconne/quick/r16-5-tw-0.png') p2 = R.img('priconne/quick/r16-5-tw-1.png') p4 = R.img('priconne/quick/r17-5-jp-1.png') p5 = R.img('priconne/quick/r17-5-jp-2.png') p6 = R.img('priconne/quick/r17-5-jp-3.png') cn_rank = R.img('priconne/quick/r10-3.jpg') @sv.on_rex(r'^(\*?([日台国陆b])服?([前中后]*)卫?)?rank(表|推荐|指南)?$') async def rank_sheet(bot, ev: EventInterface): match = ev.get_param().match is_jp = match.group(2) == '日' is_tw = match.group(2) == '台' is_cn = match.group(2) and match.group(2) in '国陆b' if not is_jp and not is_tw and not is_cn: await bot.kkr_send( ev, '\n请问您要查询哪个服务器的rank表?\n*日rank表\n*台rank表\n*B服rank表\n', at_sender=True) return msg = [ '\n※表格仅供参考,升r有风险,强化需谨慎\n※一切以会长要求为准——', ] if is_jp: msg.append('※不定期搬运自图中Q群\n※广告为原作者推广,与本bot无关\nR17-5 rank表:') await bot.kkr_send(ev, '\n'.join(msg), at_sender=True)
async def yukari_sheet(bot, ev): await bot.kkr_send(ev, R.img('priconne/quick/黄骑充电.jpg')) await bot.kkr_send(ev, YUKARI_SHEET, at_sender=True)
async def new_year_burst(bot: KokkoroBot, ev: EventInterface): cmd = ev.get_param().plain_text if cmd in util.join_iterable(_ue_sorry, _image_suffix) or random.random() < 0.02: await bot.kkr_send(ev, R.img('ue_sorry.jpg'))