mirror of
https://github.com/nonebot/nonebot2.git
synced 2024-11-30 17:15:08 +08:00
添加了查询 B 站动漫的命令,修复一些细节的 bug
This commit is contained in:
parent
6e1ac79024
commit
f1fdb34fba
25
command.py
25
command.py
@ -302,7 +302,30 @@ def split_arguments(maxsplit=0):
|
|||||||
elif isinstance(argument, (list, tuple)):
|
elif isinstance(argument, (list, tuple)):
|
||||||
argv = list(argument)
|
argv = list(argument)
|
||||||
else:
|
else:
|
||||||
argv = list(filter(lambda arg: arg, re.split('|'.join(_command_args_seps), argument, maxsplit)))
|
regexp = re.compile('|'.join(_command_args_seps))
|
||||||
|
if maxsplit == 0:
|
||||||
|
argv = list(filter(lambda arg: arg, regexp.split(argument)))
|
||||||
|
else:
|
||||||
|
cur = 0
|
||||||
|
tmp_argument = argument
|
||||||
|
argv = []
|
||||||
|
while cur <= maxsplit:
|
||||||
|
sl = regexp.split(tmp_argument, 1)
|
||||||
|
if len(sl) == 1:
|
||||||
|
if sl[0]:
|
||||||
|
argv.append(sl[0])
|
||||||
|
break
|
||||||
|
# Here len(sl) is > 1 (== 2)
|
||||||
|
if not sl[0]:
|
||||||
|
tmp_argument = sl[1]
|
||||||
|
continue
|
||||||
|
if cur < maxsplit:
|
||||||
|
argv.append(sl[0])
|
||||||
|
tmp_argument = sl[1]
|
||||||
|
else:
|
||||||
|
# Last time
|
||||||
|
argv.append(tmp_argument)
|
||||||
|
cur += 1
|
||||||
return func(argument, argv=argv, *args, **kwargs)
|
return func(argument, argv=argv, *args, **kwargs)
|
||||||
|
|
||||||
return wrapper
|
return wrapper
|
||||||
|
147
commands/bilibili.py
Normal file
147
commands/bilibili.py
Normal file
@ -0,0 +1,147 @@
|
|||||||
|
import re
|
||||||
|
import math
|
||||||
|
from datetime import datetime, timedelta
|
||||||
|
|
||||||
|
import requests
|
||||||
|
import pytz
|
||||||
|
|
||||||
|
from command import CommandRegistry, split_arguments
|
||||||
|
from commands import core
|
||||||
|
|
||||||
|
__registry__ = cr = CommandRegistry()
|
||||||
|
|
||||||
|
|
||||||
|
@cr.register('anime_index', 'anime-index', '番剧索引', '番剧', '新番')
|
||||||
|
@split_arguments()
|
||||||
|
def anime_index(_, ctx_msg, argv=None):
|
||||||
|
now = datetime.now(pytz.timezone('Asia/Shanghai'))
|
||||||
|
year = now.year
|
||||||
|
month = now.month
|
||||||
|
if len(argv) == 2 and re.fullmatch('(?:20)?\d{2}', argv[0]) and re.fullmatch('\d{1,2}', argv[1]):
|
||||||
|
year = int(argv[0]) if len(argv[0]) > 2 else 2000 + int(argv[0])
|
||||||
|
month = int(argv[1])
|
||||||
|
elif len(argv) == 1 and re.fullmatch('\d{1,2}', argv[0]):
|
||||||
|
month = int(argv[0])
|
||||||
|
elif len(argv) == 1 and re.fullmatch('(?:20)?\d{2}-\d{1,2}', argv[0]):
|
||||||
|
year, month = [int(x) for x in argv[0].split('-')]
|
||||||
|
year = 2000 + year if year < 100 else year
|
||||||
|
elif len(argv):
|
||||||
|
core.echo('抱歉无法识别的输入的参数,下面将给出本季度的番剧~', ctx_msg)
|
||||||
|
|
||||||
|
quarter = math.ceil(month / 3)
|
||||||
|
json = requests.get('http://bangumi.bilibili.com/web_api/season/index'
|
||||||
|
'?page=1&page_size=20&version=0&is_finish=0'
|
||||||
|
'&start_year=%d&quarter=%d&tag_id=&index_type=1&index_sort=0' % (year, quarter)).json()
|
||||||
|
if json and json.get('result') and int(json['result'].get('count', 0)) > 0:
|
||||||
|
anime_list = json['result'].get('list', [])
|
||||||
|
reply = '%d年%d月番剧\n按追番人数排序,前20部如下:\n\n' % (year, 1 + (quarter - 1) * 3)
|
||||||
|
reply += '\n'.join([anime.get('title', '未知动画') + ' '
|
||||||
|
+ ('未开播' if anime.get('total_count', -1) < 0
|
||||||
|
else ('全%d话' % anime['total_count']
|
||||||
|
if anime['newest_ep_index'] == str(anime['total_count'])
|
||||||
|
else '更新至%s' % anime['newest_ep_index']
|
||||||
|
+ ('话' if anime['newest_ep_index'].isdigit() else '')))
|
||||||
|
for anime in anime_list])
|
||||||
|
|
||||||
|
reply += '\n\n更多详细资料见 bilibili 官网 ' \
|
||||||
|
'http://bangumi.bilibili.com/anime/index' \
|
||||||
|
'#p=1&v=0&area=&stat=0&y=%d&q=%d&tag=&t=1&sort=0' % (year, quarter)
|
||||||
|
else:
|
||||||
|
reply = '没有查询到%d年%d月开播的番剧……' % (year, 1 + (quarter - 1) * 3)
|
||||||
|
|
||||||
|
core.echo(reply, ctx_msg)
|
||||||
|
|
||||||
|
|
||||||
|
@cr.register('anime_timeline', 'anime-timeline', '番剧时间表', '新番时间表')
|
||||||
|
@split_arguments(maxsplit=1)
|
||||||
|
def anime_timeline(args_text, ctx_msg, internal=False, argv=None):
|
||||||
|
if len(argv) == 0:
|
||||||
|
core.echo('请指定要查询的日期或番剧名称,例如下面(主要看参数,你的命令是对的~):\n\n'
|
||||||
|
'/新番时间表 02-21\n'
|
||||||
|
'/新番时间表 0\n'
|
||||||
|
'/新番时间表 小林家的龙女仆\n'
|
||||||
|
'/新番时间表 02-21 小林家的龙女仆\n\n'
|
||||||
|
'上面第二个例子的「0」代表和今天相差的天数,0表示今天,1表示明天,-1表示昨天,以此类推\n'
|
||||||
|
'参数中间记得用用空格隔开哦~', ctx_msg, internal)
|
||||||
|
return None
|
||||||
|
|
||||||
|
json = requests.get('http://bangumi.bilibili.com/web_api/timeline_v4').json()
|
||||||
|
if not json or 'result' not in json:
|
||||||
|
return None
|
||||||
|
|
||||||
|
timeline_list = json['result'] or []
|
||||||
|
|
||||||
|
date_str = None
|
||||||
|
anime_name = None
|
||||||
|
|
||||||
|
if re.fullmatch('\d{1,2}-\d{1,2}', argv[0]):
|
||||||
|
# month-day
|
||||||
|
date_str = argv[0]
|
||||||
|
argv = argv[1:]
|
||||||
|
elif re.fullmatch('-?\d', argv[0]):
|
||||||
|
# timedelta (days)
|
||||||
|
delt = timedelta(days=int(argv[0]))
|
||||||
|
dt = datetime.now() + delt
|
||||||
|
date_str = dt.strftime('%m-%d')
|
||||||
|
argv = argv[1:]
|
||||||
|
|
||||||
|
if len(argv) > 1:
|
||||||
|
anime_name = args_text.strip()
|
||||||
|
elif len(argv) == 1:
|
||||||
|
anime_name = argv[0].rstrip()
|
||||||
|
|
||||||
|
if date_str:
|
||||||
|
timeline_list = list(filter(lambda item: item.get('pub_date', '').endswith(date_str), timeline_list))
|
||||||
|
if anime_name:
|
||||||
|
timeline_list = list(filter(
|
||||||
|
lambda item: anime_name.lower() in item.get('title', '').lower()
|
||||||
|
and len(anime_name) > len(item.get('title', '')) / 4,
|
||||||
|
timeline_list
|
||||||
|
))
|
||||||
|
|
||||||
|
if internal:
|
||||||
|
return timeline_list
|
||||||
|
|
||||||
|
if date_str and anime_name:
|
||||||
|
if not timeline_list:
|
||||||
|
reply = '没更新'
|
||||||
|
else:
|
||||||
|
reply = ''
|
||||||
|
for item in timeline_list:
|
||||||
|
reply += '\n' + ('更新了' if item['is_published'] else '将在%s更新' % item['ontime']) \
|
||||||
|
+ '第%s话' % item['ep_index'] if item['ep_index'].isdigit() else item['ep_index']
|
||||||
|
reply = reply.lstrip()
|
||||||
|
|
||||||
|
core.echo(reply, ctx_msg, internal)
|
||||||
|
return
|
||||||
|
|
||||||
|
if not timeline_list:
|
||||||
|
core.echo('没有找到符合条件的时间表……', ctx_msg, internal)
|
||||||
|
return
|
||||||
|
|
||||||
|
if date_str and not anime_name:
|
||||||
|
month, day = [int(x) for x in date_str.split('-')]
|
||||||
|
reply = '在%d月%d日更新的番剧有:\n\n' % (month, day)
|
||||||
|
reply += '\n'.join([item.get('title', '未知动画') + ' '
|
||||||
|
+ item.get('ontime', '未知时间') + ' '
|
||||||
|
+ ('第%s话' % item.get('ep_index')
|
||||||
|
if item.get('ep_index', '').isdigit()
|
||||||
|
else item.get('ep_index', ''))
|
||||||
|
for item in timeline_list])
|
||||||
|
core.echo(reply, ctx_msg, internal)
|
||||||
|
elif anime_name and not date_str:
|
||||||
|
anime_dict = {}
|
||||||
|
for item in timeline_list:
|
||||||
|
k = item.get('title', '未知动画')
|
||||||
|
if k not in anime_dict:
|
||||||
|
anime_dict[k] = []
|
||||||
|
anime_dict[k].append(item)
|
||||||
|
|
||||||
|
for name, items in anime_dict.items():
|
||||||
|
reply = name + '\n'
|
||||||
|
for item in items:
|
||||||
|
_, month, day = [int(x) for x in item['pub_date'].split('-')]
|
||||||
|
reply += '\n' + ('已' if item['is_published'] else '将') \
|
||||||
|
+ '在%d月%d日%s更新' % (month, day, item['ontime']) \
|
||||||
|
+ '第%s话' % item['ep_index'] if item['ep_index'].isdigit() else item['ep_index']
|
||||||
|
core.echo(reply, ctx_msg, internal)
|
@ -45,7 +45,8 @@ def subscribe(args_text, ctx_msg, argv=None, internal=False, allow_interactive=T
|
|||||||
hour, minute = data['hour'], data['minute']
|
hour, minute = data['hour'], data['minute']
|
||||||
command = data['command']
|
command = data['command']
|
||||||
job = scheduler.add_job(
|
job = scheduler.add_job(
|
||||||
'-H %s -M %s %s %s' % (hour, minute, _scheduler_job_id_prefix + str(int(datetime.now().timestamp())), command),
|
'-H %s -M %s --multi %s %s' % (
|
||||||
|
hour, minute, _scheduler_job_id_prefix + str(int(datetime.now().timestamp())), command),
|
||||||
ctx_msg, internal=True
|
ctx_msg, internal=True
|
||||||
)
|
)
|
||||||
if internal:
|
if internal:
|
||||||
@ -138,7 +139,7 @@ def _subscribe_interactively(args_text, ctx_msg, source, data):
|
|||||||
if 'command' not in sess.data:
|
if 'command' not in sess.data:
|
||||||
# Ask for command
|
# Ask for command
|
||||||
core.echo(
|
core.echo(
|
||||||
'请输入你需要订阅的命令(包括所需的参数),不需要加开头的斜杠哦~\n\n'
|
'请输入你需要订阅的命令(包括所需的参数),每行一条,不需要加开头的斜杠哦~\n\n'
|
||||||
'例如(序号后的):\n'
|
'例如(序号后的):\n'
|
||||||
'(1) 天气 南京\n'
|
'(1) 天气 南京\n'
|
||||||
'(2) 知乎日报\n'
|
'(2) 知乎日报\n'
|
||||||
|
@ -13,6 +13,7 @@ _command_start_flags = get_command_start_flags()
|
|||||||
_command_args_start_flags = get_command_args_start_flags()
|
_command_args_start_flags = get_command_args_start_flags()
|
||||||
|
|
||||||
|
|
||||||
|
# noinspection PyBroadException
|
||||||
@as_filter(priority=0)
|
@as_filter(priority=0)
|
||||||
def _dispatch_command(ctx_msg):
|
def _dispatch_command(ctx_msg):
|
||||||
text = ctx_msg.get('text', '').lstrip()
|
text = ctx_msg.get('text', '').lstrip()
|
||||||
@ -41,14 +42,18 @@ def _dispatch_command(ctx_msg):
|
|||||||
# No fallback
|
# No fallback
|
||||||
raise SkipException
|
raise SkipException
|
||||||
else:
|
else:
|
||||||
# Split command and arguments
|
if start_flag == '' and interactive.has_session(source):
|
||||||
command = re.split('|'.join(_command_args_start_flags),
|
# Start flag is empty, so we don't override any sessions
|
||||||
text[len(start_flag):], 1)
|
command = [interactive.get_session(source).cmd, text]
|
||||||
if len(command) == 1:
|
else:
|
||||||
# Add an empty argument
|
# Split command and arguments
|
||||||
command.append('')
|
command = re.split('|'.join(_command_args_start_flags),
|
||||||
# Starting a new command, so remove previous command session, if any
|
text[len(start_flag):], 1)
|
||||||
interactive.remove_session(source)
|
if len(command) == 1:
|
||||||
|
# Add an empty argument
|
||||||
|
command.append('')
|
||||||
|
# Starting a new command, so remove previous command session, if any
|
||||||
|
interactive.remove_session(source)
|
||||||
|
|
||||||
command[0] = command[0].lower()
|
command[0] = command[0].lower()
|
||||||
ctx_msg['command'] = command[0]
|
ctx_msg['command'] = command[0]
|
||||||
@ -70,6 +75,10 @@ def _dispatch_command(ctx_msg):
|
|||||||
core.echo('你没有权限使用这个命令哦~', ctx_msg)
|
core.echo('你没有权限使用这个命令哦~', ctx_msg)
|
||||||
except CommandScopeError as se:
|
except CommandScopeError as se:
|
||||||
core.echo('这个命令不支持' + se.msg_type + '哦~', ctx_msg)
|
core.echo('这个命令不支持' + se.msg_type + '哦~', ctx_msg)
|
||||||
|
except Exception as e:
|
||||||
|
# Ignore all exceptions raised during command running
|
||||||
|
print(e)
|
||||||
|
core.echo('程序执行命令时发生了一点错误,可能没法回复啦~', ctx_msg)
|
||||||
|
|
||||||
|
|
||||||
def _add_registry_mod_cb(mod):
|
def _add_registry_mod_cb(mod):
|
||||||
|
48
nl_processors/bilibili.py
Normal file
48
nl_processors/bilibili.py
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
import re
|
||||||
|
|
||||||
|
from nl_processor import as_processor
|
||||||
|
|
||||||
|
|
||||||
|
@as_processor(keywords=('番', '动漫', '动画'))
|
||||||
|
def _processor_anime_index(sentence, segmentation):
|
||||||
|
m = re.search('(?:(?P<year>\d{2})\s*年\s*)?(?P<month>\d{1,2})\s*月', sentence)
|
||||||
|
year, month = None, None
|
||||||
|
if m:
|
||||||
|
year = m.group('year')
|
||||||
|
month = m.group('month')
|
||||||
|
|
||||||
|
args_text = month if month else ''
|
||||||
|
args_text = (str(year) + ' ' + args_text) if year else args_text
|
||||||
|
|
||||||
|
possibility = 80
|
||||||
|
if '哪些' in sentence or '什么' in sentence:
|
||||||
|
possibility += 3
|
||||||
|
if not re.search('b\s*站', sentence.lower()):
|
||||||
|
possibility -= 10
|
||||||
|
|
||||||
|
return possibility, 'bilibili.anime_index', args_text, None
|
||||||
|
|
||||||
|
|
||||||
|
@as_processor(keywords=('更新',))
|
||||||
|
def _processor_anime_timeline(sentence, segmentation):
|
||||||
|
m = re.match('(?P<day_str>(?:前|昨|今|明|大?后)天)?(?P<name>.+?)'
|
||||||
|
'(?P<day_str2>(?:前|昨|今|明|大?后)天)?(?:会|有)?更(?:不更)?新',
|
||||||
|
sentence)
|
||||||
|
day_str, name = None, None
|
||||||
|
if m:
|
||||||
|
day_str = m.group('day_str') or m.group('day_str2')
|
||||||
|
name = m.group('name')
|
||||||
|
|
||||||
|
if not name:
|
||||||
|
return None
|
||||||
|
|
||||||
|
possibility = 80
|
||||||
|
if not day_str:
|
||||||
|
possibility -= 5
|
||||||
|
if not re.search('b\s*站', sentence.lower()):
|
||||||
|
possibility -= 10
|
||||||
|
|
||||||
|
delta_day_dict = {'前天': -2, '昨天': -1, '今天': 0, '明天': 1, '后天': 2, '大后天': 3}
|
||||||
|
delta_day = delta_day_dict.get(day_str, 0)
|
||||||
|
|
||||||
|
return possibility, 'bilibili.anime_timeline', str(delta_day) + ' ' + name, None
|
@ -24,6 +24,5 @@ def _processor(sentence, segmentation):
|
|||||||
lang, query = m.group('lang'), m.group('query')
|
lang, query = m.group('lang'), m.group('query')
|
||||||
break
|
break
|
||||||
if lang and query:
|
if lang and query:
|
||||||
print('翻译: 目标语言:', lang, ', 待翻译文本:', query)
|
|
||||||
return 90, 'translate.translate_to', ' '.join((lang.strip(), query.strip(' ,,'))), None
|
return 90, 'translate.translate_to', ' '.join((lang.strip(), query.strip(' ,,'))), None
|
||||||
return None
|
return None
|
||||||
|
Loading…
Reference in New Issue
Block a user