Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

magic-judge-telegram-bot.py 8.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  1. import logging
  2. import json
  3. from telegram.ext import Updater, CommandHandler, InlineQueryHandler, CallbackQueryHandler, MessageHandler, Filters
  4. from telegram import InlineQueryResultArticle, InputTextMessageContent, InlineKeyboardButton, InlineKeyboardMarkup
  5. #logging.basicConfig(level=logging.DEBUG,
  6. # format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
  7. names = {}
  8. with open('data/names.json') as file:
  9. names = json.load(file)
  10. namesToSearch = names.keys()
  11. oracleData = {}
  12. with open('data/oracle.json') as file:
  13. oracleData = json.load(file)
  14. print('Registered {} card names and {} oracle entries'.format(len(namesToSearch), len(oracleData)))
  15. crData = {}
  16. with open('data/cr.json') as file:
  17. crData = json.load(file)
  18. crDataNames = crData['glossary'].keys()
  19. crDataNumbers = crData['sections'].keys()
  20. print('Registered {} CR glossary terms and {} CR sections'.format(len(crDataNames), len(crDataNumbers)))
  21. def format_card(card):
  22. mana = ''
  23. if 'manaCost' in card:
  24. mana = '\t' + card['manaCost']
  25. text = ''
  26. if 'text' in card:
  27. text = '\n' + card['text']
  28. footer = ''
  29. if "Creature" in card['type']:
  30. footer = '\n{}/{}'.format(card['power'], card['toughness'])
  31. if "Planeswalker" in card['type'] and 'loyalty' in card:
  32. footer = '\n{}'.format(card['loyalty'])
  33. return '<b>{}</b>{}\n<i>{}</i>{}{}'.format(
  34. card['name'],
  35. mana,
  36. card['type'],
  37. text,
  38. footer)
  39. def preview_card(card):
  40. mana = ''
  41. if 'manaCost' in card:
  42. mana = '\t' + card['manaCost']
  43. return '{}{}\n{}'.format(
  44. card['name'],
  45. mana,
  46. card['type'])
  47. def start(bot, update):
  48. commands = [
  49. '/o <card name or search strings> - oracle text for a card',
  50. '/q <question> - oracle text for cards mentioned in the question',
  51. '/cr <section> (coming soon)',
  52. '/ipg <section> (coming soon)',
  53. '/mtr <section> (coming soon)',
  54. ]
  55. update.message.reply_text('How can I help?\n{}'.format('\n'.join(commands)), quote = False)
  56. def search_names(words):
  57. nameCandidates = [name for name in namesToSearch if all(word in name.casefold() for word in words)]
  58. term = ' '.join(words)
  59. if len(words) > 1:
  60. goodCandidates = [name for name in nameCandidates if term in name.casefold()]
  61. if goodCandidates:
  62. nameCandidates = goodCandidates
  63. bestCandidates = [name for name in nameCandidates if term == name.casefold()]
  64. if bestCandidates:
  65. return bestCandidates
  66. return nameCandidates
  67. def oracle(bot, update, args):
  68. if not args:
  69. update.message.reply_text('I need some clues to search for, my master!', quote=False)
  70. return
  71. words = [word.casefold() for word in args]
  72. nameCandidates = search_names(words)
  73. if not nameCandidates:
  74. update.message.reply_text('I searched very thoroughly, but returned empty-handed, my master!', quote=False)
  75. return
  76. if len(nameCandidates) > 20:
  77. update.message.reply_text('I need more specific clues, my master! This would return {} names'.format(len(nameCandidates)), quote=False)
  78. return
  79. if len(nameCandidates) > 1:
  80. reply_markup = InlineKeyboardMarkup([[InlineKeyboardButton(name, callback_data=name)] for name in nameCandidates])
  81. update.message.reply_text('Which one?', reply_markup=reply_markup, quote=False)
  82. return
  83. reply = []
  84. for name in nameCandidates:
  85. for uniqueName in names[name]:
  86. reply.append(format_card(oracleData[uniqueName]))
  87. update.message.reply_text('\n'.join(reply), parse_mode='HTML', quote = False)
  88. def question(bot, update, args):
  89. text = ' '.join(args).casefold()
  90. reply = []
  91. for name in namesToSearch:
  92. if name.casefold() in text:
  93. reply.append('"' + name + '":\n' + '\n'.join([format_card(oracleData[uniqueName]) for uniqueName in names[name]]))
  94. if reply:
  95. update.message.reply_text('\n\n'.join(reply), parse_mode='HTML', quote = False)
  96. def inline_oracle(bot, update):
  97. query = update.inline_query.query.casefold()
  98. if not query:
  99. return
  100. if len(query) < 3:
  101. return
  102. words = query.split()
  103. nameCandidates = search_names(words)
  104. if not nameCandidates:
  105. return
  106. results = list()
  107. for word in nameCandidates[:3]:
  108. for uniqueName in names[word]:
  109. results.append(
  110. InlineQueryResultArticle(
  111. id=oracleData[uniqueName]['name'],
  112. title=word,
  113. description=preview_card(oracleData[uniqueName]),
  114. input_message_content=InputTextMessageContent(format_card(oracleData[uniqueName]), parse_mode='HTML')
  115. )
  116. )
  117. bot.answerInlineQuery(update.inline_query.id, results)
  118. def callback_name(bot, update):
  119. message_id = update.callback_query.message.message_id
  120. chat_id = update.callback_query.message.chat.id
  121. name = update.callback_query.data
  122. if not name in names:
  123. bot.answerCallbackQuery(update.callback_query.id)
  124. return
  125. bot.editMessageText(
  126. chat_id = chat_id,
  127. message_id = message_id,
  128. parse_mode = 'HTML',
  129. text = '\n'.join([format_card(oracleData[uniqueName]) for uniqueName in names[name]])
  130. )
  131. bot.answerCallbackQuery(update.callback_query.id)
  132. def text(bot, update):
  133. if update.message.chat.type != 'private':
  134. return
  135. text = update.message.text
  136. if len(text) < 30:
  137. oracle(bot, update, text.split())
  138. else:
  139. question(bot, update, text)
  140. def comp_rules(bot, update, args):
  141. if not args:
  142. update.message.reply_text('I need some clues to search for, my master!', quote=False)
  143. return
  144. words = [word.casefold() for word in args]
  145. if words[0][0].isdigit():
  146. lang = 'en'
  147. if len(words) > 1 and words[1] == 'ru':
  148. lang = 'ru'
  149. results = []
  150. other = []
  151. section = words[0].casefold()
  152. pos = len(section)
  153. for name in sorted([name for name in crDataNumbers if name.startswith(section)]):
  154. diff = name[pos:].strip('.')
  155. if len(diff) < 2 and (len(diff) == 0 or diff.isalpha()):
  156. results.append(name)
  157. elif not diff[-1:].isalpha():
  158. other.append(name)
  159. if not results:
  160. update.message.reply_text('This section doesn\'t exist, my master!', quote=False)
  161. return
  162. text = '\n'.join(['<b>{}</b> {}'.format(name, crData['sections'][name][lang]) for name in results])
  163. if other:
  164. text += '\n<i>(Subsections: {}-{})</i>'.format(other[0], other[-1])
  165. if len(text) > 4000:
  166. text = '<b>{}</b> {}\n<i>(See also: {}-{})</i>'.format(results[0], crData['sections'][results[0]][lang], results[1], results[-1])
  167. update.message.reply_text(text, parse_mode='HTML', quote = False)
  168. return
  169. nameCandidates = [name for name in crDataNames if all(word in name.casefold() for word in words)]
  170. term = ' '.join(words)
  171. if len(words) > 1:
  172. goodCandidates = [name for name in nameCandidates if term in name.casefold()]
  173. if goodCandidates:
  174. nameCandidates = goodCandidates
  175. bestCandidates = [name for name in nameCandidates if name.casefold().startswith(term)]
  176. if bestCandidates:
  177. nameCandidates = bestCandidates
  178. excellentCandidate = [name for name in nameCandidates if name.casefold() == term]
  179. if excellentCandidate:
  180. nameCandidates = excellentCandidate
  181. if not nameCandidates:
  182. update.message.reply_text('I searched very thoroughly, but returned empty-handed, my master!', quote=False)
  183. return
  184. if len(nameCandidates) > 20:
  185. update.message.reply_text('I need more specific clues, my master! This would return {} names'.format(len(nameCandidates)), quote=False)
  186. return
  187. text = '\n'.join(['<b>{}</b> {}'.format(name, crData['glossary'][name]) for name in sorted(nameCandidates)])
  188. update.message.reply_text(text, parse_mode='HTML', quote = False)
  189. def ask(bot, update, args):
  190. pass
  191. def dispatcher_setup(dispatcher):
  192. dispatcher.add_handler(CommandHandler('start', start))
  193. dispatcher.add_handler(CommandHandler('help', start))
  194. dispatcher.add_handler(CommandHandler('o', oracle, pass_args=True))
  195. dispatcher.add_handler(CommandHandler('q', question, pass_args=True))
  196. dispatcher.add_handler(CommandHandler('cr', comp_rules, pass_args=True))
  197. dispatcher.add_handler(CommandHandler('ask', ask, pass_args=True))
  198. dispatcher.add_handler(InlineQueryHandler(inline_oracle))
  199. dispatcher.add_handler(CallbackQueryHandler(callback_name))
  200. dispatcher.add_handler(MessageHandler(Filters.text, text))
  201. with open('config.json') as file:
  202. config = json.load(file)
  203. updater = Updater(config['token'])
  204. dispatcher_setup(updater.dispatcher)
  205. updater.start_polling()
  206. updater.idle()