mirror of
https://github.com/house-of-vanity/conf_bot.git
synced 2025-07-07 06:44:06 +00:00
Compare commits
10 Commits
Author | SHA1 | Date | |
---|---|---|---|
7428d1df51 | |||
c6f8876c2e | |||
1c0a3bd582 | |||
3fe8f87df8 | |||
31ce4d15cf | |||
7320a10b51 | |||
2eed876e6e | |||
977f918baa | |||
643ccfafbc | |||
3aa7982116 |
4
.gitignore
vendored
4
.gitignore
vendored
@ -4,3 +4,7 @@ assets/cert*
|
|||||||
main.db
|
main.db
|
||||||
main.db-journal
|
main.db-journal
|
||||||
settings.ini
|
settings.ini
|
||||||
|
code.png
|
||||||
|
*.swp
|
||||||
|
*.swo
|
||||||
|
*.allah
|
||||||
|
21
README.md
21
README.md
@ -3,8 +3,27 @@
|
|||||||
# Create your own spy bot in Telegram ¯\_(ツ)_/¯
|
# Create your own spy bot in Telegram ¯\_(ツ)_/¯
|
||||||
|
|
||||||
This bot is able to get every message in your group, log it and send simple stat about top 10 used words.
|
This bot is able to get every message in your group, log it and send simple stat about top 10 used words.
|
||||||
Also bot can summon every active member of group with @here command.
|
|
||||||
|
|
||||||
|
|
||||||
|
/code - highlight any code snippet following command. There is lexer guesser but you are able to specify language by adding last line comment like this:
|
||||||
|
```
|
||||||
|
/code
|
||||||
|
class Cat {
|
||||||
|
constructor(name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function get_name(any_object) {
|
||||||
|
console.log(any_object.name);
|
||||||
|
}
|
||||||
|
var my_cat = new Cat('Cassandra');
|
||||||
|
get_name(my_cat)
|
||||||
|
#js
|
||||||
|
```
|
||||||
|
/sql - perform an SQL request to internal bot SQLite database. Any WRITE requests are prohibited.
|
||||||
|
/stat - your top 10 words in conf.
|
||||||
|
|
||||||
|
Also bot can summon every active member of group with @here command or just with mentioning bot username like @test_huy_bot .
|
||||||
**Copyright**
|
**Copyright**
|
||||||
|
|
||||||
*As probabilistic morphological analyzer (PMA) this bot uses mystem app, which developed by yandex and provided as binary package.*
|
*As probabilistic morphological analyzer (PMA) this bot uses mystem app, which developed by yandex and provided as binary package.*
|
||||||
|
27
database.py
27
database.py
@ -1,5 +1,6 @@
|
|||||||
import datetime as dt
|
import datetime as dt
|
||||||
|
|
||||||
|
|
||||||
class DataBase:
|
class DataBase:
|
||||||
def __init__(self, basefile, scheme):
|
def __init__(self, basefile, scheme):
|
||||||
import sqlite3
|
import sqlite3
|
||||||
@ -35,10 +36,10 @@ class DataBase:
|
|||||||
return(self.execute(sql)[0][0])
|
return(self.execute(sql)[0][0])
|
||||||
|
|
||||||
def add_user(self,
|
def add_user(self,
|
||||||
username,
|
username,
|
||||||
user_id,
|
user_id,
|
||||||
first_name,
|
first_name,
|
||||||
last_name):
|
last_name):
|
||||||
date = int(dt.datetime.now().strftime("%s"))
|
date = int(dt.datetime.now().strftime("%s"))
|
||||||
sql = """INSERT OR IGNORE INTO
|
sql = """INSERT OR IGNORE INTO
|
||||||
user('id', 'username', 'first_name', 'last_name', 'date')
|
user('id', 'username', 'first_name', 'last_name', 'date')
|
||||||
@ -76,7 +77,7 @@ class DataBase:
|
|||||||
self.execute(sql)
|
self.execute(sql)
|
||||||
|
|
||||||
def get_top(self, user_id, conf_id, limit=10):
|
def get_top(self, user_id, conf_id, limit=10):
|
||||||
sql= """
|
sql = """
|
||||||
SELECT w.word, COUNT(*) as count FROM relations r
|
SELECT w.word, COUNT(*) as count FROM relations r
|
||||||
LEFT JOIN word w ON w.id = r.word_id
|
LEFT JOIN word w ON w.id = r.word_id
|
||||||
LEFT JOIN `user` u ON u.id = r.user_id
|
LEFT JOIN `user` u ON u.id = r.user_id
|
||||||
@ -99,7 +100,7 @@ class DataBase:
|
|||||||
return(result)
|
return(result)
|
||||||
|
|
||||||
def here(self, user_id, conf_id):
|
def here(self, user_id, conf_id):
|
||||||
sql= """
|
sql = """
|
||||||
SELECT DISTINCT(u.username) FROM relations r
|
SELECT DISTINCT(u.username) FROM relations r
|
||||||
LEFT JOIN user u
|
LEFT JOIN user u
|
||||||
ON u.id = r.user_id
|
ON u.id = r.user_id
|
||||||
@ -129,17 +130,17 @@ class DataBase:
|
|||||||
|
|
||||||
def command(self, sql):
|
def command(self, sql):
|
||||||
if 'DELETE' in sql.upper() \
|
if 'DELETE' in sql.upper() \
|
||||||
or 'INSERT' in sql.upper() \
|
or 'INSERT' in sql.upper() \
|
||||||
or 'UPDATE' in sql.upper() \
|
or 'UPDATE' in sql.upper() \
|
||||||
or 'DROP' in sql.upper() \
|
or 'DROP' in sql.upper() \
|
||||||
or 'CREATE' in sql.upper() \
|
or 'CREATE' in sql.upper() \
|
||||||
or 'ALTER' in sql.upper():
|
or 'ALTER' in sql.upper():
|
||||||
return('gtfo')
|
return('gtfo')
|
||||||
try:
|
try:
|
||||||
if 'LIMIT' in sql.upper()[-9:]:
|
if 'LIMIT' in sql.upper()[-9:]:
|
||||||
result = self.execute(sql)
|
result = self.execute(sql)
|
||||||
else:
|
else:
|
||||||
result = self.execute(sql + ' limit 20')
|
result = self.execute(sql + ' limit 20')
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
result = err
|
result = err
|
||||||
return(result)
|
return(result)
|
||||||
|
@ -12,4 +12,4 @@ db = DataBase(
|
|||||||
scheme='assets/main.db.sql')
|
scheme='assets/main.db.sql')
|
||||||
|
|
||||||
global worker
|
global worker
|
||||||
worker = MessageWorker(db = db)
|
worker = MessageWorker(db=db)
|
||||||
|
28
webhook.py
28
webhook.py
@ -1,7 +1,7 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
from http.server import HTTPServer,SimpleHTTPRequestHandler,CGIHTTPRequestHandler
|
from http.server import HTTPServer, SimpleHTTPRequestHandler, CGIHTTPRequestHandler
|
||||||
from socketserver import BaseServer
|
from socketserver import BaseServer
|
||||||
import ssl
|
import ssl
|
||||||
import json
|
import json
|
||||||
@ -10,11 +10,12 @@ import settings
|
|||||||
# fuckin dirty hack. idk the best way to inherit return func into
|
# fuckin dirty hack. idk the best way to inherit return func into
|
||||||
# RequestHandler class
|
# RequestHandler class
|
||||||
|
|
||||||
|
|
||||||
class RequestHandler(SimpleHTTPRequestHandler):
|
class RequestHandler(SimpleHTTPRequestHandler):
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
request,
|
request,
|
||||||
client_address,
|
client_address,
|
||||||
server):
|
server):
|
||||||
self.worker = settings.worker
|
self.worker = settings.worker
|
||||||
super(RequestHandler, self).__init__(
|
super(RequestHandler, self).__init__(
|
||||||
request=request,
|
request=request,
|
||||||
@ -36,20 +37,19 @@ class RequestHandler(SimpleHTTPRequestHandler):
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class WebHook:
|
class WebHook:
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
certfile,
|
certfile,
|
||||||
keyfile,
|
keyfile,
|
||||||
address = '0.0.0.0',
|
address='0.0.0.0',
|
||||||
port=8443,
|
port=8443,
|
||||||
RequestHandler=RequestHandler):
|
RequestHandler=RequestHandler):
|
||||||
|
|
||||||
self.httpd = HTTPServer((address, port), RequestHandler)
|
self.httpd = HTTPServer((address, port), RequestHandler)
|
||||||
self.httpd.socket = ssl.wrap_socket (self.httpd.socket,
|
self.httpd.socket = ssl.wrap_socket(self.httpd.socket,
|
||||||
certfile=certfile,
|
certfile=certfile,
|
||||||
keyfile=keyfile,
|
keyfile=keyfile,
|
||||||
server_side=True)
|
server_side=True)
|
||||||
|
|
||||||
def serve(self):
|
def serve(self):
|
||||||
try:
|
try:
|
||||||
|
155
worker.py
155
worker.py
@ -7,17 +7,63 @@ from database import DataBase
|
|||||||
import os
|
import os
|
||||||
import urllib.request
|
import urllib.request
|
||||||
from urllib.parse import urlencode
|
from urllib.parse import urlencode
|
||||||
|
import requests
|
||||||
|
import json
|
||||||
import settings
|
import settings
|
||||||
import re
|
import re
|
||||||
|
|
||||||
|
from pygments import highlight
|
||||||
|
from pygments.lexers import PythonLexer
|
||||||
|
from pygments.lexers import guess_lexer, get_lexer_by_name
|
||||||
|
from pygments.styles import get_style_by_name
|
||||||
|
from pygments.formatters import ImageFormatter
|
||||||
|
|
||||||
|
|
||||||
class MessageWorker:
|
class MessageWorker:
|
||||||
def __init__(self, db, stop_words = 'assets/stop-word.ru'):
|
def __init__(self, db, stop_words='assets/stop-word.ru', settings=settings):
|
||||||
self.stop_words = stop_words
|
self.stop_words = stop_words
|
||||||
self.db = db
|
self.db = db
|
||||||
|
self.telegram_key = settings.parser.get('bot', 'telegram_key')
|
||||||
|
self.telegram_api = settings.parser.get('bot', 'telegram_api')
|
||||||
|
self.me = self.getMe()
|
||||||
|
print("My name is %s" % self.me['result']['username'])
|
||||||
|
|
||||||
|
def getMe(self):
|
||||||
|
url = self.telegram_api + 'bot' + self.telegram_key + '/getMe'
|
||||||
|
print(url)
|
||||||
|
urllib.request.Request(url)
|
||||||
|
request = urllib.request.Request(url)
|
||||||
|
raw = urllib.request.urlopen(request).read().decode()
|
||||||
|
return json.loads(raw)
|
||||||
|
|
||||||
def handleUpdate(self, msg):
|
def handleUpdate(self, msg):
|
||||||
try:
|
try:
|
||||||
if msg['message']['text'] == '/scheme':
|
try:
|
||||||
|
input_message = msg['message']['text']
|
||||||
|
if ('@here' in input_message) or (' @'+self.me['result']['username'] in input_message):
|
||||||
|
conf_id = msg['message']['chat']['id']
|
||||||
|
user_id = msg['message']['from']['id']
|
||||||
|
chat_title = msg['message']['chat']['title']
|
||||||
|
self.db.add_conf(conf_id, chat_title)
|
||||||
|
if msg['message']['text'] != '@here':
|
||||||
|
message = msg['message']['text'].replace('@here', '\n').replace(' @'+self.me['result']['username'], '\n')
|
||||||
|
else:
|
||||||
|
message = """I summon you!\n"""
|
||||||
|
|
||||||
|
users = self.db.here(
|
||||||
|
user_id=user_id,
|
||||||
|
conf_id=conf_id
|
||||||
|
)
|
||||||
|
for user in users:
|
||||||
|
message += ' @%s ' % (user[0])
|
||||||
|
self.send(id=conf_id, msg=message)
|
||||||
|
return True
|
||||||
|
|
||||||
|
input_message = msg['message']['text'].replace(
|
||||||
|
'@' + self.me['result']['username'], '')
|
||||||
|
except:
|
||||||
|
input_message = msg['message']['text']
|
||||||
|
if input_message == '/scheme':
|
||||||
conf_id = msg['message']['chat']['id']
|
conf_id = msg['message']['chat']['id']
|
||||||
user_id = msg['message']['from']['id']
|
user_id = msg['message']['from']['id']
|
||||||
chat_title = msg['message']['chat']['title']
|
chat_title = msg['message']['chat']['title']
|
||||||
@ -25,7 +71,7 @@ class MessageWorker:
|
|||||||
self.send(id=conf_id, msg='```\n' + self.db.scheme + '\n```')
|
self.send(id=conf_id, msg='```\n' + self.db.scheme + '\n```')
|
||||||
return True
|
return True
|
||||||
|
|
||||||
if msg['message']['text'] == '/stat':
|
if input_message == '/stat':
|
||||||
conf_id = msg['message']['chat']['id']
|
conf_id = msg['message']['chat']['id']
|
||||||
user_id = msg['message']['from']['id']
|
user_id = msg['message']['from']['id']
|
||||||
chat_title = msg['message']['chat']['title']
|
chat_title = msg['message']['chat']['title']
|
||||||
@ -41,7 +87,7 @@ class MessageWorker:
|
|||||||
self.send(id=conf_id, msg=message)
|
self.send(id=conf_id, msg=message)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
if msg['message']['text'] == '/reset':
|
if input_message == '/reset':
|
||||||
conf_id = msg['message']['chat']['id']
|
conf_id = msg['message']['chat']['id']
|
||||||
user_id = msg['message']['from']['id']
|
user_id = msg['message']['from']['id']
|
||||||
chat_title = msg['message']['chat']['title']
|
chat_title = msg['message']['chat']['title']
|
||||||
@ -53,7 +99,7 @@ class MessageWorker:
|
|||||||
user_id=user_id)
|
user_id=user_id)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
if msg['message']['text'][:4] == '/sql':
|
if input_message[:4] == '/sql':
|
||||||
conf_id = msg['message']['chat']['id']
|
conf_id = msg['message']['chat']['id']
|
||||||
user_id = msg['message']['from']['id']
|
user_id = msg['message']['from']['id']
|
||||||
chat_title = msg['message']['chat']['title']
|
chat_title = msg['message']['chat']['title']
|
||||||
@ -62,35 +108,63 @@ class MessageWorker:
|
|||||||
|
|
||||||
res = self.db.command(sql)
|
res = self.db.command(sql)
|
||||||
if 'syntax' in str(res) \
|
if 'syntax' in str(res) \
|
||||||
or 'ambiguous' in str(res):
|
or 'ambiguous' in str(res):
|
||||||
self.send(id=conf_id, msg=str(res))
|
self.send(id=conf_id, msg=str(res))
|
||||||
return False
|
return False
|
||||||
try:
|
try:
|
||||||
msg = '```\n'
|
msg = '```\n'
|
||||||
for z in res:
|
for z in res:
|
||||||
for i in z:
|
for i in z:
|
||||||
msg = msg + str(i) + '\t'
|
msg = msg + str(i) + '\t'
|
||||||
msg = msg + '\n'
|
msg = msg + '\n'
|
||||||
except:
|
except:
|
||||||
msg = res
|
msg = res
|
||||||
self.send(id=conf_id, msg=msg + ' ```')
|
self.send(id=conf_id, msg=msg + ' ```')
|
||||||
return True
|
return True
|
||||||
|
|
||||||
if msg['message']['text'][:5] == '@here' or \
|
# if '@here' in input_message:
|
||||||
msg['message']['text'][5:] == '@here':
|
# conf_id = msg['message']['chat']['id']
|
||||||
|
# user_id = msg['message']['from']['id']
|
||||||
|
# chat_title = msg['message']['chat']['title']
|
||||||
|
# self.db.add_conf(conf_id, chat_title)
|
||||||
|
# if msg['message']['text'] != '@here':
|
||||||
|
# message = msg['message']['text'].replace('@here', '\n')
|
||||||
|
# else:
|
||||||
|
# message = """I summon you!\n"""
|
||||||
|
|
||||||
|
# users = self.db.here(
|
||||||
|
# user_id=user_id,
|
||||||
|
# conf_id=conf_id
|
||||||
|
# )
|
||||||
|
# for user in users:
|
||||||
|
# message += ' @%s ' % (user[0])
|
||||||
|
# self.send(id=conf_id, msg=message)
|
||||||
|
# return True
|
||||||
|
if input_message[:5] == '/code':
|
||||||
conf_id = msg['message']['chat']['id']
|
conf_id = msg['message']['chat']['id']
|
||||||
user_id = msg['message']['from']['id']
|
user_id = msg['message']['from']['id']
|
||||||
chat_title = msg['message']['chat']['title']
|
chat_title = msg['message']['chat']['title']
|
||||||
self.db.add_conf(conf_id, chat_title)
|
self.db.add_conf(conf_id, chat_title)
|
||||||
|
if len(msg['message']['text'][6:]) < 10000:
|
||||||
message = """I summon you!\n"""
|
code = msg['message']['text'][6:]
|
||||||
users = self.db.here(
|
code_tag = code[code.rfind('#') + 1:]
|
||||||
user_id=user_id,
|
try:
|
||||||
conf_id=conf_id
|
lexer = get_lexer_by_name(code_tag)
|
||||||
)
|
code = code[:code.rfind('#')]
|
||||||
for user in users:
|
print("Lexer is defined as %s" % lexer)
|
||||||
message += '@%s ' % (user[0])
|
except:
|
||||||
self.send(id=conf_id, msg=message)
|
lexer = guess_lexer(code)
|
||||||
|
print("lexer is %s" % lexer)
|
||||||
|
if lexer.name == 'Text only':
|
||||||
|
lexer = get_lexer_by_name('python')
|
||||||
|
highlight(code, lexer, ImageFormatter(
|
||||||
|
font_size=16,
|
||||||
|
line_number_bg="#242e0c",
|
||||||
|
line_number_fg="#faddf2",
|
||||||
|
line_number_bold=True,
|
||||||
|
font_name='DejaVuSansMono',
|
||||||
|
style=get_style_by_name('monokai')), outfile="code.png")
|
||||||
|
self.send_img(conf_id)
|
||||||
return True
|
return True
|
||||||
except:
|
except:
|
||||||
return False
|
return False
|
||||||
@ -108,35 +182,34 @@ class MessageWorker:
|
|||||||
user_id = msg['message']['from']['id']
|
user_id = msg['message']['from']['id']
|
||||||
chat_id = msg['message']['chat']['id']
|
chat_id = msg['message']['chat']['id']
|
||||||
chat_title = msg['message']['chat']['title']
|
chat_title = msg['message']['chat']['title']
|
||||||
#print(self.clean_text(text))
|
|
||||||
except:
|
except:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
collection = self.clean_text(text)
|
collection = self.clean_text(text)
|
||||||
|
|
||||||
self.db.add_user(username,
|
self.db.add_user(username,
|
||||||
user_id,
|
user_id,
|
||||||
first_name,
|
first_name,
|
||||||
last_name)
|
last_name)
|
||||||
|
|
||||||
self.db.add_conf(chat_id, chat_title)
|
self.db.add_conf(chat_id, chat_title)
|
||||||
|
|
||||||
for word in collection:
|
for word in collection:
|
||||||
self.db.add_relation(word=word, user_id=user_id, conf_id=chat_id)
|
self.db.add_relation(word=word, user_id=user_id, conf_id=chat_id)
|
||||||
|
|
||||||
|
|
||||||
def clean_text(self, s):
|
def clean_text(self, s):
|
||||||
file = open(self.stop_words, 'rt')
|
file = open(self.stop_words, 'rt')
|
||||||
sw = file.read().split('\n')
|
sw = file.read().split('\n')
|
||||||
file.close()
|
file.close()
|
||||||
s = re.sub(r'(https?:\/\/)?([\da-z\.-]+)\.([\/\w\.-]*)*\/?\S','',s,flags=re.MULTILINE)
|
s = re.sub(
|
||||||
|
r'(https?:\/\/)?([\da-z\.-]+)\.([\/\w\.-]*)*\/?\S', '', s, flags=re.MULTILINE)
|
||||||
print(s)
|
print(s)
|
||||||
# dirty hack with dat fucking file
|
# dirty hack with dat fucking file
|
||||||
fh = open("tmp.txt","w")
|
fh = open("tmp.txt", "w")
|
||||||
fh.write(s)
|
fh.write(s)
|
||||||
fh.close()
|
fh.close()
|
||||||
cmd = "./assets/mystem -nlwd < tmp.txt"
|
cmd = "./assets/mystem -nlwd < tmp.txt"
|
||||||
ps = subprocess.Popen(cmd,shell=True,stdout=subprocess.PIPE)
|
ps = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE)
|
||||||
output = ps.communicate()[0]
|
output = ps.communicate()[0]
|
||||||
os.remove("tmp.txt")
|
os.remove("tmp.txt")
|
||||||
# end of the fuckin' dirty hack
|
# end of the fuckin' dirty hack
|
||||||
@ -145,7 +218,7 @@ class MessageWorker:
|
|||||||
s = s.split('\n')
|
s = s.split('\n')
|
||||||
collection = []
|
collection = []
|
||||||
for word in s:
|
for word in s:
|
||||||
if len(word) >2:
|
if len(word) > 2:
|
||||||
if word not in sw:
|
if word not in sw:
|
||||||
collection.append(word)
|
collection.append(word)
|
||||||
else:
|
else:
|
||||||
@ -155,17 +228,21 @@ class MessageWorker:
|
|||||||
return collection
|
return collection
|
||||||
|
|
||||||
def send(self, id, msg):
|
def send(self, id, msg):
|
||||||
print(msg)
|
# print(msg)
|
||||||
url = settings.parser.get('bot', 'telegram_api') + \
|
url = self.telegram_api + 'bot' + self.telegram_key + '/sendMessage'
|
||||||
'bot'+ settings.parser.get('bot', 'telegram_key') \
|
|
||||||
+ '/sendMessage'
|
|
||||||
post_fields = {
|
post_fields = {
|
||||||
'text': msg,
|
'text': msg,
|
||||||
'chat_id': id,
|
'chat_id': id,
|
||||||
'parse_mode': 'Markdown',
|
'parse_mode': 'Markdown',
|
||||||
'disable_web_page_preview': 1
|
'disable_web_page_preview': 1
|
||||||
}
|
}
|
||||||
urllib.request.Request(url, urlencode(post_fields).encode())
|
urllib.request.Request(url, urlencode(post_fields).encode())
|
||||||
request = urllib.request.Request(url, urlencode(post_fields).encode())
|
request = urllib.request.Request(url, urlencode(post_fields).encode())
|
||||||
json = urllib.request.urlopen(request).read().decode()
|
json = urllib.request.urlopen(request).read().decode()
|
||||||
return json
|
return json
|
||||||
|
|
||||||
|
def send_img(self, id):
|
||||||
|
url = self.telegram_api + 'bot' + self.telegram_key + '/sendPhoto'
|
||||||
|
data = {'chat_id': id}
|
||||||
|
files = {'photo': open('code.png', 'rb')}
|
||||||
|
r = requests.post(url, files=files, data=data)
|
||||||
|
Reference in New Issue
Block a user