tox_irc_sync/tox-irc-sync.py

259 lines
8.6 KiB
Python
Raw Normal View History

2013-12-01 15:09:54 +00:00
import sys
import socket
import string
import select
import re
2014-02-20 11:38:20 +00:00
import pickle
2013-12-01 15:09:54 +00:00
2014-09-27 05:25:35 +00:00
from pytox import Tox, ToxAV
2013-12-01 15:09:54 +00:00
from time import sleep
from os.path import exists
2014-04-06 00:16:18 +00:00
from threading import Thread
2013-12-01 15:09:54 +00:00
2014-08-15 15:10:31 +00:00
SERVER = ['54.199.139.199', 33445, '7F9C31FE850E97CEFD4C4591DF93FC757C7C12549DDD55F8EEAECC34FE76C029']
2014-04-16 06:52:02 +00:00
GROUP_BOT = '56A1ADE4B65B86BCD51CC73E2CD4E542179F47959FE3E0E21B4B0ACDADE51855D34D34D37CB5'
2014-08-15 15:10:31 +00:00
PWD = ''
2013-12-01 15:09:54 +00:00
2014-08-15 15:10:31 +00:00
IRC_HOST = 'irc.freenode.net'
2013-12-01 15:09:54 +00:00
IRC_PORT = 6667
2014-08-15 15:10:31 +00:00
NAME = NICK = IDENT = REALNAME = 'SyncBot'
2013-12-01 15:09:54 +00:00
CHANNEL = '#tox-ontopic'
2014-02-20 11:27:49 +00:00
MEMORY_DB = 'memory.pickle'
2013-12-01 15:09:54 +00:00
2014-04-06 00:16:18 +00:00
class AV(ToxAV):
2014-08-05 06:36:03 +00:00
def __init__(self, core, max_calls):
2014-04-06 00:16:18 +00:00
self.core = self.get_tox()
2014-08-05 06:36:03 +00:00
self.cs = None
2014-04-09 20:48:24 +00:00
self.call_type = self.TypeAudio
2014-04-06 00:16:18 +00:00
2014-08-05 06:36:03 +00:00
def on_invite(self, idx):
self.cs = self.get_peer_csettings(idx, 0)
2014-08-15 15:10:31 +00:00
self.call_type = self.cs['call_type']
2014-04-09 20:48:24 +00:00
2014-08-15 15:10:31 +00:00
print('Incoming %s call from %d:%s ...' % (
'video' if self.call_type == self.TypeVideo else 'audio', idx,
2014-08-05 06:36:03 +00:00
self.core.get_name(self.get_peer_id(idx, 0))))
2014-04-09 20:48:24 +00:00
2014-08-05 06:36:03 +00:00
self.answer(idx, self.call_type)
2014-08-15 15:10:31 +00:00
print('Answered, in call...')
2014-04-09 20:48:24 +00:00
2014-08-05 06:36:03 +00:00
def on_start(self, idx):
2014-08-15 15:10:31 +00:00
self.change_settings(idx, {'max_video_width': 1920,
'max_video_height': 1080})
2014-08-05 06:36:03 +00:00
self.prepare_transmission(idx, self.jbufdc * 2, self.VADd,
True if self.call_type == self.TypeVideo else False)
2014-04-06 00:16:18 +00:00
2014-08-05 06:36:03 +00:00
def on_end(self, idx):
2014-04-06 00:16:18 +00:00
self.kill_transmission()
2014-04-09 20:48:24 +00:00
2014-08-05 06:36:03 +00:00
print('Call ended')
2014-04-06 00:16:18 +00:00
2014-08-05 06:36:03 +00:00
def on_peer_timeout(self, idx):
2014-04-06 00:16:18 +00:00
self.stop_call()
2014-08-05 06:36:03 +00:00
def on_audio_data(self, idx, size, data):
sys.stdout.write('.')
sys.stdout.flush()
self.send_audio(idx, size, data)
2014-04-06 00:16:18 +00:00
2014-08-05 06:36:03 +00:00
def on_video_data(self, idx, width, height, data):
sys.stdout.write('*')
sys.stdout.flush()
self.send_video(idx, width, height, data)
2014-04-06 00:16:18 +00:00
2014-12-17 11:17:29 +00:00
bot_toxname = 'SyncBot'
2014-04-06 00:16:18 +00:00
2013-12-01 15:09:54 +00:00
class SyncBot(Tox):
def __init__(self):
if exists('data'):
self.load_from_file('data')
2014-08-05 06:36:03 +00:00
self.av = AV(self, 10)
2013-12-01 15:09:54 +00:00
self.connect()
2014-12-17 11:17:29 +00:00
self.set_name(bot_toxname)
self.set_status_message("Send me a message with the word 'invite'")
2013-12-01 15:09:54 +00:00
print('ID: %s' % self.get_address())
2014-08-15 15:10:31 +00:00
self.readbuffer = ''
2013-12-01 15:09:54 +00:00
self.tox_group_id = None
self.irc_init()
2014-02-20 11:27:49 +00:00
self.memory = {}
if exists(MEMORY_DB):
2014-02-20 11:38:20 +00:00
with open(MEMORY_DB, 'r') as f:
self.memory = pickle.load(f)
def irc_init(self):
2013-12-01 15:09:54 +00:00
self.irc = socket.socket()
self.irc.connect((IRC_HOST, IRC_PORT))
2014-08-15 15:10:31 +00:00
self.irc.send('NICK %s\r\n' % NICK)
self.irc.send('USER %s %s bla :%s\r\n' % (IDENT, IRC_HOST, REALNAME))
2013-12-01 15:09:54 +00:00
def connect(self):
print('connecting...')
2014-08-15 14:38:38 +00:00
self.bootstrap_from_address(SERVER[0], SERVER[1], SERVER[2])
2013-12-11 15:55:40 +00:00
def ensure_exe(self, func, args):
count = 0
2013-12-11 16:02:01 +00:00
THRESHOLD = 50
2013-12-11 15:55:40 +00:00
while True:
try:
return func(*args)
except:
assert count < THRESHOLD
count += 1
for i in range(10):
self.do()
sleep(0.02)
2013-12-01 15:09:54 +00:00
def loop(self):
checked = False
self.joined = False
2013-12-11 16:02:01 +00:00
self.request = False
2013-12-01 15:09:54 +00:00
try:
while True:
status = self.isconnected()
if not checked and status:
print('Connected to DHT.')
checked = True
2013-12-11 16:02:01 +00:00
try:
self.bid = self.get_friend_id(GROUP_BOT)
except:
2014-08-15 15:10:31 +00:00
self.ensure_exe(self.add_friend, (GROUP_BOT, 'Hi'))
2013-12-11 16:02:01 +00:00
self.bid = self.get_friend_id(GROUP_BOT)
2013-12-01 15:09:54 +00:00
if checked and not status:
print('Disconnected from DHT.')
self.connect()
checked = False
2013-12-09 04:25:08 +00:00
readable, _, _ = select.select([self.irc], [], [], 0.01)
2013-12-01 15:09:54 +00:00
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())
2014-02-20 09:01:45 +00:00
msg = '[%s]: %s' % rx.groups()
2013-12-22 16:33:15 +00:00
content = rx.group(2)
if content[1:].startswith('ACTION '):
2014-02-20 09:01:45 +00:00
action = '[%s]: %s' % (rx.group(1),
2013-12-22 16:33:15 +00:00
rx.group(2)[8:-1])
self.ensure_exe(self.group_action_send,
(self.tox_group_id, action))
2013-12-11 15:55:40 +00:00
elif self.tox_group_id != None:
self.ensure_exe(self.group_message_send,
(self.tox_group_id, msg))
2013-12-01 15:09:54 +00:00
if content.startswith('^'):
self.handle_command(content)
2013-12-01 15:24:33 +00:00
l = line.rstrip().split()
2014-08-15 15:10:31 +00:00
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)
2013-12-01 15:24:33 +00:00
2013-12-01 15:09:54 +00:00
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)
2013-12-11 15:55:40 +00:00
def on_connection_status(self, friendId, status):
2013-12-11 16:02:01 +00:00
if not self.request and not self.joined \
and friendId == self.bid and status:
2013-12-11 15:55:40 +00:00
print('Groupbot online, trying to join group chat.')
2013-12-11 16:02:01 +00:00
self.request = True
self.ensure_exe(self.send_message, (self.bid, 'invite'))
2014-12-17 11:15:36 +00:00
def on_group_invite(self, friendid, type, data):
2013-12-01 15:09:54 +00:00
if not self.joined:
self.joined = True
2014-12-17 11:15:36 +00:00
self.tox_group_id = self.join_groupchat(friendid, data)
2013-12-01 15:09:54 +00:00
print('Joined groupchat.')
def on_group_message(self, groupnumber, friendgroupnumber, message):
name = self.group_peername(groupnumber, friendgroupnumber)
2014-04-06 00:12:34 +00:00
if len(name) and name != NAME:
2013-12-01 15:09:54 +00:00
print('TOX> %s: %s' % (name, message))
2014-02-20 18:28:35 +00:00
if message.startswith('>'):
2014-02-20 18:34:59 +00:00
message = '\x0309%s\x03' % message
2014-03-13 19:31:26 +00:00
self.irc_send('PRIVMSG %s :[%s]: %s\r\n' %
(CHANNEL, name, message))
if message.startswith('^'):
2014-02-20 11:04:54 +00:00
self.handle_command(message)
2013-12-01 15:09:54 +00:00
2013-12-22 16:33:15 +00:00
def on_group_action(self, groupnumber, friendgroupnumber, action):
name = self.group_peername(groupnumber, friendgroupnumber)
2014-04-06 00:12:34 +00:00
if len(name) and name != NAME:
2013-12-22 16:33:15 +00:00
print('TOX> %s: %s' % (name, action))
2014-02-20 18:28:35 +00:00
if action.startswith('>'):
2014-02-20 18:34:59 +00:00
action = '\x0309%s\x03' % action
2014-02-20 09:01:45 +00:00
self.irc_send('PRIVMSG %s :\x01ACTION [%s]: %s\x01\r\n' %
2013-12-22 16:33:15 +00:00
(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':
2014-03-13 19:33:34 +00:00
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))
2014-02-20 11:27:49 +00:00
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))
2014-02-20 11:02:07 +00:00
def handle_command(self, cmd):
2014-02-20 11:27:49 +00:00
cmd = cmd[1:]
if cmd in ['syncbot', 'echobot']:
self.send_both(self.get_address())
2014-03-13 19:33:34 +00:00
elif cmd == 'resync':
sys.exit(0)
2014-02-20 11:27:49 +00:00
elif cmd.startswith('remember '):
args = cmd[9:].split(' ')
subject = args[0]
desc = ' '.join(args[1:])
self.memory[subject] = desc
2014-02-20 11:38:20 +00:00
with open(MEMORY_DB, 'w') as f:
pickle.dump(self.memory, f)
2014-02-20 11:27:49 +00:00
self.send_both('Remembering ^%s: %s' % (subject, desc))
elif self.memory.has_key(cmd):
self.send_both(self.memory[cmd])
2014-02-20 11:02:07 +00:00
2013-12-01 15:09:54 +00:00
t = SyncBot()
t.loop()