Ejemplo n.º 1
0
class pleasureBot:
	def __init__(self):
#		self.bot
#		self.con
#		self.roomid
#		self.adminid
#		self.userid
		dbName = None
		auth   = None
	
		self.bot = Bot('auth+live+583320f7e5a458eb161c2a88930556307fd544e7', '4f316824a3f75176aa014dfc', '4f94d6d1eb35c17511000418')
		self.bot.on('speak', self.checkIt)
		self.bot.start()

	def checkIt(self, data):
		print "--checkit--", data['text']
		
		if data['text'] == 'snag' :
			methodToCall = getattr(self.bot, data['text'])
		else:
			methodToCall = getattr(self, data['text'])
		result = methodToCall()
		print "-checkit result-", result

	def doit(self):
		print "----doit---"
		return "doit"


	def doitagain(self):
		print "---do it again----"
		return "doitagain"

	print "--init-- "
Ejemplo n.º 2
0
   def __init__(self, config):
      self.config = config

      self._current_users = []
      self._dj_queue = []
      self._djs = []
      self._mods = []

      self._waitingDj = False
      self._waiting_down = False
      self._waiting_user = None

      self._bot = Bot(self.config.authInfo.auth, self.config.authInfo.userid, self.config.authInfo.roomid)

      self._bot.on('speak', self._speak)
      self._bot.on('registered', self._user_in)
      self._bot.on('deregistered', self._user_out)
      self._bot.on('add_dj', self._dj_added)
      self._bot.on('rem_dj', self._dj_removed)
      self._bot.on('roomChanged', self._room_changed)
      self._bot.on('endsong', self._end_song)

      #This prefix can be used by anyone in the room, and it specifies local utility commands for bot management
      #under certain circumstances
      self.LOCAL_COMMAND_PREFIX = ":%:"
Ejemplo n.º 3
0
    def __init__(self, config_section, plugin_dir, enable_logging):
        if not self.update_checked:
            update_check(__name__, __version__)
            self.update_checked = True

        self.start_time = datetime.utcnow()

        if plugin_dir:
            if os.path.isdir(plugin_dir):
                sys.path.append(plugin_dir)
            else:
                print ("`{0}` is not a directory.".format(plugin_dir))

        config = self._get_config(config_section)
        self._delayed_events = []
        self._loaded_plugins = {}
        self.api = Bot(config["auth_id"], config["user_id"], rate_limit=0.575)
        self.api.debug = enable_logging
        self.api.on("add_dj", self.handle_add_dj)
        self.api.on("booted_user", self.handle_booted_user)
        self.api.on("deregistered", self.handle_user_leave)
        self.api.on("new_moderator", self.handle_add_moderator)
        self.api.on("post_message", self.run_delayed_events)
        self.api.on("pmmed", self.handle_pm)
        self.api.on("ready", self.handle_ready)
        self.api.on("registered", self.handle_user_join)
        self.api.on("rem_dj", self.handle_remove_dj)
        self.api.on("rem_moderator", self.handle_remove_moderator)
        self.api.on("roomChanged", self.handle_room_change)
        self.api.on("speak", self.handle_room_message)
        self.bot_id = config["user_id"]
        self.commands = {
            "/about": self.cmd_about,
            "/commands": self.cmd_commands,
            "/help": self.cmd_help,
            "/join": self.cmd_join,
            "/leave": self.cmd_leave,
            "/pgload": self.cmd_plugin_load,
            "/pgreload": self.cmd_plugin_reload,
            "/pgunload": self.cmd_plugin_unload,
            "/plugins": self.cmd_plugins,
            "/uptime": self.cmd_uptime,
        }
        self.config = config
        self.dj_ids = set()
        self.listener_ids = set()
        self.max_djs = None
        self.moderator_ids = set()
        self.username = None

        # Load plugins after everything has been initialized
        for plugin in config["plugins"].split("\n"):
            self.load_plugin(plugin)

        self.api.connect(config["room_id"])
        self.api.ws.on_error = handle_error
Ejemplo n.º 4
0
    def __init__(self, config_section, plugin_dir, enable_logging):
        if not self.update_checked:
            update_check(__name__, __version__)
            self.update_checked = True

        self.start_time = datetime.utcnow()

        if plugin_dir:
            if os.path.isdir(plugin_dir):
                sys.path.append(plugin_dir)
            else:
                print('`{0}` is not a directory.'.format(plugin_dir))

        config = self._get_config(config_section)
        self._delayed_events = []
        self._loaded_plugins = {}
        self.api = Bot(config['auth_id'], config['user_id'], rate_limit=0.575)
        self.api.debug = enable_logging
        self.api.on('add_dj', self.handle_add_dj)
        self.api.on('booted_user', self.handle_booted_user)
        self.api.on('deregistered', self.handle_user_leave)
        self.api.on('new_moderator', self.handle_add_moderator)
        self.api.on('post_message', self.run_delayed_events)
        self.api.on('pmmed', self.handle_pm)
        self.api.on('ready', self.handle_ready)
        self.api.on('registered', self.handle_user_join)
        self.api.on('rem_dj', self.handle_remove_dj)
        self.api.on('rem_moderator', self.handle_remove_moderator)
        self.api.on('roomChanged', self.handle_room_change)
        self.api.on('speak', self.handle_room_message)
        self.bot_id = config['user_id']
        self.commands = {'/about': self.cmd_about,
                         '/commands': self.cmd_commands,
                         '/help': self.cmd_help,
                         '/join': self.cmd_join,
                         '/leave': self.cmd_leave,
                         '/pgload': self.cmd_plugin_load,
                         '/pgreload': self.cmd_plugin_reload,
                         '/pgunload': self.cmd_plugin_unload,
                         '/plugins': self.cmd_plugins,
                         '/uptime': self.cmd_uptime}
        self.config = config
        self.dj_ids = set()
        self.listener_ids = set()
        self.max_djs = None
        self.moderator_ids = set()
        self.username = None

        # Load plugins after everything has been initialized
        for plugin in config['plugins'].split('\n'):
            self.load_plugin(plugin)

        self.api.connect(config['room_id'])
        self.api.ws.on_error = handle_error
Ejemplo n.º 5
0
	def __init__(self):
#		self.bot
#		self.con
#		self.roomid
#		self.adminid
#		self.userid
		dbName = None
		auth   = None
	
		self.bot = Bot('auth+live+583320f7e5a458eb161c2a88930556307fd544e7', '4f316824a3f75176aa014dfc', '4f94d6d1eb35c17511000418')
		self.bot.on('speak', self.checkIt)
		self.bot.start()
Ejemplo n.º 6
0
Archivo: vitrola.py Proyecto: rflc/bots
from ttapi import Bot
import re
import threading
import random

AUTH   = 'pKTXOWwgzqIbuneEGAvGdyEr'
USERID = '5137e601aaa5cd6a937bec38'
#ROOMID = '5121d8f8aaa5cd20218d1da8'
ROOMID = '5105bbc1aaa5cd73a44088ac' #Electronic Indie Mix

autobopStat = True

bot = Bot(AUTH, USERID, ROOMID)

def songInfo(data):
    #  desc = data['description']
    # awsm = data['upvotes']
    # lm   = data['downvotes']
    # mod  = data['moderator_id']
    # djs  = data['djs']
    # dj   = data['djname']
    # meta = data['metadata']
    global sid
    sid = data['room']['metadata']['current_song']['_id']

bot.on('newsong', songInfo)

def commands(data):
    global sid
    global autobopStat
    global autobopText
Ejemplo n.º 7
0
from sys import exit
import json
import re
import sqlite3 as sql

# There should be a file in the same directory as the bot
# that is named myConfig.py. This file shold contain some
# variables that we need to connect to tt.fm
# For example:
# myUserID      = 'XXXXXX'
# myAuthKet     = 'XXXXXX'
# defaultRoom   = 'XXXXXX'
# ownerID       = 'XXXXXX'
# dbFile        = '<BotName>.sqlite'

bot = Bot(myAuthKey, myUserID, defaultRoom)


# Define callbacks
def roomChanged(data):
    global theUsersList
    global theBopList
    global curSongID
    global curDjID
    global theOpList
    global maxDjCount
    global roomDJs
    global roomOwner
    roomInfo = data['room']
    roomMeta = roomInfo['metadata']
    curDjID = roomMeta['current_dj']
Ejemplo n.º 8
0
from ttapi import Bot

AUTH = 'HDuKXnXcExdxcpjGuVVOuSEJ'
USERID = '511479b5eb35c11c9a3b65e1'
ROOMID = '5114792feb35c11c9a3b65e0'

bot = Bot(AUTH, USERID, ROOMID)


def speak(data):
    name = data['name']
    text = data['text']
    if text == '/hello':
        bot.speak('Hey! How are you %s ?' % name)


bot.on('speak', speak)

bot.start()
Ejemplo n.º 9
0
from ttapi import Bot
import re

AUTH   = 'auth+live+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
USERID = 'xxxxxxxxxxxxxxxxxxxxxxxx'
ROOMID = 'xxxxxxxxxxxxxxxxxxxxxxxx'
bot = Bot(AUTH, USERID, ROOMID)


def speak(data):
   name = data['name']
   text = data['text']

   if re.match('/hello', text):
      bot.speak('Hey! How are you %s ?' % name)


bot.on('speak', speak)

bot.start()
Ejemplo n.º 10
0
# -*- coding: iso-8859-15 -*-

import twitter
import re
import settings # this is a relative import. Not sure it works in all versions of python, but seems okay in 2.7.x
from ttapi import Bot
from random import choice, shuffle

ADDRESSING_REQUIRED = True
ADDRESSING_PATTERNS = (
	r'@?%s[,:;]?\s+(.*)' % settings.TURNTABLE['name'].lower(),
	r'(.*),?\s+@?%s[\.!\?]?' % settings.TURNTABLE['name'].lower(),
)

# Initialize Turntable bot
tt_bot = Bot(settings.TURNTABLE['auth'], settings.TURNTABLE['user'], settings.TURNTABLE['room'])

# Connect to Twitter account, if settings are in place
if hasattr(settings, 'TWITTER'):
	tw_bot = twitter.Api(**settings.TWITTER)

# These globals serve as a short term database.
RECENT_SONGS = []
BOPPING = False

# Utility function

def add_current_song(data):
	"This function adds the current song to queue. Expects to receive data from tt_bot.roomInfo()"
	current_song = data['room']['metadata']['songlog'][-1]
	tt_bot.playlistAdd(current_song['_id'], 999999) # add to bottom of queue
Ejemplo n.º 11
0
Archivo: visions.py Proyecto: rflc/bots
# -*- coding: utf-8 -*-
from urllib import urlopen
from ttapi import Bot
import cleverbot
import re
import threading
import random
from random import choice
import time

AUTH   = 'ILmomQAOCHRceIlEBwAENLij'
USERID = '512034b3aaa5cd20218d181f'
#ROOMID = '5121d8f8aaa5cd20218d1da8' #Private
ROOMID = '5105bbc1aaa5cd73a44088ac' #Electronic Indie Mix

bot = Bot(AUTH, USERID, ROOMID)

autobopStat = True
cb          = cleverbot.Session()
songStat    = True
outOfGenre  = False
stage       = {}
dj          = {'name':'','id':''}
mods = []
brobot = True
queue = {}

#    global midTempo
#    lstnrs = data['listenerids']
#    for x in lstnrs:
#        if re.match('50f097bdaaa5cd4d3ca6c999', x):
Ejemplo n.º 12
0
Archivo: boss.py Proyecto: rflc/qt
from ttapi import Bot
import re
import threading
import random

AUTH = 'AbpmQKoDwRAmxRiAyKVDCkZQ'
USERID = '513b8ca8aaa5cd76af092576'
ROOMID = '5105bbc1aaa5cd73a44088ac'  #Electronic Indie Mix
#ROOMID = '4f1e02590c4cc807574030f1' #treehouse
#ROOMID = '4e1f8b6614169c5fba0005a0'

autobopStat = True

bot = Bot(AUTH, USERID, ROOMID)

greet = [
    'You are such a rockstar', 'ILYSM', 'Been waiting FOREVER for you',
    'Long time no see'
]

qtfact = [
    'It\'s not QT sharing hour.', 'Wait until QT Sharing Hour.',
    'You secretly wanna be her.', 'She is omniscient',
    'QT lurves geeks (but not nerds)', 'QT is your hero!', 'We all lurve QT!',
    'Shower QT with some luvin\'!', 'QT IS the original cutiepie',
    'QT LOVES CUPCAKES! :cake:', 'QT ROCKS! :beers: on me!',
    'QT needs some luvin\'', '/me pokes Q-T-3.14[etc.]',
    'QT has more talking stuffed animals than you.', 'QT plays with toys.',
    'QT is easily amused', 'QT\'s middle name is actually \'Sugar\'',
    'QT daydreams in the shower.', 'QT has a 2-pak stomach',
    'QT plays Super Mario', 'QT loves to dance to the 80\'s',
Ejemplo n.º 13
0
from ttapi import Bot

AUTH   = 'auth+live+xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
USERID = 'xxxxxxxxxxxxxxxxxxxxxxxx'
ROOMID = 'xxxxxxxxxxxxxxxxxxxxxxxx'
bot = Bot(AUTH, USERID, ROOMID)

theUsersList = { }

def roomChanged(data):
   global theUsersList
   # Reset the users list
   theUsersList = {}
   users = data['users']
   for user in users:
      theUsersList[user['userid']] = user


def registered(data):
   global theUsersList
   user = data['user'][0]
   theUsersList[user['userid']] = user


def deregistered(data):
   global theUsersList
   user = data['user'][0]
   del theUsersList[user['userid']]


bot.on('roomChanged',  roomChanged)
Ejemplo n.º 14
0
from sys import exit
import json
import re
import sqlite3 as sql

# There should be a file in the same directory as the bot
# that is named myConfig.py. This file shold contain some
# variables that we need to connect to tt.fm
# For example:
# myUserID      = 'XXXXXX'
# myAuthKet     = 'XXXXXX'
# defaultRoom   = 'XXXXXX'
# ownerID       = 'XXXXXX'
# dbFile        = '<BotName>.sqlite'

bot = Bot(myAuthKey, myUserID, defaultRoom)

# Define callbacks
def roomChanged(data):
    global theUsersList
    global theBopList
    global curSongID
    global curDjID
    global theOpList
    global maxDjCount
    global roomDJs
    global roomOwner
    roomInfo = data["room"]
    roomMeta = roomInfo["metadata"]
    curDjID = roomMeta["current_dj"]
    songLog = roomMeta["songlog"]
Ejemplo n.º 15
0
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
"""
from ttapi import Bot
from re import match

AUTH = 'XXXXXXXXXXXXXXXXXXXXXXXX'
USERID = 'XXXXXXXXXXXXXXXXXXXXXXXX'
ROOMID = 'XXXXXXXXXXXXXXXXXXXXXXXX'

bot = Bot(AUTH, USERID, ROOMID)
djs = {}

# Callbacks
def onSpeak(data):
	name = data['name']
	text = data['text']
	
	if text == '/join':
		bot.addDj()
	elif text == '/leave':
		bot.remDj()
	elif text == '/rejoin':
		bot.remDj()
		bot.addDj()
	elif text == '/skip':
Ejemplo n.º 16
0
#
# Each time a song starts, the bot vote up.
# WARNING: Turntable no longer allows bots that autobop. This script is provided for educational purposes only.
# For more information, visit http://faq.turntable.fm/customer/portal/articles/258935
#

from ttapi import Bot

AUTH   = 'auth+live+2cdbb9bd018b4d3af371b29471ce903b9413083a'
USERID = '4fc90519eb35c1533d000006'
ROOMID = '4e3c380114169c4fda19da3b'
bot = Bot(AUTH, USERID, ROOMID)

def autobop(data): bot.bop()

bot.on('newsong', autobop)

bot.start()
Ejemplo n.º 17
0
import threading
import pickle

eebot_auth = 'auth+live+xxxxxx'
eebot_userid = '4fdcd2f9aaa5cd1e7900032d'

lsk_userid = '4e7c70bc4fe7d052ef034402'

ee_roomid = '4fae71e0aaa5cd57e50011e1'
speakeasy_id = '4e8a63d614169c39fb79b09a'

AUTH   = eebot_auth
USERID = eebot_userid
ROOM   = ee_roomid

eebot = Bot(AUTH,USERID,ROOM)
banlistDir = 'Hidden'
bl = open(banlistDir,'r')
banlist = pickle.load(bl)
bl.close()
print 'Banlist: %s' % str(banlist)
songban = ['6e6967676572'.decode('hex')]
songId  = ''
DJid = ''
addedSong = False
waitForSong = False
currUserIds = []
currDjs = []
djOnCmd = False
botPl = []
songData = {}
Ejemplo n.º 18
0
class LazySusan(object):
    update_checked = False

    @staticmethod
    def _get_config(section):
        config = ConfigParser()
        if "APPDATA" in os.environ:  # Windows
            os_config_path = os.environ["APPDATA"]
        elif "XDG_CONFIG_HOME" in os.environ:  # Modern Linux
            os_config_path = os.environ["XDG_CONFIG_HOME"]
        elif "HOME" in os.environ:  # Legacy Linux
            os_config_path = os.path.join(os.environ["HOME"], ".config")
        else:
            os_config_path = None
        locations = ["lazysusan.ini"]
        if os_config_path is not None:
            locations.insert(0, os.path.join(os_config_path, "lazysusan.ini"))
        if not config.read(locations):
            raise LazySusanException("No lazysusan.ini found.")
        if not config.has_section(section) and section != "DEFAULT":
            raise LazySusanException("No section `{0}` found in lazysusan.ini.".format(section))
        return dict(config.items(section))

    def __init__(self, config_section, plugin_dir, enable_logging):
        if not self.update_checked:
            update_check(__name__, __version__)
            self.update_checked = True

        self.start_time = datetime.utcnow()

        if plugin_dir:
            if os.path.isdir(plugin_dir):
                sys.path.append(plugin_dir)
            else:
                print ("`{0}` is not a directory.".format(plugin_dir))

        config = self._get_config(config_section)
        self._delayed_events = []
        self._loaded_plugins = {}
        self.api = Bot(config["auth_id"], config["user_id"], rate_limit=0.575)
        self.api.debug = enable_logging
        self.api.on("add_dj", self.handle_add_dj)
        self.api.on("booted_user", self.handle_booted_user)
        self.api.on("deregistered", self.handle_user_leave)
        self.api.on("new_moderator", self.handle_add_moderator)
        self.api.on("post_message", self.run_delayed_events)
        self.api.on("pmmed", self.handle_pm)
        self.api.on("ready", self.handle_ready)
        self.api.on("registered", self.handle_user_join)
        self.api.on("rem_dj", self.handle_remove_dj)
        self.api.on("rem_moderator", self.handle_remove_moderator)
        self.api.on("roomChanged", self.handle_room_change)
        self.api.on("speak", self.handle_room_message)
        self.bot_id = config["user_id"]
        self.commands = {
            "/about": self.cmd_about,
            "/commands": self.cmd_commands,
            "/help": self.cmd_help,
            "/join": self.cmd_join,
            "/leave": self.cmd_leave,
            "/pgload": self.cmd_plugin_load,
            "/pgreload": self.cmd_plugin_reload,
            "/pgunload": self.cmd_plugin_unload,
            "/plugins": self.cmd_plugins,
            "/uptime": self.cmd_uptime,
        }
        self.config = config
        self.dj_ids = set()
        self.listener_ids = set()
        self.max_djs = None
        self.moderator_ids = set()
        self.username = None

        # Load plugins after everything has been initialized
        for plugin in config["plugins"].split("\n"):
            self.load_plugin(plugin)

        self.api.connect(config["room_id"])
        self.api.ws.on_error = handle_error

    def _load_command_plugin(self, plugin):
        to_add = {}
        for command, func_name in plugin.COMMANDS.items():
            if command in self.commands:
                other = self.commands[command]
                if isinstance(other.im_self, CommandPlugin):
                    print (
                        "`{0}` conflicts with `{1}` for command `{2}`.".format(plugin.NAME, other.im_self.NAME, command)
                    )
                else:
                    print ("`{0}` cannot use the reserved command `{1}`.".format(plugin.NAME, command))
                print ("Not loading plugin `{0}`.".format(plugin.NAME))
                return False
            to_add[command] = getattr(plugin, func_name)
        self.commands.update(to_add)
        return True

    def _unload_command_plugin(self, plugin):
        for command in plugin.COMMANDS:
            del self.commands[command]

    @no_arg_command
    def cmd_about(self, data):
        """Display information about this bot."""
        reply = "I am powered by LazySusan version {0}. " "https://github.com/bboe/LazySusan".format(__version__)
        self.reply(reply, data)

    @no_arg_command
    def cmd_commands(self, data):
        """List the available commands."""

        admin_cmds = []
        admin_or_moderator_cmds = []
        moderator_cmds = []
        no_priv_cmds = []

        for command, func in self.commands.items():
            if func.func_dict.get("admin_required"):
                admin_cmds.append(command)
            elif func.func_dict.get("admin_or_moderator_required"):
                admin_or_moderator_cmds.append(command)
            elif func.func_dict.get("moderator_required"):
                moderator_cmds.append(command)
            else:
                no_priv_cmds.append(command)
        reply = "Available commands: "
        reply += ", ".join(sorted(no_priv_cmds))
        self.reply(reply, data)

        user_id = get_sender_id(data)
        if moderator_cmds and self.is_moderator(user_id):
            reply = "Moderator commands: "
            reply += ", ".join(sorted(moderator_cmds))
            self.api.pm(reply, user_id)
        if admin_or_moderator_cmds and (self.is_moderator(user_id) or self.is_admin(user_id)):
            reply = "Priviliged commands: "
            reply += ", ".join(sorted(admin_or_moderator_cmds))
            self.api.pm(reply, user_id)
        if admin_cmds and self.is_admin(user_id):
            reply = "Admin commands: "
            reply += ", ".join(sorted(admin_cmds))
            self.api.pm(reply, user_id)

    def _connect(self, room_id, when_connected=True):
        if self.api.roomId == room_id or (self.api.roomId and not when_connected):
            return
        print ("Joining {0}".format(room_id))
        self.api.roomRegister(room_id)

    def cmd_help(self, message, data):
        """With no arguments, display this message. Otherwise, display the help
        for the given command. Type /commands to see the list of commands."""

        def docstr(item):
            lines = []
            for line in item.__doc__.split("\n"):
                line = line.strip()
                if line:
                    lines.append(line)
            return " ".join(lines)

        if not message:
            reply = docstr(self.cmd_help)
        elif " " not in message:
            if message in self.commands:
                tmp = self.commands[message].func_dict
                if (
                    tmp.get("admin_required")
                    and not self.is_admin(data)
                    or tmp.get("moderator_required")
                    and not self.is_moderator(data)
                ):
                    return
                reply = docstr(self.commands[message])
            else:
                reply = "`{0}` is not a valid command.".format(message)
        else:
            return
        self.reply(reply, data)

    @admin_required
    def cmd_join(self, message, data):
        """Join the room by room_id.

        With no arguments, join the room specified in lazysusan.ini."""
        if " " in message:
            return
        room_id = message if message else self.config["room_id"]
        if room_id == self.api.roomId:
            self.reply("I am already in that room.", data)
        else:
            self._connect(room_id)

    @admin_required
    @no_arg_command
    def cmd_leave(self, data):
        """Leave the current room and remain connected to the chat server."""

        def callback(cb_data):
            user_id = get_sender_id(data)
            if cb_data["success"]:
                # Schedule an event to possibly rejoin after 1 minute
                self.schedule(60, self._connect, self.config["room_id"], False)
                self.api.pm(
                    "I have left the room. If I remain roomless after " "~1 minute, I will rejoin the default room.",
                    user_id,
                )
            else:
                self.api.pm("Leaving the room failed.", user_id)

        print ("Leaving {0}".format(self.api.roomId))
        self.api.roomDeregister(callback)

    @admin_required
    @single_arg_command
    def cmd_plugin_load(self, message, data):
        """Load the specified plugin."""
        if message in self._loaded_plugins:
            reply = "Plugin `{0}` is already loaded.".format(message)
        elif self.load_plugin(message, attempt_reload=True):
            reply = "Plugin `{0}` loaded.".format(message)
        else:
            reply = "Plugin `{0}` could not be loaded.".format(message)
        self.reply(reply, data)

    @admin_required
    @single_arg_command
    def cmd_plugin_reload(self, message, data):
        """Reoad the specified plugin."""
        if message not in self._loaded_plugins:
            reply = "Plugin `{0}` is not loaded.".format(message)
        elif not (self.unload_plugin(message) and self.load_plugin(message, attempt_reload=True)):
            reply = "Plugin `{0}` could not be reloaded.".format(message)
        else:
            reply = "Plugin `{0}` reloaded.".format(message)
        self.reply(reply, data)

    @admin_required
    @single_arg_command
    def cmd_plugin_unload(self, message, data):
        """Unload the specified plugin."""
        if message not in self._loaded_plugins:
            reply = "Plugin `{0}` is not loaded.".format(message)
        elif self.unload_plugin(message):
            reply = "Plugin `{0}` unloaded.".format(message)
        else:
            reply = "Plugin `{0}` could not be unloaded.".format(message)
        self.reply(reply, data)

    @admin_required
    @no_arg_command
    def cmd_plugins(self, data):
        """Display the list of loaded plugins."""
        reply = "Loaded plugins: "
        reply += ", ".join(sorted(self._loaded_plugins.keys()))
        self.reply(reply, data)

    @no_arg_command
    def cmd_uptime(self, data):
        """Display how long since LazySusan was started."""
        msg = "LazySusan was started {0}".format(pretty_date(self.start_time))
        self.reply(msg, data)

    def is_admin(self, item):
        """item can be either the user_id, or a dictionary from a message."""
        if isinstance(item, dict):
            item = get_sender_id(item)
        return item in self.config["admin_ids"]

    def is_moderator(self, item):
        """item can be either the user_id, or a dictionary from a message."""
        if isinstance(item, dict):
            item = get_sender_id(item)
        return item in self.moderator_ids

    def handle_add_dj(self, data):
        for user in data["user"]:
            self.dj_ids.add(user["userid"])

    def handle_booted_user(self, data):
        if data["userid"] == self.bot_id:
            # Try to rejoin the default room after 30 seconds.
            self.api.roomId = None
            self.schedule(30, self._connect, self.config["room_id"], False)

    def handle_add_moderator(self, data):
        self.moderator_ids.add(data["userid"])

    def handle_pm(self, data):
        self.process_message(data)

    def handle_ready(self, _):
        self.api.userInfo(self.set_username)

    @display_exceptions
    def handle_remove_dj(self, data):
        for user in data["user"]:
            self.dj_ids.remove(user["userid"])

    @display_exceptions
    def handle_remove_moderator(self, data):
        self.moderator_ids.remove(data["userid"])

    def handle_room_change(self, data):
        if not data["success"]:
            if data["errno"] == 3:
                print ("You are banned from that room. Retrying in 3 minutes.")
                self.schedule(180, self._connect, self.config["room_id"], False)
                return
            print ("Error changing rooms.")
            # Try to rejoin the default room
            self.api.roomId = None
            self._connect(self.config["room_id"])
            return
        self.dj_ids = set(data["room"]["metadata"]["djs"])
        self.listener_ids = set(x["userid"] for x in data["users"])
        self.max_djs = data["room"]["metadata"]["max_djs"]
        self.moderator_ids = set(data["room"]["metadata"]["moderator_id"])

    @display_exceptions
    def handle_room_message(self, data):
        if self.username and self.username != data["name"]:
            self.process_message(data)

    def handle_user_join(self, data):
        for user in data["user"]:
            self.listener_ids.add(user["userid"])

    @display_exceptions
    def handle_user_leave(self, data):
        for user in data["user"]:
            self.listener_ids.remove(user["userid"])

    def load_plugin(self, plugin_name, attempt_reload=False):
        parts = plugin_name.split(".")
        if len(parts) > 1:
            module_name = ".".join(parts[:-1])
            class_name = parts[-1]
        else:
            # Use the titlecase format of the module name as the class name
            module_name = parts[0]
            class_name = parts[0].title()

        # First try to load plugins from the passed in plugins_dir and then
        # from the lazysusan.plugins package.
        module = None
        for package in (None, "lazysusan.plugins"):
            if package:
                module_name = "{0}.{1}".format(package, module_name)

            if attempt_reload and module_name in sys.modules:
                module = reload(sys.modules[module_name])
            else:
                try:
                    module = __import__(module_name, fromlist=[class_name])
                except ImportError:
                    pass
            if module:
                break
        if not module:
            print ("Cannot find plugin `{0}`.".format(plugin_name))
            return False
        try:
            plugin = getattr(module, class_name)(self)
        except AttributeError:
            print ("Cannot find plugin `{0}`.".format(plugin_name))
            return False

        plugin.__class__.NAME = plugin_name
        if isinstance(plugin, CommandPlugin):
            if not self._load_command_plugin(plugin):
                return
        self._loaded_plugins[plugin_name] = plugin
        print ("Loaded plugin `{0}`.".format(plugin_name))
        return True

    def process_message(self, data):
        parts = data["text"].split()
        if not parts:
            return
        command = parts[0]
        if len(parts) == 1:
            message = ""
        else:
            message = " ".join(parts[1:])  # Normalize with single spaces
        handler = self.commands.get(command)
        if not handler:
            return
        handler(message, data)

    def reply(self, message, data):
        if data["command"] == "speak":
            self.api.speak(message)
        elif data["command"] == "pmmed":
            self.api.pm(message, data["senderid"])
        else:
            raise Exception("Unrecognized command type `{0}`".format(data["command"]))

    def run_delayed_events(self, _):
        now = time.time()
        process = True
        while process and self._delayed_events:
            item = self._delayed_events[0]  # Peek at the top
            if item[0] < now:
                heapq.heappop(self._delayed_events)  # Actually remove
                item[1](*item[2], **item[3])
            else:
                process = False

    def schedule(self, min_delay, callback, *args, **kwargs):
        """Schedule an event to occur at least min_delay seconds in the future.

        The passed in callback function will be called with all remaining
        arguments.

        Scheduled events are checked and processed after every received message
        from turntable. In an inactive room the longest duration between
        received messages is 12 seconds."""
        schedule_time = time.time() + min_delay
        heapq.heappush(self._delayed_events, (schedule_time, callback, args, kwargs))

    def set_username(self, data):
        self.username = data["name"]

    def start(self):
        self.api.start()

    def unload_plugin(self, plugin_name):
        if plugin_name not in self._loaded_plugins:
            return False
        plugin = self._loaded_plugins[plugin_name]
        if isinstance(plugin, CommandPlugin):
            self._unload_command_plugin(plugin)
        del self._loaded_plugins[plugin_name]
        del plugin
        print ("Unloaded plugin `{0}`.".format(plugin_name))
        return True
Ejemplo n.º 19
0
from datetime import datetime as dt
from collections import deque
import random
from ttapi import Bot
#from settings import DBHOST,DBUSER,DBPASS

def init():
	global bot
	global con
	global roomid
	global adminid
	global userid
	dbName = None
	auth   = None
	
bot = Bot('auth+live+3ff1fdf4426da214708693e7fb9bd151ac7ff2e6', '4fa8283daaa5cd337c0000c9', '4f94d6d1eb35c17511000418')

def checkIt(data):
	print "--checkit--", data['userid']
	if data['text'] == '1up':
		doit()
	elif data['text'] =='1down':
		dothat()
	elif data['text'] == '1vu':
		voteUp()
	elif data['text'] == '1vd':
		voteDown()

def dothat():
	bot.remDj()
Ejemplo n.º 20
0
from config import *
import sys
import time
import pdb

class DJ:  # Data container for a DJ
	id = ""
	songs = 0
class Ban: # Data container for a Ban of any sort
	id = ""
	timeStart = 0
	length = 0



bot = Bot(botAuth, botId, roomId)
warnThreshold = 3  # Threshold after which people can lose their spot
djs = []  # List of current DJs
djWhitelist = []  # List of DJs who are currently whitelisted. No whitelist if empty

def m_addBan(id, length):  # Creates and appends a ban to the whitelist
	ban = Ban()
	ban.id = id
	ban.length = length
	ban.timeStart = int(round(time.time() * 1000))
	djWhitelist.append(ban)

def initRoom(data):  # Run on bot connect to room.
	global djs
	bot.modifyLaptop('linux')  # Choose settings
	bot.setAvatar(3)
Ejemplo n.º 21
0
class VitaminBot:
   def __init__(self, config):
      self.config = config

      self._current_users = []
      self._dj_queue = []
      self._djs = []
      self._mods = []

      self._waitingDj = False
      self._waiting_down = False
      self._waiting_user = None

      self._bot = Bot(self.config.authInfo.auth, self.config.authInfo.userid, self.config.authInfo.roomid)

      self._bot.on('speak', self._speak)
      self._bot.on('registered', self._user_in)
      self._bot.on('deregistered', self._user_out)
      self._bot.on('add_dj', self._dj_added)
      self._bot.on('rem_dj', self._dj_removed)
      self._bot.on('roomChanged', self._room_changed)
      self._bot.on('endsong', self._end_song)

      #This prefix can be used by anyone in the room, and it specifies local utility commands for bot management
      #under certain circumstances
      self.LOCAL_COMMAND_PREFIX = ":%:"

#Local helper functions
   def _getUserById(self, l, userid):
      for user in l:
         if user.uid == userid:
            return user
   
   def _getUserByName(self, l, name):
      for user in l:
         if user.name == name:
            return user

   def _removeUser(self, l, userid):
      for user in l:
         if user.uid == userid:
            l.remove(user)
            return user

      return None

   def _queueTimeout(self, user):
      self._bot.speak("Well fine then @%s! You're out of line!" % user.name)
      self._removeUser(self._dj_queue, user.uid)
      self._waitingDj = False
      if len(self._dj_queue) > 0:
         self._notifyQueueUp(self._dj_queue[0])


   def _halfTimeout(self, user):
      self._bot.speak("@%s, 15 seconds and you're out breh..." % user.name)
      self._up_timer = Timer(15,self._queueTimeout, [user])
      self._up_timer.start()

   def _stepDownTimeout(self, user):
      self._bot.speak("Okay @%s, time's up!" % user.name)
      self._waiting_down = False
      self._waiting_user = None

      self._bot.remDj(user.uid)

   def _notifyQueueUp(self, user):
      if not self._waitingDj:
         self._bot.speak("Alright @%s, you're up!" % user.name)
         self._up_timer = Timer(15, self._halfTimeout, [user])
         self._up_timer.start()
         self._waitingDj = True

#Public API functions
#NOTE: These are the only functions that should be called from an
#      implementing module
   def start(self):
      self._bot.start()

   def stop(self):
      self._bot.stop()

   def startDaemon(self, pidfile):
      _daemon = VitaminDaemon(pidfile, self._bot)
      _daemon.start()

   def stopDaemon(self, pidfile):
      _daemon = VitaminDaemon(pidfile, self._bot)
      _daemon.stop()

   def speak(self, s):
      self._bot.speak(str(s))

   def printQueue(self):
      if not self.config.q_enabled:
         self._bot.speak("We are not currently using a queue")
         return

      l = ""

      for i in range(len(self._dj_queue)):
         l += self._dj_queue[i].name + ", "

      self._bot.speak(l)

   def printCommands(self):
      l = ""

      for cmd in self.config.commandList:
         l += cmd + ", "

      self._bot.speak(l)

   def addQueue(self, name, userid):
      user = self._getUserById(self._current_users, userid)

      if not user:
         return

      if not self.config.q_enabled:
         self._bot.speak("We are not currently using a queue")
         return

      if self._dj_queue.count(user) == 0:
         self._dj_queue.append(user)
         self._bot.speak("You have been added to the queue @%s" % name)

         #Now make sure we don't have room for them already
         if len(self._djs) < self.config.MAX_DJS:
            self._notifyQueueUp(user)

      else:
         self._bot.speak("You are already added to the queue... dumb shit.")

   def removeQueue(self, name, userid):
      user = self._getUserById(self._current_users, userid)

      if not user: 
         return

      if not self.config.q_enabled:
         self._bot.speak("We are not currently using a queue")
         return

      if self._dj_queue.count(user) > 0:
         try:
            index = self._dj_queue.index(user)
         except ValueError:
            index = -1

         self._dj_queue.remove(user)
         self._bot.speak("You have been removed from the queue @%s" % name)

         #If this is the user we are waiting on to get up, cancel his timer
         if(index == 0):
            self._up_timer.cancel()
            self._waitingDj = False
            if len(self._dj_queue) > 0:
               self._notifyQueueUp(self._dj_queue[0])

      else:
         self._bot.speak("You aren't in the queue. Get you shit together @%s!" % name)

   def _roomInfoclb(self, data):
      new_users = []
      new_mods = []
      for u in data['users']:
         new_users.append(UserInfo(u['name'], u['userid']))

      for m in data['room']['metadata']['moderator_id']:
         new_mods.append(m)

      self._mods = new_mods

      self._current_users = new_users


   def roomUpdate(self):
      self._bot.roomInfo(False, self._roomInfoclb)


   def enableQueue(self):
      self.config.q_enabled = True

   def disableQueue(self):
      self.config.q_enabled = False

   def vote(self, val):
      if val == 'up' or val == 'down':
         self._bot.vote(val)

   def bop(self):
      self.vote('up')
#Event Handlers

   def _user_id_clb(self, data):
      if data['success']:
         self._current_users.append(UserInfo(self.pendingUserName, data['userid']))

   def _speak(self, data):
      name = data['name']
      text = data['text']

      if text.startswith(self.LOCAL_COMMAND_PREFIX):
         print "Local Command Captured"
         newText = text[len(self.LOCAL_COMMAND_PREFIX):]
         tokenList = newText.split()
         commandToken = tokenList[0]
         print("Token: %s" % commandToken)
         if commandToken == "adduser":
            self.pendingUserName = tokenList[1]
            self._bot.getUserId(tokenList[1], self._user_id_clb)
            return
         if commandToken == "update":
            self.roomUpdate()
            return
         
      #Check if this is a bot command
      if text.startswith(self.config.COMMAND_PREFIX):
         newText = text[len(self.config.COMMAND_PREFIX):]
         tokenList = newText.split()
         commandToken = tokenList[0]
         tokenList.pop(0)
         lCommandToken = commandToken.lower()

         if lCommandToken in self.config.commandList:
            (self.config.commandList[lCommandToken])(data['name'], data['userid'], tokenList)
         else:
            if lCommandToken in self.config.modCommandList:
               if data['userid'] in self.config.modList or data['userid'] in self._mods:
                  (self.config.modCommandList[lCommandToken])(data['name'], data['userid'], tokenList)
               else:
                  self._bot.speak("I don't take those kind of orders from bitches like you, @%s" % data['name'])
            else:
               self._bot.speak("Sorry, I don't recognize %s as a command" % commandToken)

   def _user_in(self, data):
      self._current_users.append(UserInfo(data['user'][0]['name'], data['user'][0]['userid']))
      self._bot.speak("Hello @%s, welcome to SS1!" % data['user'][0]['name'])

   def _user_out(self, data):
      self._removeUser(self._current_users, data['user'][0]['userid'])

   def _dj_added(self, data):
      if self.config.q_enabled:
         if len(self._dj_queue) > 0 and data['user'][0]['userid'] == self._dj_queue[0].uid:
            self._djs.append(self._dj_queue.pop(0))
            self._up_timer.cancel()
            self._waitingDj = False
            if len(self._djs) < self.config.MAX_DJS and len(self._dj_queue) > 0:
               self._notifyQueueUp(self._dj_queue[0])
         else:
            self._bot.remDj(data['user'][0]['userid'])
            self._bot.speak("Get your ass in back in line @%s!" % data['user'][0]['name'])

      else:
         user = self._getUserById(self._current_users, data['user'][0]['userid'])
         self._djs.append(user)

   def _dj_removed(self, data):
      user = self._removeUser(self._djs, data['user'][0]['userid'])
      
      #The user must've been kicked for getting up out of turn
      if not user or not self.config.q_enabled:
         return

      if self._waiting_down and user == self._waiting_user:
         self._waiting_down = False
         self._down_timer.cancel()

      user.playcount = 0
      self._dj_queue.append(user)

      self._bot.speak("You have been added back into the queue @%s" % user.name)

      if len(self._dj_queue):
         self._notifyQueueUp(self._dj_queue[0])

   def _room_changed(self, data):
      self.roomUpdate()

   def _end_song(self, data):
      if not self.config.q_enabled:
         return

      user = self._getUserById(self._djs, data['room']['metadata']['current_dj'])

      if not user:
         return

      user.playcount += 1

      if user.playcount >= self.config.playcount and not self._waiting_down:
         self._bot.speak("Alright @%s. Your plays are up! GTFO" % user.name)
         self._down_timer = Timer(15, self._stepDownTimeout, [user])
         self._waiting_down = True
         self._waiting_user = user
         self._down_timer.start()
Ejemplo n.º 22
0
#
# Auto boot people on a blacklist.
#

from ttapi import Bot

AUTH   = 'auth+live+2cdbb9bd018b4d3af371b29471ce903b9413083a'
USERID = '4fc90519eb35c1533d000006'
ROOMID = '4e3c380114169c4fda19da3b'
bot = Bot(AUTH, USERID, ROOMID)


blackList = set(['xxxxxxxxxxxxxxxxxxxxxxxx', 'xxxxxxxxxxxxxxxxxxxxxxxx'])


# Someone enter the room, make sure he's not on the blacklist.
def registered(data):
   global blackList
   user = data['user'][0]
   if user['userid'] in blackList:
      bot.boot(userId, 'You are on the blacklist.')


bot.on('registered', registered)

bot.start()
Ejemplo n.º 23
0
import pickle
from datetime import *

bumbot_auth       = 'auth+live+xxxxxxxx'
bumbot_userid     = '4fdca143aaa5cd1e79000315'

lsk_userid        = '4e7c70bc4fe7d052ef034402'
babyshoe_userid   = '4e3f5465a3f7512f10015692'

speakeasy_id      = '4e8a63d614169c39fb79b09a'

AUTH   = bumbot_auth
USERID = bumbot_userid
ROOM   = speakeasy_id

bbot = Bot(AUTH,USERID,ROOM)

banlistDir = 'hidden'
bl = open(banlistDir,'r')
banlist = pickle.load(bl)
bl.close()

welcList = [] # Welcome list
userList = []
snags = 0
voteScore = 50
alreadyVoted = 0
songData = {}
djList = []
botPl=[]
addedSong=False
Ejemplo n.º 24
0
from ttapi import Bot
from pprint import pprint
from time import sleep
from collections import deque
from myConfig import *
from BotDB import *
from sys import exit
from random import randint
import json
import re
import sqlite3 as sql
import requests

bot = Bot(myAuthKey, myUserID, defaultRoom)

# Define callbacks
def roomChanged(data): 
    global theUsersList
    global theBopList
    global curSongID
    global curDjID
    global theOpList
    global maxDjCount
    global roomDJs
    global roomOwner
    global playlistCount
    roomInfo = data['room']
    roomMeta = roomInfo['metadata']
    curDjID = roomMeta['current_dj']
    songLog = roomMeta['songlog']
    curSongID = songLog[0]['_id']
Ejemplo n.º 25
0
class LazySusan(object):
    update_checked = False

    @staticmethod
    def _get_config(section):
        config = ConfigParser()
        if 'APPDATA' in os.environ:  # Windows
            os_config_path = os.environ['APPDATA']
        elif 'XDG_CONFIG_HOME' in os.environ:  # Modern Linux
            os_config_path = os.environ['XDG_CONFIG_HOME']
        elif 'HOME' in os.environ:  # Legacy Linux
            os_config_path = os.path.join(os.environ['HOME'], '.config')
        else:
            os_config_path = None
        locations = ['lazysusan.ini']
        if os_config_path is not None:
            locations.insert(0, os.path.join(os_config_path, 'lazysusan.ini'))
        if not config.read(locations):
            raise LazySusanException('No lazysusan.ini found.')
        if not config.has_section(section) and section != 'DEFAULT':
            raise LazySusanException('No section `{0}` found in lazysusan.ini.'
                                     .format(section))
        return dict(config.items(section))

    def __init__(self, config_section, plugin_dir, enable_logging):
        if not self.update_checked:
            update_check(__name__, __version__)
            self.update_checked = True

        self.start_time = datetime.utcnow()

        if plugin_dir:
            if os.path.isdir(plugin_dir):
                sys.path.append(plugin_dir)
            else:
                print('`{0}` is not a directory.'.format(plugin_dir))

        config = self._get_config(config_section)
        self._delayed_events = []
        self._loaded_plugins = {}
        self.api = Bot(config['auth_id'], config['user_id'], rate_limit=0.575)
        self.api.debug = enable_logging
        self.api.on('add_dj', self.handle_add_dj)
        self.api.on('booted_user', self.handle_booted_user)
        self.api.on('deregistered', self.handle_user_leave)
        self.api.on('new_moderator', self.handle_add_moderator)
        self.api.on('post_message', self.run_delayed_events)
        self.api.on('pmmed', self.handle_pm)
        self.api.on('ready', self.handle_ready)
        self.api.on('registered', self.handle_user_join)
        self.api.on('rem_dj', self.handle_remove_dj)
        self.api.on('rem_moderator', self.handle_remove_moderator)
        self.api.on('roomChanged', self.handle_room_change)
        self.api.on('speak', self.handle_room_message)
        self.bot_id = config['user_id']
        self.commands = {'/about': self.cmd_about,
                         '/commands': self.cmd_commands,
                         '/help': self.cmd_help,
                         '/join': self.cmd_join,
                         '/leave': self.cmd_leave,
                         '/pgload': self.cmd_plugin_load,
                         '/pgreload': self.cmd_plugin_reload,
                         '/pgunload': self.cmd_plugin_unload,
                         '/plugins': self.cmd_plugins,
                         '/uptime': self.cmd_uptime}
        self.config = config
        self.dj_ids = set()
        self.listener_ids = set()
        self.max_djs = None
        self.moderator_ids = set()
        self.username = None

        # Load plugins after everything has been initialized
        for plugin in config['plugins'].split('\n'):
            self.load_plugin(plugin)

        self.api.connect(config['room_id'])
        self.api.ws.on_error = handle_error

    def _load_command_plugin(self, plugin):
        to_add = {}
        for command, func_name in plugin.COMMANDS.items():
            if command in self.commands:
                other = self.commands[command]
                if isinstance(other.im_self, CommandPlugin):
                    print('`{0}` conflicts with `{1}` for command `{2}`.'
                          .format(plugin.NAME, other.im_self.NAME, command))
                else:
                    print('`{0}` cannot use the reserved command `{1}`.'
                          .format(plugin.NAME, command))
                print('Not loading plugin `{0}`.'.format(plugin.NAME))
                return False
            to_add[command] = getattr(plugin, func_name)
        self.commands.update(to_add)
        return True

    def _unload_command_plugin(self, plugin):
        for command in plugin.COMMANDS:
            del self.commands[command]

    @no_arg_command
    def cmd_about(self, data):
        """Display information about this bot."""
        reply = ('''I am powered by LazySusan version {0}. '
                 'https://github.com/bboe/LazySusan'.format(__version__)
                 'Questions/Comments can be directed to ##TTT on IRC.Freenode.net
                 http://webchat.freenode.net/?randomnick=1&channels=##ttt&uio=d4'''
                 )
        self.reply(reply, data)

    @no_arg_command
    def cmd_commands(self, data):
        """List the available commands."""

        admin_cmds = []
        admin_or_moderator_cmds = []
        moderator_cmds = []
        no_priv_cmds = []

        for command, func in self.commands.items():
            if func.func_dict.get('admin_required'):
                admin_cmds.append(command)
            elif func.func_dict.get('admin_or_moderator_required'):
                admin_or_moderator_cmds.append(command)
            elif func.func_dict.get('moderator_required'):
                moderator_cmds.append(command)
            else:
                no_priv_cmds.append(command)
        reply = 'Available commands: '
        reply += ', '.join(sorted(no_priv_cmds))
        self.reply(reply, data)

        user_id = get_sender_id(data)
        if moderator_cmds and self.is_moderator(user_id):
            reply = 'Moderator commands: '
            reply += ', '.join(sorted(moderator_cmds))
            self.api.pm(reply, user_id)
        if admin_or_moderator_cmds and (self.is_moderator(user_id)
                                        or self.is_admin(user_id)):
            reply = 'Priviliged commands: '
            reply += ', '.join(sorted(admin_or_moderator_cmds))
            self.api.pm(reply, user_id)
        if admin_cmds and self.is_admin(user_id):
            reply = 'Admin commands: '
            reply += ', '.join(sorted(admin_cmds))
            self.api.pm(reply, user_id)

    def _connect(self, room_id, when_connected=True):
        if self.api.roomId == room_id or (self.api.roomId
                                          and not when_connected):
            return
        print('Joining {0}'.format(room_id))
        self.api.roomRegister(room_id)

    def cmd_help(self, message, data):
        """With no arguments, display this message. Otherwise, display the help
        for the given command. Type /commands to see the list of commands."""
        def docstr(item):
            lines = []
            for line in item.__doc__.split('\n'):
                line = line.strip()
                if line:
                    lines.append(line)
            return ' '.join(lines)

        if not message:
            reply = docstr(self.cmd_help)
        elif ' ' not in message:
            if message in self.commands:
                tmp = self.commands[message].func_dict
                if tmp.get('admin_required') and not self.is_admin(data) or \
                        tmp.get('moderator_required') and \
                        not self.is_moderator(data):
                    return
                reply = docstr(self.commands[message])
            else:
                reply = '`{0}` is not a valid command.'.format(message)
        else:
            return
        self.reply(reply, data)

    @admin_required
    def cmd_join(self, message, data):
        """Join the room by room_id.

        With no arguments, join the room specified in lazysusan.ini."""
        if ' ' in message:
            return
        room_id = message if message else self.config['room_id']
        if room_id == self.api.roomId:
            self.reply('I am already in that room.', data)
        else:
            self._connect(room_id)

    @admin_required
    @no_arg_command
    def cmd_leave(self, data):
        """Leave the current room and remain connected to the chat server."""
        def callback(cb_data):
            user_id = get_sender_id(data)
            if cb_data['success']:
                # Schedule an event to possibly rejoin after 1 minute
                self.schedule(60, self._connect, self.config['room_id'], False)
                self.api.pm('I have left the room. If I remain roomless after '
                            '~1 minute, I will rejoin the default room.',
                            user_id)
            else:
                self.api.pm('Leaving the room failed.', user_id)
        print('Leaving {0}'.format(self.api.roomId))
        self.api.roomDeregister(callback)

    @admin_required
    @single_arg_command
    def cmd_plugin_load(self, message, data):
        """Load the specified plugin."""
        if message in self._loaded_plugins:
            reply = 'Plugin `{0}` is already loaded.'.format(message)
        elif self.load_plugin(message, attempt_reload=True):
            reply = 'Plugin `{0}` loaded.'.format(message)
        else:
            reply = 'Plugin `{0}` could not be loaded.'.format(message)
        self.reply(reply, data)

    @admin_required
    @single_arg_command
    def cmd_plugin_reload(self, message, data):
        """Reoad the specified plugin."""
        if message not in self._loaded_plugins:
            reply = 'Plugin `{0}` is not loaded.'.format(message)
        elif not (self.unload_plugin(message) and
                  self.load_plugin(message, attempt_reload=True)):
            reply = 'Plugin `{0}` could not be reloaded.'.format(message)
        else:
            reply = 'Plugin `{0}` reloaded.'.format(message)
        self.reply(reply, data)

    @admin_required
    @single_arg_command
    def cmd_plugin_unload(self, message, data):
        """Unload the specified plugin."""
        if message not in self._loaded_plugins:
            reply = 'Plugin `{0}` is not loaded.'.format(message)
        elif self.unload_plugin(message):
            reply = 'Plugin `{0}` unloaded.'.format(message)
        else:
            reply = 'Plugin `{0}` could not be unloaded.'.format(message)
        self.reply(reply, data)

    @admin_required
    @no_arg_command
    def cmd_plugins(self, data):
        """Display the list of loaded plugins."""
        reply = 'Loaded plugins: '
        reply += ', '.join(sorted(self._loaded_plugins.keys()))
        self.reply(reply, data)

    @no_arg_command
    def cmd_uptime(self, data):
        """Display how long since LazySusan was started."""
        msg = 'LazySusan was started {0}'.format(pretty_date(self.start_time))
        self.reply(msg, data)

    def is_admin(self, item):
        """item can be either the user_id, or a dictionary from a message."""
        if isinstance(item, dict):
            item = get_sender_id(item)
        return item in self.config['admin_ids']

    def is_moderator(self, item):
        """item can be either the user_id, or a dictionary from a message."""
        if isinstance(item, dict):
            item = get_sender_id(item)
        return item in self.moderator_ids

    def handle_add_dj(self, data):
        for user in data['user']:
            self.dj_ids.add(user['userid'])

    def handle_booted_user(self, data):
        if data['userid'] == self.bot_id:
            # Try to rejoin the default room after 30 seconds.
            self.api.roomId = None
            self.schedule(30, self._connect, self.config['room_id'], False)

    def handle_add_moderator(self, data):
        self.moderator_ids.add(data['userid'])

    def handle_pm(self, data):
        self.process_message(data)

    def handle_ready(self, _):
        self.api.userInfo(self.set_username)

    @display_exceptions
    def handle_remove_dj(self, data):
        for user in data['user']:
            self.dj_ids.remove(user['userid'])

    @display_exceptions
    def handle_remove_moderator(self, data):
        self.moderator_ids.remove(data['userid'])

    def handle_room_change(self, data):
        if not data['success']:
            if data['errno'] == 3:
                print('You are banned from that room. Retrying in 3 minutes.')
                self.schedule(180, self._connect, self.config['room_id'],
                              False)
                return
            print('Error changing rooms.')
            # Try to rejoin the default room
            self.api.roomId = None
            self._connect(self.config['room_id'])
            return
        self.dj_ids = set(data['room']['metadata']['djs'])
        self.listener_ids = set(x['userid'] for x in data['users'])
        self.max_djs = data['room']['metadata']['max_djs']
        self.moderator_ids = set(data['room']['metadata']['moderator_id'])

    @display_exceptions
    def handle_room_message(self, data):
        if self.username and self.username != data['name']:
            self.process_message(data)

    def handle_user_join(self, data):
        for user in data['user']:
            self.listener_ids.add(user['userid'])

    @display_exceptions
    def handle_user_leave(self, data):
        for user in data['user']:
            self.listener_ids.remove(user['userid'])

    def load_plugin(self, plugin_name, attempt_reload=False):
        parts = plugin_name.split('.')
        if len(parts) > 1:
            module_name = '.'.join(parts[:-1])
            class_name = parts[-1]
        else:
            # Use the titlecase format of the module name as the class name
            module_name = parts[0]
            class_name = parts[0].title()

        # First try to load plugins from the passed in plugins_dir and then
        # from the lazysusan.plugins package.
        module = None
        for package in (None, 'lazysusan.plugins'):
            if package:
                module_name = '{0}.{1}'.format(package, module_name)

            if attempt_reload and module_name in sys.modules:
                module = reload(sys.modules[module_name])
            else:
                try:
                    module = __import__(module_name, fromlist=[class_name])
                except ImportError:
                    pass
            if module:
                break
        if not module:
            print('Cannot find plugin `{0}`.'.format(plugin_name))
            return False
        try:
            plugin = getattr(module, class_name)(self)
        except AttributeError:
            print('Cannot find plugin `{0}`.'.format(plugin_name))
            return False

        plugin.__class__.NAME = plugin_name
        if isinstance(plugin, CommandPlugin):
            if not self._load_command_plugin(plugin):
                return
        self._loaded_plugins[plugin_name] = plugin
        print('Loaded plugin `{0}`.'.format(plugin_name))
        return True

    def process_message(self, data):
        parts = data['text'].split()
        if not parts:
            return
        command = parts[0]
        if len(parts) == 1:
            message = ''
        else:
            message = ' '.join(parts[1:])  # Normalize with single spaces
        handler = self.commands.get(command)
        if not handler:
            return
        handler(message, data)

    def reply(self, message, data):
        if data['command'] == 'speak':
            self.api.speak(message)
        elif data['command'] == 'pmmed':
            self.api.pm(message, data['senderid'])
        else:
            raise Exception('Unrecognized command type `{0}`'
                            .format(data['command']))

    def run_delayed_events(self, _):
        now = time.time()
        process = True
        while process and self._delayed_events:
            item = self._delayed_events[0]  # Peek at the top
            if item[0] < now:
                heapq.heappop(self._delayed_events)  # Actually remove
                item[1](*item[2], **item[3])
            else:
                process = False

    def schedule(self, min_delay, callback, *args, **kwargs):
        """Schedule an event to occur at least min_delay seconds in the future.

        The passed in callback function will be called with all remaining
        arguments.

        Scheduled events are checked and processed after every received message
        from turntable. In an inactive room the longest duration between
        received messages is 12 seconds."""
        schedule_time = time.time() + min_delay
        heapq.heappush(self._delayed_events,
                       (schedule_time, callback, args, kwargs))

    def set_username(self, data):
        self.username = data['name']

    def start(self):
        self.api.start()

    def unload_plugin(self, plugin_name):
        if plugin_name not in self._loaded_plugins:
            return False
        plugin = self._loaded_plugins[plugin_name]
        if isinstance(plugin, CommandPlugin):
            self._unload_command_plugin(plugin)
        del self._loaded_plugins[plugin_name]
        del plugin
        print('Unloaded plugin `{0}`.'.format(plugin_name))
        return True