diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8d35cb3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +__pycache__ +*.pyc diff --git a/README b/README new file mode 100644 index 0000000..fa51902 --- /dev/null +++ b/README @@ -0,0 +1,18 @@ +|__ __/ ____|___ \ | | (_) | | + | | | (___ __) | _____ _____ _ __ | |_ ___ ___ _ __ _ _ __ | |_ ___ + | | \___ \ |__ < / _ \ \ / / _ \ '_ \| __/ __|/ __| '__| | '_ \| __/ __| + | | ____) |___) | __/\ V / __/ | | | |_\__ \ (__| | | | |_) | |_\__ \ + |_| |_____/|____/ \___| \_/ \___|_| |_|\__|___/\___|_| |_| .__/ \__|___/ + | | + |_| +What we wan't to do +We want to create a great eventscript system to manage multiple teamspeak3 instances as simple as possible. Everybody should be able to manage his voiceserver. + +It's a work in progress, what does work now? +Currently we have integrated the base system - you can connect to multiple teamspeak instances and add plugins to them. We don't have any useful plugins for now, but feel free to create and commit some! + +But where is the benefit? +Every instance has it's own thread - and every plugin, too. So you don't have any waiting time. + +There is no documentation :( +This script isn't finished yet. You will need to wait some more weeks until we get all things working. diff --git a/config.ini b/config.ini new file mode 100644 index 0000000..a4066ec --- /dev/null +++ b/config.ini @@ -0,0 +1,8 @@ +[instance1] +id = example_ts3 +ip = 127.0.0.1 +port = 10011 +sid = 1 +user = serveradmin +pass = 7SRRo7EE +name = Botty diff --git a/myexception.py b/myexception.py new file mode 100644 index 0000000..6ba0b92 --- /dev/null +++ b/myexception.py @@ -0,0 +1,2 @@ +class MyException(Exception): + pass diff --git a/plugins/example_ts3/test.py b/plugins/example_ts3/test.py new file mode 100644 index 0000000..cf78b3b --- /dev/null +++ b/plugins/example_ts3/test.py @@ -0,0 +1,29 @@ +from ts3tools import ts3tools +import time + +# plugin name (must be unique!) +name = 'test' +socket = None +app2 = None + +# pluginbase help: http://pluginbase.pocoo.org/ + +# setup - initial plugin load + + +def setup(app, ts3socket): + # set socket + global socket + global app2 + app2 = app + socket = ts3socket + # register plugin function as callback + app.register_callback(name, 'ts3.loop', test) + + +def test(values): + global app2 + time.sleep(5) + socket.send('sendtextmessage targetmode=2 target=1 msg=' + + ts3tools.escape_text('dies ist ein test')) + app2.execute_callback(name + '.test', {}) diff --git a/plugins/example_ts3/test2.py b/plugins/example_ts3/test2.py new file mode 100644 index 0000000..ac2778a --- /dev/null +++ b/plugins/example_ts3/test2.py @@ -0,0 +1,27 @@ +from ts3tools import ts3tools + +# plugin name (must be unique!) +name = 'test2' +socket = None +app2 = None + +# pluginbase help: http://pluginbase.pocoo.org/ + +# setup - initial plugin load + + +def setup(app, ts3socket): + # set socket + global socket + global app2 + app2 = app + socket = ts3socket + # register plugin function as callback + app.register_callback(name, 'ts3.loop', test) + + +def test(values): + global app2 + socket.send('sendtextmessage targetmode=2 target=1 msg=' + + ts3tools.escape_text('nope')) + app2.execute_callback(name + '.test', {}) diff --git a/plugins/test.py b/plugins/test.py new file mode 100644 index 0000000..5b52676 --- /dev/null +++ b/plugins/test.py @@ -0,0 +1,29 @@ +from ts3tools import ts3tools +import time + +# plugin name (must be unique!) +name = 'test' +socket = None +app2 = None + +# pluginbase help: http://pluginbase.pocoo.org/ + +# setup - initial plugin load + + +def setup(app, ts3socket): + # set socket + global socket + global app2 + app2 = app + socket = ts3socket + # register plugin function as callback + app.register_callback(name, 'ts3.loop', test) + + +def test(values): + # global app2 + # time.sleep(5) + # socket.send('sendtextmessage targetmode=2 target=1 msg=' + + # ts3tools.escape_text('dies ist ein test')) + # app2.execute_callback(name + '.test', {}) diff --git a/plugins/test2.py b/plugins/test2.py new file mode 100644 index 0000000..91e75f9 --- /dev/null +++ b/plugins/test2.py @@ -0,0 +1,27 @@ +from ts3tools import ts3tools + +# plugin name (must be unique!) +name = 'test2' +socket = None +app2 = None + +# pluginbase help: http://pluginbase.pocoo.org/ + +# setup - initial plugin load + + +def setup(app, ts3socket): + # set socket + global socket + global app2 + app2 = app + socket = ts3socket + # register plugin function as callback + app.register_callback(name, 'ts3.loop', test) + + +def test(values): + # global app2 + # socket.send('sendtextmessage targetmode=2 target=1 msg=' + + # ts3tools.escape_text('nope')) + # app2.execute_callback(name + '.test', {}) diff --git a/ts3base.py b/ts3base.py new file mode 100644 index 0000000..de25755 --- /dev/null +++ b/ts3base.py @@ -0,0 +1,91 @@ +import os +import threading +import time +from functools import partial +from collections import defaultdict +from pluginbase import PluginBase +from ts3socket import ts3socket +from ts3tools import ts3tools +from myexception import MyException +from threading import Thread + +# For easier usage calculate the path relative to here. +here = os.path.abspath(os.path.dirname(__file__)) +get_path = partial(os.path.join, here) + + +class ts3base(threading.Thread): + + def __init__(self, config): + # init threading + threading.Thread.__init__(self) + # set config for whole class + self.config = config + # debug message + self.debprint('instance initialized') + # init callbacks + self.callbacks = defaultdict(dict) + # identifier + package name for pluginbase + identifier = config['id'] + package = 'ts3eventscripts' + identifier + # init pluginbase + self.pluginbase = PluginBase( + package=package, searchpath=['./plugins/' + self.config['id']]) + # init pluginsource + self.pluginsource = self.pluginbase.make_plugin_source( + searchpath=[get_path('./plugins/' + self.config['id'])], identifier=identifier) + # init ts3 connection + self.ts3_init() + # init all plugins + self.plugin_init() + + def ts3_init(self): + # init ts3 query socket + self.ts3socket = ts3socket( + self.config['ip'], + self.config['port'], + self.config['sid'], + self.config['user'], + self.config['pass']) + # debug message + self.debprint('socket initialized') + + def plugin_init(self): + # debug message + self.debprint('loading plugins') + for plugin_name in self.pluginsource.list_plugins(): + plugin = self.pluginsource.load_plugin(plugin_name) + plugin.setup(self, self.ts3socket) + + def register_callback(self, plugin, key, function): + self.callbacks[key][plugin + '_' + function.__name__] = function + # debug message + self.debprint( + 'plugin ' + + plugin + + ' -> (func)' + + function.__name__ + + ' -> (callback)' + + key) + + def execute_callback(self, key, values): + if key in self.callbacks: + for index, func in self.callbacks[key].items(): + t = Thread(target=func, args=(values,)) + t.start() + + def debprint(self, msg): + print(self.config['id'] + ' - ' + msg) + + def run(self): + try: + # set nickname + ts3tools.set_nickname(self.ts3socket, self.config['name']) + while 1: + # loop callback + self.execute_callback('ts3.loop', {}) + # sleep a half second + time.sleep(0.5) + except MyException as e: + print(str(e)) + exit() diff --git a/ts3eventscripts.py b/ts3eventscripts.py new file mode 100755 index 0000000..f57ceb8 --- /dev/null +++ b/ts3eventscripts.py @@ -0,0 +1,30 @@ +#!/usr/bin/env python3 +import time +import configparser +from ts3base import ts3base +from myexception import MyException + +config = configparser.ConfigParser() +config.read('config.ini') + +for key in config: + if key.startswith('instance'): + ts3 = ts3base({'id': config[key]['id'], + 'ip': config[key]['ip'], + 'port': int(config[key]['port']), + 'sid': int(config[key]['sid']), + 'user': config[key]['user'], + 'pass': config[key]['pass'], + 'name': config[key]['name'], }) + ts3.start() + +try: + while 1: + # endless loop + time.sleep(1) +except KeyboardInterrupt as e: + print('exit...') + exit() +except MyException as e: + print(str(e)) + exit() diff --git a/ts3socket.py b/ts3socket.py new file mode 100644 index 0000000..4c1a602 --- /dev/null +++ b/ts3socket.py @@ -0,0 +1,41 @@ +import socket +from myexception import MyException + +# Buffer size +BUFFER_SIZE = 1024 + + +class ts3socket: + + def __init__(self, ip, port, sid, user, password): + self.ip = ip + self.port = port + self.sid = sid + self.user = user + self.password = password + self.connect() + + def connect(self): + self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + self.sock.connect((self.ip, self.port)) + try: + if self.receive().startswith('TS3'): + self.send('use %s\n\r' % (self.sid, )) + if not self.receive().endswith('msg=ok\n\r'): + raise MyException("ServerID not found") + self.send('login ' + self.user + ' ' + self.password) + if not self.receive().endswith('msg=ok\n\r'): + raise MyException("username/password wrong") + else: + raise MyException("this isn't a TS3-Server, right?") + except (socket.error, socket.timeout): + self.disconnect() + + def send(self, msg): + return self.sock.send((msg + '\n').encode()) + + def disconnect(self): + self.sock.close() + + def receive(self): + return self.sock.recv(BUFFER_SIZE).decode() diff --git a/ts3tools.py b/ts3tools.py new file mode 100644 index 0000000..5047673 --- /dev/null +++ b/ts3tools.py @@ -0,0 +1,17 @@ +# static definitions +escapeText = [ + (' ', '\s'), + ('|', '\p'), + ('/', '\/')] + + +class ts3tools: + + def escape_text(msg): + for search, replace in escapeText: + msg = msg.replace(search, replace) + return msg + + def set_nickname(socket, nickname): + return socket.send( + 'clientupdate client_nickname=' + ts3tools.escape_text(nickname))