├── LICENSE ├── README.md ├── Readme_Img ├── Screenshot1.jpg └── Screenshot2.jpg ├── config.json ├── data.json └── main.py /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # telegram-submission-bot 2 | 3 | ## 准备 4 | * 安装Python并运行`pip install python-telegram-bot==11.1.0` 5 | * 创建1个Bot、1个Group和1个Public Channel 6 | 7 | ## 配置 8 | 打开`config.json`并配置 9 | ``` 10 | { 11 | "Admin": 0, //管理员用户ID(通常为8~9位数字) 12 | "Token": "", //Bot的Token 13 | "Group_ID": 0, //无需填写 14 | "Publish_Channel_ID": "" //频道ID(如:@channel) 15 | } 16 | ``` 17 | 运行bot后在审稿群中输入`/setgroup` 18 | 19 | ## 运行 20 | ``` 21 | python main.py 22 | ``` 23 | 24 | ## 使用 25 | ### 投稿 26 | ![Screenshot](https://github.com/Netrvin/telegram-submission-bot/raw/master/Readme_Img/Screenshot1.jpg) 27 | 28 | 将消息发送至机器人,选择是否保留消息来源后即可完成投稿(若转发他人的消息,则不可选择不保留消息来源) 29 | 可接收的投稿类型: 30 | * 文字 31 | * 图片 32 | * 音频/语音 33 | * 视频 34 | * 文件 35 | 36 | ### 审稿 37 | ![Screenshot](https://github.com/Netrvin/telegram-submission-bot/raw/master/Readme_Img/Screenshot2.jpg) 38 | 39 | 所有在审稿群中的用户,点击采用即可完成审稿 40 | 在群中回复稿件本身(不是稿件详情),可在采用的同时对其进行评论 41 | 42 | ## Todo (Features) 43 | - [x] 评论稿件 44 | - [x] 转发他人的消息禁止匿名,避免版权问题 45 | - [x] 采用稿件后通知投稿人 46 | - [x] 稿件详情添加投稿/审稿人内链 47 | - [x] 匿名发布稿件 48 | - [ ] 投稿统计 49 | - [ ] 多语言 50 | -------------------------------------------------------------------------------- /Readme_Img/Screenshot1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Netrvin/telegram-submission-bot/8d5c2069cc45dc915ae13f9c2a4f80f6bc247724/Readme_Img/Screenshot1.jpg -------------------------------------------------------------------------------- /Readme_Img/Screenshot2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Netrvin/telegram-submission-bot/8d5c2069cc45dc915ae13f9c2a4f80f6bc247724/Readme_Img/Screenshot2.jpg -------------------------------------------------------------------------------- /config.json: -------------------------------------------------------------------------------- 1 | { 2 | "Admin": 0, 3 | "Token": "", 4 | "Group_ID": 0, 5 | "Publish_Channel_ID": "" 6 | } -------------------------------------------------------------------------------- /data.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | 4 | import time 5 | import json 6 | import telegram.ext 7 | import telegram 8 | import sys 9 | import datetime 10 | import os 11 | import logging 12 | import threading 13 | import six 14 | 15 | if six.PY2: 16 | reload(sys) 17 | sys.setdefaultencoding('utf8') 18 | 19 | Version_Code = 'v1.0.0' 20 | 21 | logging.basicConfig(level=logging.INFO, 22 | format='%(asctime)s - %(name)s - %(levelname)s - %(message)s' 23 | ) 24 | 25 | PATH = os.path.dirname(os.path.realpath(__file__)) + '/' 26 | 27 | CONFIG = json.loads(open(PATH + 'config.json', 'r').read()) 28 | 29 | DATA_LOCK = False 30 | 31 | submission_list = json.loads(open(PATH + 'data.json', 'r').read()) 32 | 33 | 34 | def save_data(): 35 | global DATA_LOCK 36 | while DATA_LOCK: 37 | time.sleep(0.05) 38 | DATA_LOCK = True 39 | f = open(PATH + 'data.json', 'w') 40 | f.write(json.dumps(submission_list, ensure_ascii=False)) 41 | f.close() 42 | DATA_LOCK = False 43 | 44 | 45 | def save_config(): 46 | f = open(PATH + 'config.json', 'w') 47 | f.write(json.dumps(CONFIG, indent=4)) 48 | f.close() 49 | 50 | 51 | updater = telegram.ext.Updater(token=CONFIG['Token']) 52 | dispatcher = updater.dispatcher 53 | 54 | me = updater.bot.get_me() 55 | CONFIG['ID'] = me.id 56 | CONFIG['Username'] = '@' + me.username 57 | 58 | print('Starting... (ID: ' + str(CONFIG['ID']) + ', Username: ' + CONFIG['Username'] + ')') 59 | 60 | 61 | def process_msg(bot, update): 62 | if update.channel_post != None: 63 | return 64 | if update.message.chat_id == CONFIG['Group_ID'] \ 65 | and update.message.reply_to_message != None: 66 | if update.message.reply_to_message.from_user.id == CONFIG['ID'] \ 67 | and (update.message.reply_to_message.forward_from != None 68 | or update.message.reply_to_message.forward_from_chat 69 | != None): 70 | msg = update.message.reply_to_message 71 | global submission_list 72 | if submission_list[str(CONFIG['Group_ID']) + ':' 73 | + str(msg.message_id)]['posted'] == True: 74 | return 75 | if submission_list[str(CONFIG['Group_ID']) + ':' 76 | + str(msg.message_id)]['type'] == 'real': 77 | post = real_name_post(bot, msg, 78 | update.message.from_user) 79 | elif submission_list[str(CONFIG['Group_ID']) + ':' 80 | + str(msg.message_id)]['type'] \ 81 | == 'anonymous': 82 | 83 | post = anonymous_post(bot, msg, 84 | update.message.from_user) 85 | if update.message.text != None: 86 | bot.send_message(chat_id=CONFIG['Publish_Channel_ID'], 87 | text=update.message.text, 88 | reply_to_message_id=post.message_id) 89 | return 90 | if update.message.from_user.id == update.message.chat_id: 91 | markup = \ 92 | telegram.InlineKeyboardMarkup([[telegram.InlineKeyboardButton("是" 93 | , callback_data='submission_type:real'), 94 | telegram.InlineKeyboardButton("否", 95 | callback_data='submission_type:anonymous')], 96 | [telegram.InlineKeyboardButton("取消投稿", 97 | callback_data='cancel:submission')]]) 98 | if update.message.forward_from != None \ 99 | or update.message.forward_from_chat != None: 100 | if update.message.forward_from_chat != None: 101 | markup = \ 102 | telegram.InlineKeyboardMarkup([[telegram.InlineKeyboardButton("是" 103 | , callback_data='submission_type:real')], 104 | [telegram.InlineKeyboardButton("取消投稿", 105 | callback_data='cancel:submission')]]) 106 | elif update.message.forward_from.id \ 107 | != update.message.from_user.id: 108 | markup = \ 109 | telegram.InlineKeyboardMarkup([[telegram.InlineKeyboardButton("是" 110 | , callback_data='submission_type:real')], 111 | [telegram.InlineKeyboardButton("取消投稿", 112 | callback_data='cancel:submission')]]) 113 | bot.send_message(chat_id=update.message.chat_id, 114 | text="即将完成投稿...\n⁠您是否想要保留消息来源(保留消息发送者用户名)", 115 | reply_to_message_id=update.message.message_id, 116 | reply_markup=markup) 117 | 118 | 119 | def process_command(bot, update): 120 | if update.channel_post != None: 121 | return 122 | command = update.message.text[1:].replace(CONFIG['Username'], '' 123 | ).lower() 124 | if command == 'start': 125 | bot.send_message(chat_id=update.message.chat_id, 126 | text="""可接收的投稿类型: 127 | 文字 128 | 图片 129 | 音频/语音 130 | 视频 131 | 文件""") 132 | return 133 | if command == 'version': 134 | bot.send_message(chat_id=update.message.chat_id, 135 | text='Telegram Submission Bot\n' 136 | + Version_Code 137 | + '\nhttps://github.com/Netrvin/telegram-submission-bot' 138 | ) 139 | return 140 | if update.message.from_user.id == CONFIG['Admin']: 141 | if command == 'setgroup': 142 | CONFIG['Group_ID'] = update.message.chat_id 143 | save_config() 144 | bot.send_message(chat_id=update.message.chat_id, 145 | text="已设置本群为审稿群") 146 | return 147 | 148 | 149 | def anonymous_post(bot, msg, editor): 150 | if msg.audio != None: 151 | r = bot.send_audio(chat_id=CONFIG['Publish_Channel_ID'], 152 | audio=msg.audio, caption=msg.caption) 153 | elif msg.document != None: 154 | r = bot.send_document(chat_id=CONFIG['Publish_Channel_ID'], 155 | document=msg.document, 156 | caption=msg.caption) 157 | elif msg.voice != None: 158 | r = bot.send_voice(chat_id=CONFIG['Publish_Channel_ID'], 159 | voice=msg.voice, caption=msg.caption) 160 | elif msg.video != None: 161 | r = bot.send_video(chat_id=CONFIG['Publish_Channel_ID'], 162 | video=msg.video, caption=msg.caption) 163 | elif msg.photo: 164 | r = bot.send_photo(chat_id=CONFIG['Publish_Channel_ID'], 165 | photo=msg.photo[0], caption=msg.caption) 166 | else: 167 | r = bot.send_message(chat_id=CONFIG['Publish_Channel_ID'], 168 | text=msg.text_markdown, 169 | parse_mode=telegram.ParseMode.MARKDOWN) 170 | 171 | submission_list[str(CONFIG['Group_ID']) + ':' 172 | + str(msg.message_id)]['posted'] = True 173 | bot.edit_message_text(text="新投稿\n投稿人: [" 174 | + submission_list[str(CONFIG['Group_ID']) 175 | + ':' + str(msg.message_id)]['Sender_Name'] 176 | + '](tg://user?id=' 177 | + str(submission_list[str(CONFIG['Group_ID']) 178 | + ':' + str(msg.message_id)]['Sender_ID']) 179 | + """) 180 | 来源: 保留 181 | 审稿人: [""" + editor.name 182 | + '](tg://user?id=' + str(editor.id) 183 | + ")\n已采用", chat_id=CONFIG['Group_ID'], 184 | parse_mode=telegram.ParseMode.MARKDOWN, 185 | message_id=submission_list[str(CONFIG['Group_ID' 186 | ]) + ':' + str(msg.message_id)]['Markup_ID']) 187 | bot.send_message(chat_id=submission_list[str(CONFIG['Group_ID']) 188 | + ':' + str(msg.message_id)]['Sender_ID'], 189 | text="您的稿件已过审,感谢您对我们的支持", 190 | reply_to_message_id=submission_list[str(CONFIG['Group_ID' 191 | ]) + ':' + str(msg.message_id)]['Original_MsgID']) 192 | threading.Thread(target=save_data).start() 193 | return r 194 | 195 | 196 | def real_name_post(bot, msg, editor): 197 | global submission_list 198 | r = bot.forward_message(chat_id=CONFIG['Publish_Channel_ID'], 199 | from_chat_id=CONFIG['Group_ID'], 200 | message_id=msg.message_id) 201 | 202 | submission_list[str(CONFIG['Group_ID']) + ':' 203 | + str(msg.message_id)]['posted'] = True 204 | bot.edit_message_text(text="新投稿\n投稿人: [" 205 | + submission_list[str(CONFIG['Group_ID']) 206 | + ':' + str(msg.message_id)]['Sender_Name'] 207 | + '](tg://user?id=' 208 | + str(submission_list[str(CONFIG['Group_ID']) 209 | + ':' + str(msg.message_id)]['Sender_ID']) 210 | + """) 211 | 来源: 保留 212 | 审稿人: [""" + editor.name 213 | + '](tg://user?id=' + str(editor.id) 214 | + ")\n已采用", chat_id=CONFIG['Group_ID'], 215 | parse_mode=telegram.ParseMode.MARKDOWN, 216 | message_id=submission_list[str(CONFIG['Group_ID' 217 | ]) + ':' + str(msg.message_id)]['Markup_ID']) 218 | bot.send_message(chat_id=submission_list[str(CONFIG['Group_ID']) 219 | + ':' + str(msg.message_id)]['Sender_ID'], 220 | text="您的稿件已过审,感谢您对我们的支持", 221 | reply_to_message_id=submission_list[str(CONFIG['Group_ID' 222 | ]) + ':' + str(msg.message_id)]['Original_MsgID']) 223 | threading.Thread(target=save_data).start() 224 | return r 225 | 226 | 227 | def process_callback(bot, update): 228 | if update.channel_post != None: 229 | return 230 | global submission_list 231 | query = update.callback_query 232 | if query.message.chat_id == CONFIG['Group_ID'] and query.data \ 233 | == 'receive:real': 234 | real_name_post(bot, query.message.reply_to_message, 235 | query.from_user) 236 | return 237 | if query.message.chat_id == CONFIG['Group_ID'] and query.data \ 238 | == 'receive:anonymous': 239 | anonymous_post(bot, query.message.reply_to_message, 240 | query.from_user) 241 | return 242 | if query.data == 'cancel:submission': 243 | bot.edit_message_text(text="已取消投稿", 244 | chat_id=query.message.chat_id, 245 | message_id=query.message.message_id) 246 | return 247 | msg = "新投稿\n投稿人: [" + query.message.reply_to_message.from_user.name \ 248 | + '](tg://user?id=' \ 249 | + str(query.message.reply_to_message.from_user.id) + ")\n来源: " 250 | fwd_msg = bot.forward_message(chat_id=CONFIG['Group_ID'], 251 | from_chat_id=query.message.chat_id, 252 | message_id=query.message.reply_to_message.message_id) 253 | 254 | submission_list[str(CONFIG['Group_ID']) + ':' 255 | + str(fwd_msg.message_id)] = {} 256 | 257 | submission_list[str(CONFIG['Group_ID']) + ':' 258 | + str(fwd_msg.message_id)]['posted'] = False 259 | 260 | submission_list[str(CONFIG['Group_ID']) + ':' 261 | + str(fwd_msg.message_id)]['Sender_Name'] = \ 262 | query.message.reply_to_message.from_user.name 263 | 264 | submission_list[str(CONFIG['Group_ID']) + ':' 265 | + str(fwd_msg.message_id)]['Sender_ID'] = \ 266 | query.message.reply_to_message.from_user.id 267 | 268 | submission_list[str(CONFIG['Group_ID']) + ':' 269 | + str(fwd_msg.message_id)]['Original_MsgID'] = \ 270 | query.message.reply_to_message.message_id 271 | 272 | if query.data == 'submission_type:real': 273 | msg += "保留" 274 | 275 | submission_list[str(CONFIG['Group_ID']) + ':' 276 | + str(fwd_msg.message_id)]['type'] = 'real' 277 | markup = \ 278 | telegram.InlineKeyboardMarkup([[telegram.InlineKeyboardButton("采用" 279 | , callback_data='receive:real')]]) 280 | markup_msg = bot.send_message(chat_id=CONFIG['Group_ID'], 281 | text=msg, reply_to_message_id=fwd_msg.message_id, 282 | reply_markup=markup, 283 | parse_mode=telegram.ParseMode.MARKDOWN) 284 | 285 | submission_list[str(CONFIG['Group_ID']) + ':' 286 | + str(fwd_msg.message_id)]['Markup_ID'] = \ 287 | markup_msg.message_id 288 | elif query.data == 'submission_type:anonymous': 289 | msg += "匿名" 290 | 291 | submission_list[str(CONFIG['Group_ID']) + ':' 292 | + str(fwd_msg.message_id)]['type'] = 'anonymous' 293 | markup = \ 294 | telegram.InlineKeyboardMarkup([[telegram.InlineKeyboardButton("采用" 295 | , callback_data='receive:anonymous')]]) 296 | markup_msg = bot.send_message(chat_id=CONFIG['Group_ID'], 297 | text=msg, reply_to_message_id=fwd_msg.message_id, 298 | reply_markup=markup, 299 | parse_mode=telegram.ParseMode.MARKDOWN) 300 | 301 | submission_list[str(CONFIG['Group_ID']) + ':' 302 | + str(fwd_msg.message_id)]['Markup_ID'] = \ 303 | markup_msg.message_id 304 | bot.edit_message_text(text="感谢您的投稿", chat_id=query.message.chat_id, 305 | message_id=query.message.message_id) 306 | threading.Thread(target=save_data).start() 307 | 308 | 309 | dispatcher.add_handler(telegram.ext.MessageHandler(telegram.ext.Filters.text 310 | | telegram.ext.Filters.audio 311 | | telegram.ext.Filters.photo 312 | | telegram.ext.Filters.video 313 | | telegram.ext.Filters.voice 314 | | telegram.ext.Filters.document, process_msg)) 315 | 316 | dispatcher.add_handler(telegram.ext.MessageHandler(telegram.ext.Filters.command, 317 | process_command)) 318 | 319 | dispatcher.add_handler(telegram.ext.CallbackQueryHandler(process_callback)) 320 | 321 | updater.start_polling() 322 | print('Started') 323 | updater.idle() 324 | print('Stopping...') 325 | save_data() 326 | print('Data saved.') 327 | print('Stopped.') 328 | --------------------------------------------------------------------------------