From 9080c719dc0252b43fd894d71cf7d410ae8b0cb6 Mon Sep 17 00:00:00 2001 From: nico Date: Sat, 7 Dec 2019 13:09:41 +0100 Subject: TeamSpeak datebased GroupAssigner cleaned up working release + properly register for servernotify events + process only voice_clients + properly check if client is already a group member + logging --- .gitignore | 138 +++++++++++++++++++++++++++++++++++++++++++++++++++++ config.json.sample | 9 ++++ config.py | 17 +++++++ main.py | 72 ++++++++++++++++++++++++++++ requirements.txt | 1 + 5 files changed, 237 insertions(+) create mode 100644 .gitignore create mode 100644 config.json.sample create mode 100644 config.py create mode 100644 main.py create mode 100644 requirements.txt diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..821dc45 --- /dev/null +++ b/.gitignore @@ -0,0 +1,138 @@ +# Created by .ignore support plugin (hsz.mobi) +### Python template +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +pip-wheel-metadata/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +.python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pycharm +.idea + +# project specific +config.json +*.log diff --git a/config.json.sample b/config.json.sample new file mode 100644 index 0000000..2f2eedf --- /dev/null +++ b/config.json.sample @@ -0,0 +1,9 @@ +{ + "host": "localhost", + "port": 10011, + "user": "serveradmin", + "password": "super_secret-Password", + "server_id": 1337, + + "gid" : 9999 +} \ No newline at end of file diff --git a/config.py b/config.py new file mode 100644 index 0000000..d0dc061 --- /dev/null +++ b/config.py @@ -0,0 +1,17 @@ +# -*- coding: utf-8 -*- +import json + +with open("config.json", "r", encoding="utf-8") as file: + config = json.load(file) + + +class Config(object): + # connection arguments + HOST = config['host'] + PORT = config['port'] + USER = config['user'] + PW = config['password'] + SID = config['server_id'] + + # assignment settings + GID = config['gid'] diff --git a/main.py b/main.py new file mode 100644 index 0000000..532e4af --- /dev/null +++ b/main.py @@ -0,0 +1,72 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +import logging + +import ts3 + +from config import Config + + +def watcher(conn): + # Register for events + # https://yat.qa/ressourcen/server-query-notify/#server + conn.servernotifyregister(event="server") + + while True: + conn.send_keepalive() + + try: + event = conn.wait_for_event(timeout=60) + + except ts3.query.TS3TimeoutError: + pass + + else: + # only parse entering clients info + if event.event == "notifycliententerview": + + # skip query clients -- query client = 1 , voice client = 0 + if event[0]['client_type'] == '0': + + # reasonid should be 0 not sure though + if event[0]["reasonid"] == "0": + + user_grps = event.parsed[0]['client_servergroups'].split(sep=',') + gid = Config.GID + + # only try to add nonmembers to group + if str(gid) not in user_grps: + + cldbid = event.parsed[0]['client_database_id'] + + # https://yat.qa/ressourcen/server-query-kommentare/ + # Usage: servergroupaddclient sgid={groupID} cldbid={clientDBID} + try: + cmd = conn.servergroupaddclient(sgid=gid, cldbid=cldbid) + + if cmd.error['id'] != '0': + logger.info(cmd.data[0].decode("utf-8")) + + # log process + logmsg = '{client_nickname}:{client_database_id} - added to {gid}' + logging.info(logmsg.format(**event[0], gid=gid)) + + except KeyError: + logger.error(str(event.parsed)) + pass + + +if __name__ == "__main__": + # logging + logger = logging.getLogger() + logger.setLevel(logging.INFO) + + logf = logging.FileHandler('info.log') + logf.setFormatter(logging.Formatter("%(asctime)s - %(levelname)-8s - %(message)s")) + + logger.addHandler(logf) + + with ts3.query.TS3Connection(Config.HOST, Config.PORT) as ts3conn: + ts3conn.login(client_login_name=Config.USER, client_login_password=Config.PW) + ts3conn.use(sid=Config.SID) + watcher(ts3conn) diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..ae7b420 --- /dev/null +++ b/requirements.txt @@ -0,0 +1 @@ +ts3>=1.0.11 -- cgit v1.2.3-18-g5258