You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

259 lines
8.6 KiB
Python

11 years ago
import sys
import socket
import string
import select
import re
10 years ago
import pickle
11 years ago
from pytox import Tox, ToxAV
11 years ago
from time import sleep
from os.path import exists
10 years ago
from threading import Thread
11 years ago
SERVER = ['54.199.139.199', 33445, '7F9C31FE850E97CEFD4C4591DF93FC757C7C12549DDD55F8EEAECC34FE76C029']
GROUP_BOT = '56A1ADE4B65B86BCD51CC73E2CD4E542179F47959FE3E0E21B4B0ACDADE51855D34D34D37CB5'
PWD = ''
11 years ago
IRC_HOST = 'irc.freenode.net'
11 years ago
IRC_PORT = 6667
NAME = NICK = IDENT = REALNAME = 'SyncBot'
11 years ago
CHANNEL = '#tox-ontopic'
MEMORY_DB = 'memory.pickle'
11 years ago
10 years ago
class AV(ToxAV):
10 years ago
def __init__(self, core, max_calls):
10 years ago
self.core = self.get_tox()
10 years ago
self.cs = None
self.call_type = self.TypeAudio
10 years ago
10 years ago
def on_invite(self, idx):
self.cs = self.get_peer_csettings(idx, 0)
self.call_type = self.cs['call_type']
print('Incoming %s call from %d:%s ...' % (
'video' if self.call_type == self.TypeVideo else 'audio', idx,
10 years ago
self.core.get_name(self.get_peer_id(idx, 0))))
10 years ago
self.answer(idx, self.call_type)
print('Answered, in call...')
10 years ago
def on_start(self, idx):
self.change_settings(idx, {'max_video_width': 1920,
'max_video_height': 1080})
10 years ago
self.prepare_transmission(idx, self.jbufdc * 2, self.VADd,
True if self.call_type == self.TypeVideo else False)
10 years ago
10 years ago
def on_end(self, idx):
10 years ago
self.kill_transmission()
10 years ago
print('Call ended')
10 years ago
10 years ago
def on_peer_timeout(self, idx):
10 years ago
self.stop_call()
10 years ago
def on_audio_data(self, idx, size, data):
sys.stdout.write('.')
sys.stdout.flush()
self.send_audio(idx, size, data)
10 years ago
10 years ago
def on_video_data(self, idx, width, height, data):
sys.stdout.write('*')
sys.stdout.flush()
self.send_video(idx, width, height, data)
10 years ago
10 years ago
bot_toxname = 'SyncBot'
10 years ago
11 years ago
class SyncBot(Tox):
def __init__(self):
if exists('data'):
self.load_from_file('data')
10 years ago
self.av = AV(self, 10)
11 years ago
self.connect()
10 years ago
self.set_name(bot_toxname)
self.set_status_message("Send me a message with the word 'invite'")
11 years ago
print('ID: %s' % self.get_address())
self.readbuffer = ''
11 years ago
self.tox_group_id = None
self.irc_init()
self.memory = {}
if exists(MEMORY_DB):
10 years ago
with open(MEMORY_DB, 'r') as f:
self.memory = pickle.load(f)
def irc_init(self):
11 years ago
self.irc = socket.socket()
self.irc.connect((IRC_HOST, IRC_PORT))
self.irc.send('NICK %s\r\n' % NICK)
self.irc.send('USER %s %s bla :%s\r\n' % (IDENT, IRC_HOST, REALNAME))
11 years ago
def connect(self):
print('connecting...')
10 years ago
self.bootstrap_from_address(SERVER[0], SERVER[1], SERVER[2])
def ensure_exe(self, func, args):
count = 0
11 years ago
THRESHOLD = 50
while True:
try:
return func(*args)
except:
assert count < THRESHOLD
count += 1
for i in range(10):
self.do()
sleep(0.02)
11 years ago
def loop(self):
checked = False
self.joined = False
11 years ago
self.request = False
11 years ago
try:
while True:
status = self.isconnected()
if not checked and status:
print('Connected to DHT.')
checked = True
11 years ago
try:
self.bid = self.get_friend_id(GROUP_BOT)
except:
self.ensure_exe(self.add_friend, (GROUP_BOT, 'Hi'))
11 years ago
self.bid = self.get_friend_id(GROUP_BOT)
11 years ago
if checked and not status:
print('Disconnected from DHT.')
self.connect()
checked = False
readable, _, _ = select.select([self.irc], [], [], 0.01)
11 years ago
if readable:
self.readbuffer += self.irc.recv(4096)
lines = self.readbuffer.split('\n')
self.readbuffer = lines.pop()
for line in lines:
rx = re.match(r':(.*?)!.*? PRIVMSG %s :(.*?)\r' %
CHANNEL, line, re.S)
if rx:
print('IRC> %s: %s' % rx.groups())
msg = '[%s]: %s' % rx.groups()
content = rx.group(2)
if content[1:].startswith('ACTION '):
action = '[%s]: %s' % (rx.group(1),
rx.group(2)[8:-1])
self.ensure_exe(self.group_action_send,
(self.tox_group_id, action))
elif self.tox_group_id != None:
self.ensure_exe(self.group_message_send,
(self.tox_group_id, msg))
11 years ago
if content.startswith('^'):
self.handle_command(content)
l = line.rstrip().split()
if l[0] == 'PING':
self.irc_send('PONG %s\r\n' % l[1])
if l[1] == '376':
self.irc.send('PRIVMSG NickServ :IDENTIFY %s %s\r\n'
% (NICK, PWD))
self.irc.send('JOIN %s\r\n' % CHANNEL)
11 years ago
self.do()
except KeyboardInterrupt:
self.save_to_file('data')
def irc_send(self, msg):
success = False
while not success:
try:
self.irc.send(msg)
success = True
break
except socket.error:
self.irc_init()
sleep(1)
def on_connection_status(self, friendId, status):
11 years ago
if not self.request and not self.joined \
and friendId == self.bid and status:
print('Groupbot online, trying to join group chat.')
11 years ago
self.request = True
self.ensure_exe(self.send_message, (self.bid, 'invite'))
def on_group_invite(self, friendid, type, data):
11 years ago
if not self.joined:
self.joined = True
self.tox_group_id = self.join_groupchat(friendid, data)
11 years ago
print('Joined groupchat.')
def on_group_message(self, groupnumber, friendgroupnumber, message):
name = self.group_peername(groupnumber, friendgroupnumber)
if len(name) and name != NAME:
11 years ago
print('TOX> %s: %s' % (name, message))
10 years ago
if message.startswith('>'):
10 years ago
message = '\x0309%s\x03' % message
self.irc_send('PRIVMSG %s :[%s]: %s\r\n' %
(CHANNEL, name, message))
if message.startswith('^'):
10 years ago
self.handle_command(message)
11 years ago
def on_group_action(self, groupnumber, friendgroupnumber, action):
name = self.group_peername(groupnumber, friendgroupnumber)
if len(name) and name != NAME:
print('TOX> %s: %s' % (name, action))
10 years ago
if action.startswith('>'):
10 years ago
action = '\x0309%s\x03' % action
self.irc_send('PRIVMSG %s :\x01ACTION [%s]: %s\x01\r\n' %
(CHANNEL, name, action))
def on_friend_request(self, pk, message):
print('Friend request from %s: %s' % (pk, message))
self.add_friend_norequest(pk)
print('Accepted.')
def on_friend_message(self, friendid, message):
if message == 'invite':
10 years ago
if not self.tox_group_id is None:
print('Inviting %s' % self.get_name(friendid))
self.invite_friend(friendid, self.tox_group_id)
return
else:
message = 'Waiting for GroupBot, please try again in 1 min.'
self.ensure_exe(self.send_message, (friendid, message))
def send_both(self, content):
self.ensure_exe(self.group_message_send, (self.tox_group_id, content))
self.irc_send('PRIVMSG %s :%s\r\n' % (CHANNEL, content))
10 years ago
def handle_command(self, cmd):
cmd = cmd[1:]
if cmd in ['syncbot', 'echobot']:
self.send_both(self.get_address())
10 years ago
elif cmd == 'resync':
sys.exit(0)
elif cmd.startswith('remember '):
args = cmd[9:].split(' ')
subject = args[0]
desc = ' '.join(args[1:])
self.memory[subject] = desc
10 years ago
with open(MEMORY_DB, 'w') as f:
pickle.dump(self.memory, f)
self.send_both('Remembering ^%s: %s' % (subject, desc))
elif self.memory.has_key(cmd):
self.send_both(self.memory[cmd])
10 years ago
11 years ago
t = SyncBot()
t.loop()