Lets you submit and vote on images
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 

211 行
7.3 KiB

  1. from telegram.ext import Updater, MessageHandler, Filters, CallbackContext, CommandHandler
  2. from telegram import Update, InputMediaPhoto
  3. import json
  4. import sys
  5. import io
  6. import logging
  7. from PIL import Image
  8. import random
  9. from mwt import MWT
  10. submissions = {}
  11. names = {}
  12. polls = {}
  13. poll_options = {}
  14. status = {}
  15. @MWT(timeout=60*60)
  16. def get_admin_ids(bot, chat_id):
  17. """Returns a list of admin IDs for a given chat. Results are cached for 1 hour."""
  18. return [admin.user.id for admin in bot.get_chat_administrators(chat_id)]
  19. def ensure_admin(func):
  20. def wrapper(update, context, *args, **kwargs):
  21. chat_id = update.effective_chat.id
  22. user_id = update.effective_user.id
  23. if user_id in get_admin_ids(context.bot, chat_id):
  24. return func(update, context, *args, **kwargs)
  25. return wrapper
  26. def ensure_chat(func):
  27. def wrapper(update, *args, **kwargs):
  28. chat_id = update.effective_chat.id
  29. if chat_id not in submissions:
  30. submissions[chat_id] = {}
  31. names[chat_id] = {}
  32. status[chat_id] = "closed"
  33. polls[chat_id] = {}
  34. poll_options[chat_id] = []
  35. print("Added chat: ", chat_id)
  36. return func(update, *args, **kwargs)
  37. return wrapper
  38. def ensure_user(func):
  39. def wrapper(update, *args, **kwargs):
  40. chat_id = update.effective_chat.id
  41. user_id = update.effective_user.id
  42. if user_id not in submissions[chat_id]:
  43. names[chat_id][user_id] = update.effective_user.first_name
  44. print("Added user: ", user_id, " - ", update.effective_user.first_name)
  45. return func(update, *args, **kwargs)
  46. return wrapper
  47. def update_name(func):
  48. def wrapper(update, *args, **kwargs):
  49. chat_id = update.effective_chat.id
  50. user_id = update.effective_user.id
  51. if user_id not in submissions[update.effective_chat.id]:
  52. names[chat_id][user_id] = update.effective_user.first_name
  53. print("Got name for ", user_id, ": ", update.effective_user.first_name)
  54. return func(update, *args, **kwargs)
  55. return wrapper
  56. def ensure_closed(func):
  57. def wrapper(update, context, *args, **kwargs):
  58. chat_id = update.effective_chat.id
  59. if status[chat_id] == "closed":
  60. return func(update, context, *args, **kwargs)
  61. else:
  62. context.bot.send_message(chat_id=chat_id, text="I need to be closed to do that. I'm currently: " + status[chat_id])
  63. return wrapper
  64. def ensure_open(func):
  65. def wrapper(update, context, *args, **kwargs):
  66. chat_id = update.effective_chat.id
  67. if status[chat_id] == "open":
  68. return func(update, context, *args, **kwargs)
  69. else:
  70. context.bot.send_message(chat_id=chat_id, text="I need to be open to do that. I'm currently: " + status[chat_id])
  71. return wrapper
  72. def ensure_polling(func):
  73. def wrapper(update, context, *args, **kwargs):
  74. chat_id = update.effective_chat.id
  75. if status[chat_id] == "polling":
  76. return func(update, context, *args, **kwargs)
  77. else:
  78. context.bot.send_message(chat_id=chat_id, text="I need to be polling to do that. I'm currently: " + status[chat_id])
  79. return wrapper
  80. @ensure_chat
  81. @ensure_user
  82. @update_name
  83. @ensure_open
  84. def accept_photo(update: Update, context: CallbackContext):
  85. chat_id = update.effective_chat.id
  86. user_id = update.effective_user.id
  87. file_id = update.message.photo[-1].file_id
  88. submissions[chat_id][user_id] = file_id
  89. print(file_id)
  90. @ensure_chat
  91. @ensure_admin
  92. @ensure_closed
  93. def open_submissions(update: Update, context: CallbackContext):
  94. chat_id = update.effective_chat.id
  95. submissions[chat_id] = {}
  96. context.bot.send_message(chat_id=chat_id, text="Send your images as a reply to this post.")
  97. status[chat_id] = "open"
  98. @ensure_chat
  99. @ensure_admin
  100. @ensure_open
  101. def start_poll(update: Update, context: CallbackContext):
  102. chat_id = update.effective_chat.id
  103. status[chat_id] = "polling"
  104. poll_options[chat_id] = []
  105. users = list(submissions[chat_id].keys())
  106. print("Users with submissions: ", users)
  107. chosen_users = random.sample(users, k=min(len(users), 10))
  108. options = []
  109. chosen = []
  110. for index, user_id in enumerate(chosen_users):
  111. options.append(str(index+1) + ": " + names[chat_id][user_id])
  112. chosen.append(submissions[chat_id][user_id])
  113. poll_options[chat_id].append(user_id)
  114. if len(chosen) == 0:
  115. context.bot.send_message(chat_id=chat_id, text="There were no submissions.")
  116. status[chat_id] = "closed"
  117. elif len(chosen) == 1:
  118. context.bot.send_photo(chat_id=chat_id, photo=chosen[0])
  119. context.bot.send_message(chat_id=chat_id, text="There was only one submission. " + options[0] + " is the winner.")
  120. status[chat_id] = "closed"
  121. else:
  122. input_media = list(map(lambda pair: InputMediaPhoto(pair[1], caption=pair[0]), zip(options, chosen)))
  123. context.bot.send_media_group(chat_id=chat_id, media=input_media)
  124. polls[chat_id] = context.bot.send_poll(chat_id=chat_id, options = options, question="Pick an icon").message_id
  125. @ensure_chat
  126. @ensure_admin
  127. @ensure_polling
  128. def decide_poll(update: Update, context: CallbackContext):
  129. chat_id = update.effective_chat.id
  130. status[chat_id] = "closed"
  131. result = context.bot.stop_poll(chat_id=chat_id, message_id=polls[chat_id])
  132. votes = -1
  133. winners = []
  134. for index, option in enumerate(result.options):
  135. if option.voter_count > votes:
  136. winners = []
  137. if option.voter_count >= votes:
  138. winners.append(index)
  139. votes = option.voter_count
  140. winner = random.choice(winners)
  141. winner_id = poll_options[chat_id][winner]
  142. winner_name = names[chat_id][winner_id]
  143. winner_photo = submissions[chat_id][winner_id]
  144. context.bot.send_message(chat_id=chat_id, text="The winner was " + winner_name)
  145. context.bot.send_photo(chat_id=chat_id, photo=winner_photo)
  146. @ensure_chat
  147. @ensure_admin
  148. def cancel(update: Update, context: CallbackContext):
  149. chat_id = update.effective_chat.id
  150. status[chat_id] = "closed"
  151. submissions[chat_id] = {}
  152. del polls[chat_id]
  153. @ensure_chat
  154. def show_status(update: Update, context: CallbackContext):
  155. chat_id = update.effective_chat.id
  156. if status[chat_id] == "closed":
  157. context.bot.send_message(chat_id=chat_id, text="I am currently closed.")
  158. elif status[chat_id] == "open":
  159. context.bot.send_message(chat_id=chat_id, text=f"I am currently open for submissions. There are {len(submissions[chat_id])} submissions.")
  160. elif status[chat_id] == "polling":
  161. context.bot.send_message(chat_id=chat_id, text="I am currently polling.")
  162. if __name__ == "__main__":
  163. try:
  164. config = json.load(open("config.json", "r", encoding="utf-8"))
  165. except:
  166. logging.error("Couldn't read the config!")
  167. sys.exit(1)
  168. updater = Updater(token=config["token"], use_context=True)
  169. dispatcher = updater.dispatcher
  170. dispatcher.add_handler(MessageHandler(Filters.photo, accept_photo))
  171. dispatcher.add_handler(CommandHandler("open", open_submissions))
  172. dispatcher.add_handler(CommandHandler("poll", start_poll))
  173. dispatcher.add_handler(CommandHandler("decide", decide_poll))
  174. dispatcher.add_handler(CommandHandler("cancel", cancel))
  175. dispatcher.add_handler(CommandHandler("status", show_status))
  176. updater.start_polling()
  177. updater.idle()