添加了查询 B 站动漫的命令,修复一些细节的 bug

This commit is contained in:
Richard Chien 2017-02-23 17:32:24 +08:00
parent 6e1ac79024
commit f1fdb34fba
7 changed files with 239 additions and 12 deletions

View File

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

View File

@ -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'

View File

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

View File

@ -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