-
Notifications
You must be signed in to change notification settings - Fork 5
/
FB_page_adder_bot.py
260 lines (230 loc) · 11.6 KB
/
FB_page_adder_bot.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
#! python3
# FB_page_adder_bot.py - script to interface via Telegram in support to FB_Bot.py, used to add new pages and channel to the running list
# to avoid race conditions or other errors, this writes to an intermediate CSV file that is then read by FB_bot.py, and it handles adding the pages
# version is 20180908
# if you want to say anything go to @Udinanon on Telegram or check my email here on GitHub
# DISTRIBUTED UNDER GNU LGPL v3 or latest
# THE AUTHOR OF THE SCRIPT DOES NOT AUTHORIZE MILITARY USE OF HIS WORK OR USAGE IN ANY MILITARY-REALTED ENVIROMENT WITHOUT HIS EXPLICIT CONSENT
# is this thing vulnerable to code injection?
import requests
import logging
import time
import re
import argparse
import configparser
import csv
import telegram
from telegram.ext import Updater, CommandHandler, Filters, CallbackQueryHandler, ConversationHandler, MessageHandler
from telegram import Bot
CHANNEL, PAGES, SELECT_SINGLE_CHANNEL=range(3)
FB_Page_regex = re.compile(r"https:\/\/www\.facebook\.com")
TIME_regex = re.compile(r"(#)(1[0-9]{9})(#)")
def argument_parser(): # description of the program and command line arguments
parser = argparse.ArgumentParser(description="Support script to add new FB pages and channels to running list")
parser.add_argument("-ini_file", dest="ini_file", default="./FB_adder.ini", help="Path to INI file that sources all basic info to the bot, see the GitHub for more; defaults to ./FB_adder.ini")
return vars(parser.parse_args())
def config_parser(ini_file):
config=configparser.ConfigParser(interpolation=None)
config.read(ini_file)
basic_config, log_config=config["BASIC"], config["LOG"]
numeric_level=getattr(logging, log_config["debug_level"].upper(), None)
if not isinstance(numeric_level, int):
raise ValueError("Invalid log level in configuration file: " + log_config["debug_level"])
log_config["log_file"]=log_config["log_file_name"]+get_day(log_config["date_structure"])+".log"
logging.basicConfig(filename = log_config["log_file"], level = numeric_level)
global out_file
out_file=basic_config["output_file"]
global pages_file
pages_file=basic_config["FB_pages_file"]
global admin_id
admin_id=basic_config["admin_id"]
global temp_pages
temp_pages=basic_config["temp_file"]
global TOKEN
TOKEN=basic_config["bot_token"]
global max_n_of_pages
max_n_of_pages=int(basic_config["max_n_of_pages_per_request"])
return basic_config, log_config
def update_logfile_date(log_config):
numeric_level = getattr(logging, log_config["debug_level"].upper(), None)
log_config["log_file"]=log_config["log_file_name"]+get_day(log_config["date_structure"])+".log"
logging.basicConfig(filename = log_config["log_file"], level = numeric_level)
# BOT HANDLERS
def start(bot, update):
bot.sendMessage(chat_id=update.message.chat_id, text="""Benvenuto!
Questo bot permette di seguiire le tue pagone Facebook preferite direttamente da Telegram!
Per veder le pagine attualmente attive ed i loro canali Telegram usa il comando /see_all, se invece vuoi aggiungere una pagina o un canale puoi usare il comando /add.
Tutte le richieste sono confermate manualmente e la funzione è ancora in beta, in caso di errore inaspettato contatta lo Sviluppatore @udinanon
Se sei interessato a come funziona il Bot, se vuoi modificarlo o attivare una tua versione vieni su [GitHub](https://github.com/MorenK1/telegram-facebook-bot)""", parse_mode=telegram.ParseMode.MARKDOWN)
def error(bot, update):
bot.sendMessage(chat_id=update.message.chat_id, text="Your message was not recognized, please try again")
def add(bot, update, user_data):
bot.sendMessage(chat_id=update.message.chat_id,
text="Ok so to add a page we first need a public channel, then you need to add this bot as an admin to said channel.\nAfterwards, send me the @CHANNEL_LINK with command /channel\n Es: /channel @ItalianGoodposting")
user_data["USER_NAME"] = str(update.message.from_user.username)
print(user_data["USER_NAME"]+" is trying to add a channel!")
return CHANNEL
def channel(bot, update, args, user_data):
print("CHANNEL")
if len(args) != 1:
bot.sendMessage(chat_id=update.message.chat_id, text="There was an error reading the name of the channel, they aren't supposed to have spaces\nThis is what the bot is reading: '" +
str(args) + "'\nIf you followed our instructions correctly, you might want to contact the Developer")
try:
channel_message=bot.sendMessage(chat_id=str(args[0]), text="TEST FOR THE CHANNEL")
time.sleep(5)
bot.deleteMessage(chat_id=str(args[0]), message_id=channel_message["message_id"])
user_data["CHANNEL_ID"] = str(args[0])
user_data["CHANNEL_NAME"] = str(channel_message["chat"]["title"])
bot.sendMessage(chat_id=update.message.chat_id, text="Ok the channel " + str(args[0]) +
" seems to be working correctly, now send me the links to the posts sections of the Facebook pages you are interested in, one per line, with no spaces or anything\nMaximum numer of pages is " + str(max_n_of_pages) + ", exceeding pages will be ignored")
return PAGES
except Exception as e:
bot.sendMessage(chat_id=update.message.chat_id, text="There was an error trying to write on the channel, here's some detail:\n" +
str(e) + "\nIf you followed our instructions correctly, you might want to contact the Developer")
logging.error("There was an error trying to write on the channel, here's some detail:\n" + str(e))
def pages(bot, update, user_data):
pages = update.message.text.splitlines()
pages = list(filter(lambda x: bool(re.search(r"https:\/\/www\.facebook\.com", x)), pages))
user_data["PAGES"] = []
global max_n_of_pages
if len(pages) > max_n_of_pages:
n_skipped_pages = len(pages) - max_n_of_pages
bot.sendMessage(chat_id = update.message.chat_id, text = "You submitted more than "+str(max_n_of_pages)+" pages, the leading " + \
str(n_skipped_pages) + " pages were skipped")
pages=pages[:max_n_of_pages]
for page in pages:
try:
r=requests.get(page)
user_data["PAGES"].append(page)
except Exception as e:
bot.sendMessage(chat_id = update.message.chat_id,
text = "There was a problem with one of the pages, it might be offline or not formatted correctly\nException: " + str(e) + " for page " + str(page)+"\nIn case it's not contact the Developer")
bot.sendMessage(chat_id = update.message.chat_id, text = "The pages were read correctly, here is what the bot found:\n" + " ".join(pages))
# if len(pages)==1:
# buttons=InlineKeyboardMarkup([InlineKeyboardButton("Yes", callback_data="yes"), InlineKeyboardButton("No", callback_data="no")])
# bot.sendMessage(chat_id=update.message.chat_id, text="Your channel only has one page, if you want we could hide the page's name to avoid repetition with the Channel name", reply_markup=buttons)
# return SELECT_SINGLE_CHANNEL
# else:
bot.sendMessage(chat_id = update.message.chat_id,
text = "The setup process has been completed, your channel should start being active in a couple of hours, if nothing happens contact the Developer")
user_data["USER_ID"]=update.message.from_user.id
time=save_data(user_data)
ask_admin(bot, user_data, time)
return ConversationHandler.END
def accept(bot, update):
print("ACCEPT FROM "+str(update.message.from_user))
if str(update.message.from_user.id)==str(admin_id):
msg=update.message.reply_to_message.text
accept_time=msg[:10:]
data, request=find_time(accept_time)
with open(temp_pages, "w") as file:
file.writelines(data)
with open(out_file, "a", encoding="utf_8") as file:
print("ADDING: "+str(request))
file.writelines(request)
req_time=str(int(time.time()))
print(req_time)
file.write("#"+req_time+"#\n")
def deny(bot, update):
if str(update.message.from_user.id)==str(admin_id):
msg=update.message.reply_to_message.message.text
time=msg[:10:]
data, request=find_time(time)
with open(temp_pages, "w") as file:
file.writelines(data)
def see_all(bot, update):
global pages_file
try:
with open(pages_file, "r", encoding = 'utf_8') as file:
next(file, None)
reader=csv.reader(file)
pages=list(reader)
logging.debug("ALL PAGES: " + str(pages))
message="Here are all the pages and channels currently handled\nStructure is: Human Readable data, page URL, channel\n"
for page in pages:
message=message + str(page[0]) + " " + str(page[2]) + " " + str(page[4]) + "\n"
bot.sendMessage(chat_id = update.message.chat_id, text = message)
except IOError:
bot.sendMessage(chat_id = update.message.chat_id, text = "The list is too long, iut needs to be split but I haven't implemented it yet")
logging.warning("Nessun file di input è stato trovato a " + pages_file)
def see(bot, update, args):
args=" ".join(args.lower())
global pages_file
try:
with open(pages_file, "r", encoding = 'utf_8') as file:
next(file, None)
reader=csv.reader(file)
pages=list(reader)
logging.debug("ALL PAGES: " + str(pages))
message="Here are all the pages with the requested name currently handled\nStructure is: Human Readable data, page URL, channel ID\n"
count=0
for page in pages:
if args in page[0].lower():
count += 1
message=message + str(page[0]) + " " + str(page[2]) + " " + str(page[5]) + "\n"
if count == 0:
bot.sendMessage(chat_id = update.messages.chat_id, text = "No pages with that name were found in the list")
else:
bot.sendMessage(chat_id = update.messages.chat_id, text = message)
except IOError:
logging.warning("Nessun file di input è stato trovato a " + pages_file)
# FUNCTIONS USED
def get_day(form="%y%m%d"):
day = time.strftime(str(form))
return day
def find_time(time):
with open(temp_pages, "r") as file:
data=file.readlines()
j=0
print("LOOKING FOR "+str(time))
for i in range(len(data)):
if TIME_regex.search(data[i]):
if int(data[i].strip().strip("#")) == int(time):
request=data[j:i:]
data=data[:j:]+data[i+1::]
print("FOUND IT!")
return data, request
else:
j=i
print("MA CHE CAZZ")
def ask_admin(bot, user_data, request_time):
pages="\n".join(user_data["PAGES"])
bot.sendMessage(chat_id=admin_id, text=str(request_time)+"\n"+str(user_data["USER_NAME"])+"\n"+str(user_data["USER_ID"])+"\n"+str(user_data["CHANNEL_ID"]) + "\n" + str(user_data["CHANNEL_NAME"])+"\n"+pages)
def save_data(user_data):
with open(temp_pages, "a") as file:
file.write(str(user_data["USER_NAME"])+"\n"+str(user_data["USER_ID"])+"\n")
file.write(str(user_data["CHANNEL_NAME"]) + "\n" + str(user_data["CHANNEL_ID"])+"\n")
for page in user_data["PAGES"]:
file.write(str(page)+"\n")
request_time=int(time.time())
file.write("#" + str(request_time) + "#\n")
return request_time
def main():
args=argument_parser()
basic_config, log_config=config_parser(args["ini_file"])
print("FB ADDER BOT")
global outfile
logging.info("OUTPUT FILE: " +out_file)
updater=Updater(token =TOKEN)
bot=Bot(token =TOKEN)
dispatcher=updater.dispatcher
start_handler=CommandHandler("start", start)
con_handler=ConversationHandler(entry_points = [CommandHandler("add", add, pass_user_data=True)],
states = {CHANNEL: [CommandHandler("channel", channel, pass_args=True, pass_user_data=True)], PAGES:[MessageHandler(Filters.text, pages, pass_user_data=True)]},
fallbacks=[MessageHandler(Filters.all, error)], conversation_timeout=0)
see_handler=CommandHandler("see", see)
see_all_handler=CommandHandler("see_all", see_all)
accept_handler=CommandHandler("accept", accept)
deny_handler=CommandHandler("deny", deny)
dispatcher.add_handler(start_handler)
dispatcher.add_handler(see_all_handler)
dispatcher.add_handler(see_handler)
dispatcher.add_handler(accept_handler)
dispatcher.add_handler(deny_handler)
dispatcher.add_handler(con_handler)
updater.start_polling()
while True:
time.sleep(10000)
update_logfile_date(log_config)
if __name__ == "__main__":
main()