diff --git a/data/config/DogeDice.yml b/data/config/DogeDice.yml deleted file mode 100644 index 28b01d0..0000000 --- a/data/config/DogeDice.yml +++ /dev/null @@ -1,5 +0,0 @@ -minBet: .01 -lobbyIdleSeconds: 15 -channelWhitelistOn: True -channelWhitelist: - - test \ No newline at end of file diff --git a/data/config/DogeRPC.yml b/data/config/DogeRPC.yml deleted file mode 100644 index 8939bf3..0000000 --- a/data/config/DogeRPC.yml +++ /dev/null @@ -1,4 +0,0 @@ -host: 127.0.0.1 -username: root -password: root -port: 22555 \ No newline at end of file diff --git a/data/config/DogeScramble.yml b/data/config/DogeScramble.yml deleted file mode 100644 index 9754af9..0000000 --- a/data/config/DogeScramble.yml +++ /dev/null @@ -1,7 +0,0 @@ -hintDelay: 15 -delayNext: 5 -maxHints: 5 -abortAfterNoGuesses: 2 -winAmount: 0.1 -categoryduration: 2 -decreaseFactor: 0.83 \ No newline at end of file diff --git a/data/config/Scramble.yml b/data/config/Scramble.yml index cbd5bc5..acb369b 100644 --- a/data/config/Scramble.yml +++ b/data/config/Scramble.yml @@ -1,5 +1,4 @@ hintDelay: 15 delayNext: 5 maxHints: 5 -abortAfterNoGuesses: 5 -decreaseFactor: 0.83 \ No newline at end of file +abortAfterNoGuesses: 5 \ No newline at end of file diff --git a/pyircbot/core/pyircbot.py b/pyircbot/core/pyircbot.py index eb23b79..9856b9f 100644 --- a/pyircbot/core/pyircbot.py +++ b/pyircbot/core/pyircbot.py @@ -70,7 +70,17 @@ class PyIRCBot(asynchat.async_chat): def found_terminator(self): " A complete command was pushed through, so clear the buffer and process it." - self.process_data(self.getBuf().decode("UTF-8")) + line = None + buf = self.getBuf() + try: + line = buf.decode("UTF-8") + except UnicodeDecodeError as ude: + self.log.error("found_terminator(): could not decode input as UTF-8") + self.log.error("found_terminator(): data: %s" % line) + self.log.error("found_terminator(): repr(data): %s" % repr(line)) + self.log.error("found_terminator(): error: %s" % str(ude)) + return + self.process_data(line) def handle_close(self): " called on socket shutdown " diff --git a/pyircbot/core/rpc.py b/pyircbot/core/rpc.py index 258250f..3a6edd1 100644 --- a/pyircbot/core/rpc.py +++ b/pyircbot/core/rpc.py @@ -17,36 +17,71 @@ class BotRPC(Thread): self.server.register_function( self.unloadModule ) self.server.register_function( self.reloadModule ) self.server.register_function( self.redoModule ) - self.server.register_function( self.getTraceback ) + self.server.register_function( self.getLoadedModules ) + self.server.register_function( self.pluginCommand ) + self.server.register_function( self.setPluginVar ) + self.server.register_function( self.getPluginVar ) + self.start() def run(self): self.server.serve() - def importModule(self, moduleName): + self.log.info("RPC: calling importModule(%s)"%moduleName) return self.bot.importmodule(moduleName) def deportModule(self, moduleName): + self.log.info("RPC: calling deportModule(%s)"%moduleName) self.bot.deportmodule(moduleName) def loadModule(self, moduleName): + self.log.info("RPC: calling loadModule(%s)"%moduleName) return self.bot.loadmodule(moduleName) def unloadModule(self, moduleName): + self.log.info("RPC: calling unloadModule(%s)"%moduleName) self.bot.unloadmodule(moduleName) def reloadModule(self, moduleName): + self.log.info("RPC: calling reloadModule(%s)"%moduleName) self.bot.unloadmodule(moduleName) return self.bot.loadmodule(moduleName) def redoModule(self, moduleName): + self.log.info("RPC: calling redoModule(%s)"%moduleName) return self.bot.redomodule(moduleName) - def getTraceback(self): - tb = str(traceback.format_exc()) - print(tb) - return tb + def getLoadedModules(self): + self.log.info("RPC: calling getLoadedModules()") + return list(self.bot.moduleInstances.keys()) + def pluginCommand(self, pluginName, methodName, argList): + plugin = self.bot.getmodulebyname(pluginName) + if not plugin: + return (False, "Plugin not found") + method = getattr(plugin, methodName) + if not method: + return (False, "Method not found") + self.log.info("RPC: calling %s.%s(%s)" % (pluginName, methodName, argList)) + return (True, method(*argList)) + def getPluginVar(self, pluginName, pluginVarName): + plugin = self.bot.getmodulebyname(pluginName) + if pluginName == "_core": + plugin = self.bot + if not plugin: + return (False, "Plugin not found") + self.log.info("RPC: getting %s.%s" % (pluginName, pluginVarName)) + return (True, getattr(plugin, pluginVarName)) + def setPluginVar(self, pluginName, pluginVarName, value): + plugin = self.bot.getmodulebyname(pluginName) + if pluginName == "_core": + plugin = self.bot + if not plugin: + return (False, "Plugin not found") + self.log.info("RPC: setting %s.%s = %s )" % (pluginName, pluginVarName, value)) + setattr(plugin, pluginVarName, value) + return (True, "Var set") + diff --git a/pyircbot/modules/AttributeStorage.py b/pyircbot/modules/AttributeStorage.py index cd4b671..c732747 100644 --- a/pyircbot/modules/AttributeStorage.py +++ b/pyircbot/modules/AttributeStorage.py @@ -47,6 +47,7 @@ class AttributeStorage(ModuleBase): # self.getAttribute('xMopxShell', 'name') # self.setAttribute('xMopxShell', 'name', 'dave') + # SELECT `i`.`id`, `i`.`item`, `a`.`attribute`, `v`.`value` FROM `items` `i` INNER JOIN `values` `v` on `v`.`itemid`=`i`.`id` INNER JOIN `attribute` `a` on `a`.`id`=`v`.`attributeid` ORDER BY `i`.`id` ASC, `a`.`id` ASC LIMIT 1000 ; def getItem(self, name): c = self.db.connection.query("""SELECT diff --git a/pyircbot/modules/DogeDice.py b/pyircbot/modules/DogeDice.py deleted file mode 100644 index 80cc7a5..0000000 --- a/pyircbot/modules/DogeDice.py +++ /dev/null @@ -1,315 +0,0 @@ -#!/usr/bin/env python -from modulebase import ModuleBase,ModuleHook -import random -import yaml -import os -import time -import math -import hashlib -from threading import Timer - -class DogeDice(ModuleBase): - def __init__(self, bot, moduleName): - ModuleBase.__init__(self, bot, moduleName); - self.hooks=[ModuleHook("PRIVMSG", self.gotMsg)] - self.loadConfig() - # Load attribute storage - self.attr = self.bot.getBestModuleForService("attributes") - # Load doge RPC - self.doge = self.bot.getBestModuleForService("dogerpc") - # Dict of #channel -> game object - self.games = {} - - def gotMsg(self, args, prefix, trailing): - prefixObj = self.bot.decodePrefix(prefix) - # Ignore messages from users not logged in - loggedinfrom = self.attr.getAttribute(prefixObj.nick, "loggedinfrom") - if loggedinfrom==None: - # Send them a hint? - return - elif prefixObj.hostname == loggedinfrom: - if args[0][0] == "#": - # create a blank game obj if there isn't one (and whitelisted ? ) - if not args[0] in self.games and (not self.config["channelWhitelistOn"] or (self.config["channelWhitelistOn"] and args[0][1:] in self.config["channelWhitelist"]) ): - self.games[args[0]]=gameObj(self, args[0]) - # Channel message - self.games[args[0]].gotMsg(args, prefix, trailing) - else: - # Private message - #self.games[args[0].gotPrivMsg(args, prefix, trailing) - pass - else: - # Ignore potential spoofing - pass - - def removeGame(self, channel): - del self.games[channel] - - def ondisable(self): - self.log.info("DogeDice: Unload requested, ending games...") - while len(self.games)>0: - first = list(self.games.keys())[0] - self.games[first].gameover() - -class gameObj: - def __init__(self, master, channel): - self.master = master - self.channel = channel - # Game state - # 0 = waiting for players - # - advertise self? - # - players must be registered and have enough doge for current bet - # 1 = enough players, countdown - # - Last warning to pull out - # 2 = locked in / game setup - # - Move doge from player's wallets to table wallet. kick players if they can't afford - # 3 = start of a round - # - Each player's turn to roll - # 4 = determine winner, move doge - # - if > 10 doge, house fee? - self.step = 0 - - # Bet amount - self.bet = 0.0 - # players list - self.players = [] - # min players - self.minPlayers = 2 - # max players - self.maxPlayers = 4 - # Lobby countdown timer - self.startCountdownTimer = None - # pre-result timer - self.endgameResultTimer = None - # in-game timeout - self.playTimeout = None - # Wallet for this game - self.walletName = None - - def getPlayer(self, nick): - for player in self.players: - if player.nick == nick: - return player - return None - - def gotPrivMsg(self, args, prefix, trailing): - prefix = self.master.bot.decodePrefix(prefix) - pass - - def gotMsg(self, args, prefix, trailing): - prefix = self.master.bot.decodePrefix(prefix) - if self.step == 0 or self.step == 1: - # Join game - cmd = self.master.bot.messageHasCommand(".join", trailing) - if cmd: - if len(self.players)-1 < self.maxPlayers: - if self.getPlayer(prefix.nick)==None: - userWallet = self.master.attr.getAttribute(prefix.nick, "dogeaccountname") - if userWallet == None: - self.master.bot.act_PRIVMSG(self.channel, "%s: You don't have enough DOGE!" % (prefix.nick)) - return - balance = self.master.doge.getBal(userWallet) - - # check if the room is 'opened' already: - if len(self.players)==0: - # require an amount - if len(cmd.args)==1: - # Check if they have enough coins - try: - bet = float(cmd.args[0]) - except: - return - - if bet < self.master.config["minBet"]: - self.master.bot.act_PRIVMSG(self.channel, "%s: Minimum bet is %s DOGE!" % (prefix.nick, self.master.config["minBet"])) - return - - if balance>=bet: - newPlayer = playerObj(self, prefix.nick) - newPlayer.dogeWalletName = userWallet - self.players.append(newPlayer) - self.bet = bet - self.master.bot.act_PRIVMSG(self.channel, "%s: You have joined!" % (prefix.nick)) - else: - self.master.bot.act_PRIVMSG(self.channel, "%s: You don't have enough DOGE!" % (prefix.nick)) - else: - self.master.bot.act_PRIVMSG(self.channel, "%s: You need to specify a bet amount: .join 10" % (prefix.nick)) - else: - # no amount required - if balance>=self.bet: - newPlayer = playerObj(self, prefix.nick) - newPlayer.dogeWalletName = userWallet - self.players.append(newPlayer) - self.master.bot.act_PRIVMSG(self.channel, "%s: You have joined!" % (prefix.nick)) - if self.canStart() and self.startCountdownTimer == None: - self.initStartCountdown() - self.master.bot.act_PRIVMSG(self.channel, "The game will start in %s seconds! Bet is %s DOGE each!" % (self.master.config["lobbyIdleSeconds"], self.bet)) - else: - self.master.bot.act_PRIVMSG(self.channel, "%s: You don't have enough DOGE!" % (prefix.nick)) - - else: - self.master.bot.act_PRIVMSG(self.channel, "%s: you're already in the game. Quit with .leave" % (prefix.nick)) - else: - self.master.bot.act_PRIVMSG(self.channel, "%s: the game is full (%s/%)! Cannot join." % (prefix.nick, len(self.players), self.maxPlayers)) - # Leave game - cmd = self.master.bot.messageHasCommand(".leave", trailing) - if cmd: - if self.getPlayer(prefix.nick)==None: - self.master.bot.act_PRIVMSG(self.channel, "%s: You're not in the game." % (prefix.nick)) - else: - self.removePlayer(prefix.nick) - self.master.bot.act_PRIVMSG(self.channel, "%s: You have left the game!" % (prefix.nick)) - if not self.canStart() and self.startCountdownTimer: - self.clearTimer(self.startCountdownTimer) - self.startCountdownTimer = None - self.master.bot.act_PRIVMSG(self.channel, "Game start aborted." ) - self.step = 0 - elif self.step == 2: - pass - elif self.step == 3: - # Ignore cmds from people outside the game - player = self.getPlayer(prefix.nick) - if not player: - return - - # handle a .roll - cmd = self.master.bot.messageHasCommand(".roll", trailing) - if cmd and not player.hasRolled: - roll1 = random.randint(1,6) - roll2 = random.randint(1,6) - self.master.bot.act_PRIVMSG(self.channel, "%s rolls %s and %s!" % (prefix.nick, roll1, roll2)) - player.hasRolled = True - player.rollValue = roll1+roll2 - - # Check if all players have rolled - for player in self.players: - if not player.hasRolled: - return - - # start endgame timer - self.step = 4 - self.endgameResultTimer = Timer(2, self.endgameResults) - self.endgameResultTimer.start() - - elif self.step == 4: - pass - - #senderIsOp = self.master.attr.getAttribute(prefix.nick, "op")=="yes" - def clearTimer(self, timer): - if timer: - timer.cancel() - timer = None - - def removePlayer(self, playerNick): - pos = -1 - for i in range(0, len(self.players)): - if self.players[i].nick == playerNick: - pos = i - break - if pos >= 0: - self.players.pop(pos) - - def canStart(self): - # Return true if the step is 'lobby' mode and player count is OK - return self.step == 0 and len(self.players)>=self.minPlayers - def initStartCountdown(self): - # Start the game-start countdown - self.startCountdownTimer = Timer(self.master.config["lobbyIdleSeconds"], self.lobbyCountdownDone) - self.startCountdownTimer.start() - self.step = 1 - - def lobbyCountdownDone(self): - self.step = 2 - self.master.bot.act_PRIVMSG(self.channel, "Collecting DOGE and starting game.. Type .roll !") - # Make a wallet for this game - self.walletName = "DogeDice-"+self.channel - # Generate an address to 'create' a wallet - self.master.doge.getAcctAddr(self.walletName) - - # Verify and move funds from each player - for player in self.players: - playerBalance = self.master.doge.getAcctBal(player.dogeWalletName) - if playerBalance < self.bet: - self.master.bot.act_PRIVMSG(self.channel, "%s was dropped from the game!") - self.removePlayer(player.nick) - - if len(self.players) <= 1: - self.master.bot.act_PRIVMSG(self.channel, "1 or players left - game over!") - self.resetGame() - return - - # Take doges - for player in self.players: - self.master.doge.move(player.dogeWalletName, self.walletName, self.bet) - - # Pre-game setup (nothing !) - - # Accept game commands - self.step = 3 - - # Start play timeout - self.playTimeout = Timer(30, self.gamePlayTimeoutExpired) - self.playTimeout.start() - - def gamePlayTimeoutExpired(self): - # Time out - return doges - self.master.bot.act_PRIVMSG(self.channel, "Time expired! Returning all doges.") - if self.step == 3: - # In game step. Refund doges - for player in self.players: - self.master.doge.move(self.walletName, player.dogeWalletName, self.bet) - self.resetGame() - - def endgameResults(self): - maxRollNames = [] - maxRollValue = 0 - for player in self.players: - if player.rollValue > maxRollValue: - maxRollNames = [] - maxRollNames.append(player.nick) - maxRollValue = player.rollValue - if player.rollValue == maxRollValue: - if not player.nick in maxRollNames: - maxRollNames.append(player.nick) - - pot = self.master.doge.getAcctBal(self.walletName) - DOGEeachDec = pot/len(maxRollNames) - DOGEeach = math.floor(DOGEeachDec*100000000) / 100000000 - - if len(maxRollNames)==1: - self.master.bot.act_PRIVMSG(self.channel, "We have a winner - %s! Winnings are: %s DOGE" % (maxRollNames[0], DOGEeach)) - else: - self.master.bot.act_PRIVMSG(self.channel, "We have a tie between %s - The take is %s DOGE each" % (' and '.join(maxRollNames), DOGEeach)) - - # Pay out - for nick in maxRollNames: - player = self.getPlayer(nick) - self.master.doge.move(self.walletName, player.dogeWalletName, DOGEeach) - - # the end! - self.resetGame() - - def resetGame(self): - self.clearTimer(self.startCountdownTimer) - self.startCountdownTimer = None - self.clearTimer(self.endgameResultTimer) - self.endgameResultTimer = None - self.clearTimer(self.playTimeout) - self.playTimeout = None - self.master.removeGame(self.channel) - - def gameover(self): - self.gamePlayTimeoutExpired() - - -class playerObj: - def __init__(self, game, nick): - self.game = game - self.nick = nick - # Save the player's wallet name - self.dogeWalletName = None - # Set to true after they roll - self.hasRolled = False - # Sum of their dice - self.rollValue = None - diff --git a/pyircbot/modules/DogeRPC.py b/pyircbot/modules/DogeRPC.py deleted file mode 100644 index 16e4512..0000000 --- a/pyircbot/modules/DogeRPC.py +++ /dev/null @@ -1,66 +0,0 @@ -#!/usr/bin/env python -from modulebase import ModuleBase,ModuleHook -from bitcoinrpc.authproxy import AuthServiceProxy - -class DogeRPC(ModuleBase): - def __init__(self, bot, moduleName): - ModuleBase.__init__(self, bot, moduleName); - self.hooks=[] - self.services=["dogerpc"] - self.loadConfig() - self.rpc = DogeController(self) - - def getBal(self, acct): - " get a balance of an address or an account " - return self.getAcctBal(acct) - - def getAcctAddr(self, acct): - " returns the address for an account. creates if necessary " - self.rpc.ping() - addrs = self.rpc.con.getaddressesbyaccount(acct) - if len(addrs)==0: - return self.rpc.con.getnewaddress(acct) - return addrs[0] - - def getAcctBal(self, acct): - " returns an account's balance" - self.rpc.ping() - return float(self.rpc.con.getbalance(acct)) - - def canMove(self, fromAcct, toAcct, amount): - " true or false if fromAcct can afford to give toAcct an amount of coins " - balfrom = self.getAcctBal(fromAcct) - return balfrom >= amount - - def move(self, fromAcct, toAcct, amount): - " move coins from one account to another " - self.rpc.ping() - if self.canMove(fromAcct, toAcct, amount): - return self.rpc.con.move(fromAcct, toAcct, amount) - return False - - def send(self, fromAcct, toAddr, amount): - " send coins to an external addr " - self.rpc.ping() - if self.canMove(fromAcct, toAddr, amount): - return self.rpc.con.sendfrom(fromAcct, toAddr, amount) - return False - -class DogeController: - def __init__(self, master): - self.config = master.config - self.log = master.log - self.con = None - self.ping() - - def ping(self): - try: - self.con.getinfo() - except: - self.connect() - - def connect(self): - self.log.debug("DogeRPC: Connecting to dogecoind") - self.con = AuthServiceProxy("http://%s:%s@%s:%s" % (self.config["username"], self.config["password"], self.config["host"], self.config["port"])) - self.con.getinfo() - self.log.debug("DogeRPC: Connected to %s:%s" % (self.config["host"], self.config["port"])) diff --git a/pyircbot/modules/DogeScramble.py b/pyircbot/modules/DogeScramble.py deleted file mode 100644 index 44c923f..0000000 --- a/pyircbot/modules/DogeScramble.py +++ /dev/null @@ -1,258 +0,0 @@ -#!/usr/bin/env python -from modulebase import ModuleBase,ModuleHook -import random -import yaml -import os -import time -from threading import Timer - -class DogeScramble(ModuleBase): - def __init__(self, bot, moduleName): - ModuleBase.__init__(self, bot, moduleName); - self.hooks=[ModuleHook("PRIVMSG", self.scramble)] - self.loadConfig() - - # Load attribute storage - self.attr = None - serviceProviders = self.bot.getmodulesbyservice("attributes") - if len(serviceProviders)==0: - self.log.error("DogeScramble: Could not find a valid attributes service provider") - else: - self.log.info("DogeScramble: Selecting attributes service provider: %s" % serviceProviders[0]) - self.attr = serviceProviders[0] - - # Load doge RPC - self.doge = self.bot.getBestModuleForService("dogerpc") - - # Per channel games - self.games = {} - - def scramble(self, args, prefix, trailing): - channel = args[0] - if channel[0] == "#": - # Ignore messages from users without a dogewallet password - prefixObj = self.bot.decodePrefix(prefix) - if self.attr.getAttribute(prefixObj.nick, "password")==None: - return - if not channel in self.games: - self.games[channel]=scrambleGame(self, channel) - self.games[channel].scramble(args, prefix, trailing) - def ondisable(self): - self.log.info("DogeScramble: Unload requested, ending games...") - for game in self.games: - self.games[game].gameover() - -class scrambleGame: - def __init__(self, master, channel): - self.master = master - self.channel = channel - # Running? - self.running = False - # Current word - self.currentWord = None - # Current word, scrambled - self.scrambled = None - # Online? - self.scrambleOn = False - # Count down to hints - self.hintTimer = None - # of hints given - self.hintsGiven = 0 - # Cooldown between words - self.nextTimer = None - # How many guesses submitted this round - self.guesses = 0; - # How many games in a row where nobody guessed - self.gamesWithoutGuesses = 0; - # What file are we using - self.category_file = None; - # How many words in this category have been used? - self.category_count = 0 - # How long between categories - self.change_category_after_words = self.master.config["categoryduration"] - # Should we change categories at the next pick? - self.should_change_category = True - # Holds the processed category name - self.category_name = None - # list of last picked words - self.lastwords = [] - # name of last winner for decreasing return - self.lastwinner = None - self.lastwinvalue = 0 - - self.delayHint = self.master.config["hintDelay"]; - self.delayNext = self.master.config["delayNext"]; - self.maxHints = self.master.config["maxHints"]; - self.abortAfterNoGuesses = self.master.config["abortAfterNoGuesses"]; - - def gameover(self): - self.clearTimers(); - self.running = False - def clearTimers(self): - self.clearTimer(self.nextTimer) - self.clearTimer(self.hintTimer) - def clearTimer(self, timer): - if timer: - timer.cancel() - def scramble(self, args, prefix, trailing): - prefix = self.master.bot.decodePrefix(prefix) - sender = prefix.nick - - senderIsOp = self.master.attr.getAttribute(prefix.nick, "op")=="yes" - - cmd = self.master.bot.messageHasCommand(".scramble", trailing) - if cmd and not self.running: - #and senderIsOp - self.running = True - self.startScramble() - return - cmd = self.master.bot.messageHasCommand(".scrambleoff", trailing) - if cmd and senderIsOp and self.running: - self.gameover() - self.running = False - return - - if self.currentWord and trailing.strip().lower() == self.currentWord: - # Get winner withdraw address - useraddr = self.master.attr.getAttribute(prefix.nick, "dogeaddr") - userwallet = self.master.attr.getAttribute(prefix.nick, "dogeaccountname") - - self.master.bot.act_PRIVMSG(self.channel, "%s got the word - %s!" % (sender, self.currentWord)) - - if not useraddr: - self.master.bot.act_PRIVMSG(self.channel, "%s: to win DOGE, you must set an wallet address by PMing me \".setdogeaddr\". Next word in %s seconds." % (prefix.nick, self.delayNext)) - else: - winamount = float(self.master.config["winAmount"]) - if self.lastwinner == prefix.nick: - winamount = self.lastwinvalue * self.master.config["decreaseFactor"] - self.lastwinvalue = winamount - self.lastwinner = prefix.nick - - self.master.bot.act_PRIVMSG(self.channel, "%s won %s DOGE! Next word in %s seconds." % (prefix.nick, round(winamount, 8), self.delayNext)) - self.master.doge.move('', userwallet, winamount) - - self.currentWord = None - self.clearTimers() - self.hintsGiven = 0 - self.nextTimer = Timer(self.delayNext, self.startNewWord) - self.nextTimer.start() - self.guesses=0 - self.category_count+=1 - self.master.log.debug("DogeScramble: category_count is: %s" % (self.category_count)) - if self.category_count >= self.change_category_after_words: - self.should_change_category = True - else: - self.guesses+=1 - - def startScramble(self): - self.clearTimer(self.nextTimer) - self.nextTimer = Timer(0, self.startNewWord) - self.nextTimer.start() - - def startNewWord(self): - self.currentWord = self.pickWord() - self.scrambled = self.scrambleWord(self.currentWord) - self.master.bot.act_PRIVMSG(self.channel, "[Category: %s] Unscramble this: %s " % (self.category_name, self.scrambled)) - - self.clearTimer(self.hintTimer) - self.hintTimer = Timer(self.delayHint, self.giveHint) - self.hintTimer.start() - - def giveHint(self): - self.hintsGiven+=1 - - if self.hintsGiven>=len(self.currentWord) or self.hintsGiven > self.maxHints: - self.abortWord() - return - - blanks = "" - for letter in list(self.currentWord): - if letter == " ": - blanks+=" " - else: - blanks+="_" - partFromWord = self.currentWord[0:self.hintsGiven] - partFromBlanks = blanks[self.hintsGiven:] - hintstr = partFromWord+partFromBlanks - - self.master.bot.act_PRIVMSG(self.channel, "Hint: - %s" % (hintstr)) - - self.clearTimer(self.hintTimer) - self.hintTimer = Timer(self.delayHint, self.giveHint) - self.hintTimer.start() - - def abortWord(self): - cur = self.currentWord - self.currentWord = None - self.master.bot.act_PRIVMSG(self.channel, "Word expired - the answer was '%s'. Next word in %s seconds." % (cur, self.delayNext)) - self.hintsGiven = 0 - self.clearTimer(self.nextTimer) - - if self.guesses==0: - self.gamesWithoutGuesses+=1 - if self.gamesWithoutGuesses >= self.abortAfterNoGuesses: - self.master.bot.act_PRIVMSG(self.channel, "No one seems to be playing - type .scramble to start again.") - self.gameover() - return - else: - self.gamesWithoutGuesses=0 - - self.nextTimer = Timer(self.delayNext, self.startNewWord) - self.nextTimer.start() - - def catFileNameToStr(self, s): - s=s.split(".")[0] - s=s.replace("_", " ") - return s.title() - - def pickWord(self): - if self.should_change_category: - # clear flags - self.should_change_category = False - self.category_count = 0 - # Get the path to word files dir - dirpath = self.master.getFilePath("") - # List dir - files = os.listdir(dirpath) - # choose a random file - random.shuffle(files) - self.category_file = files[0] - self.category_name = self.catFileNameToStr(self.category_file) - # Process the name & announce - self.master.bot.act_PRIVMSG(self.channel, "The category is now: %s " % self.category_name) - # count lines - f = open(self.master.getFilePath(self.category_file), "r") - lines = 0 - while True: - lines+=1 - if f.readline() == "": - break - f.close() - # change category - picked = "" - while picked == "" or picked in self.lastwords: - - skip = random.randint(0, lines) - f = open(self.master.getFilePath(self.category_file), "r") - while skip>=0: - f.readline() - skip-=1 - picked = f.readline().strip().lower() - f.close() - - self.master.log.debug("DogeScramble: picked %s for %s" % (picked, self.channel)) - self.lastwords.append(picked) - if len(self.lastwords) > 5: - self.lastwords.pop(0) - return picked - - def scrambleWord(self, word): - scrambled = "" - for subword in word.split(" "): - scrambled+=self.scrambleIndividualWord(subword)+ " " - return scrambled.strip() - - def scrambleIndividualWord(self, word): - scrambled = list(word) - random.shuffle(scrambled) - return ''.join(scrambled).lower() diff --git a/pyircbot/modules/DogeWallet.py b/pyircbot/modules/DogeWallet.py deleted file mode 100644 index a70daf3..0000000 --- a/pyircbot/modules/DogeWallet.py +++ /dev/null @@ -1,164 +0,0 @@ -#!/usr/bin/env python -from modulebase import ModuleBase,ModuleHook -import time -import hashlib - -class DogeWallet(ModuleBase): - def __init__(self, bot, moduleName): - ModuleBase.__init__(self, bot, moduleName); - self.hooks=[ModuleHook("PRIVMSG", self.gotmsg)] - # Load attribute storage - self.attr = self.bot.getBestModuleForService("attributes") - # Load doge RPC - self.doge = self.bot.getBestModuleForService("dogerpc") - - def gotmsg(self, args, prefix, trailing): - channel = args[0] - if channel[0] == "#": - # Ignore channel messages - pass - else: - self.handlePm(args, prefix, trailing) - - def handlePm(self, args, prefix, trailing): - prefix = self.bot.decodePrefix(prefix) - cmd = self.bot.messageHasCommand(".setpass", trailing) - if cmd: - if len(cmd.args)==0: - self.bot.act_PRIVMSG(prefix.nick, ".setpass: usage: \".setpass newpass\" or \".setpass oldpass newpass\"") - else: - oldpass = self.attr.getAttribute(prefix.nick, "password") - if oldpass == None: - self.attr.setAttribute(prefix.nick, "password", cmd.args[0]) - self.bot.act_PRIVMSG(prefix.nick, ".setpass: Your password has been set to \"%s\"." % cmd.args[0]) - else: - if len(cmd.args)==2: - if cmd.args[0] == oldpass: - self.attr.setAttribute(prefix.nick, "password", cmd.args[1]) - self.bot.act_PRIVMSG(prefix.nick, ".setpass: Your password has been set to \"%s\"." % cmd.args[1]) - else: - self.bot.act_PRIVMSG(prefix.nick, ".setpass: Old password incorrect.") - else: - self.bot.act_PRIVMSG(prefix.nick, ".setpass: You must provide the old password when setting a new one.") - cmd = self.bot.messageHasCommand(".setdogeaddr", trailing) - if cmd: - userpw = self.attr.getAttribute(prefix.nick, "password") - if userpw==None: - self.bot.act_PRIVMSG(prefix.nick, ".setdogeaddr: You must first set a password with .setpass") - else: - if len(cmd.args)==2: - if userpw == cmd.args[0]: - self.attr.setAttribute(prefix.nick, "dogeaddr", cmd.args[1]) - self.bot.act_PRIVMSG(prefix.nick, ".setdogeaddr: Your doge address has been set to \"%s\"." % cmd.args[1]) - # if they don't have a wallet name, we'll make one now - if self.attr.getAttribute(prefix.nick, "dogeaccountname")==None: - randName = self.md5(str(time.time()))[0:10] - self.attr.setAttribute(prefix.nick, "dogeaccountname", randName) - - else: - self.bot.act_PRIVMSG(prefix.nick, ".setdogeaddr: incorrect password.") - else: - self.bot.act_PRIVMSG(prefix.nick, ".setdogeaddr: usage: \".setdogeaddr password address\" or \".setdogeaddr mypassword D8VNy3zkMGspffcFSWWqsxx7GrtVsmF2up\"") - - cmd = self.bot.messageHasCommand(".getdogebal", trailing) - if cmd: - userpw = self.attr.getAttribute(prefix.nick, "password") - if userpw==None: - self.bot.act_PRIVMSG(prefix.nick, ".getdogebal: You must first set a password with .setpass") - else: - if len(cmd.args)==1: - if userpw == cmd.args[0]: - ################# - walletname = self.attr.getAttribute(prefix.nick, "dogeaccountname") - amount = 0.0 - if walletname: - amount = self.doge.getBal(walletname) - - self.bot.act_PRIVMSG(prefix.nick, ".getdogebal: Your balance is: %s DOGE" % amount) - - ################# - else: - self.bot.act_PRIVMSG(prefix.nick, ".getdogebal: incorrect password.") - else: - self.bot.act_PRIVMSG(prefix.nick, ".getdogebal: usage: \".getdogebal password\"") - - cmd = self.bot.messageHasCommand(".withdrawdoge", trailing) - if cmd: - userpw = self.attr.getAttribute(prefix.nick, "password") - useraddr = self.attr.getAttribute(prefix.nick, "dogeaddr") - if userpw==None: - self.bot.act_PRIVMSG(prefix.nick, ".withdrawdoge: You must first set a password with .setpass") - elif useraddr==None: - self.bot.act_PRIVMSG(prefix.nick, ".withdrawdoge: You must first set a withdraw address .setdogeaddr") - else: - if len(cmd.args)==2: - if userpw == cmd.args[0]: - ################# - walletname = self.attr.getAttribute(prefix.nick, "dogeaccountname") - walletbal = self.doge.getBal(walletname) - - desiredAmount = float(cmd.args[1]) - - if walletbal >= desiredAmount: - txn = self.doge.send(walletname, useraddr, desiredAmount) - if txn: - self.bot.act_PRIVMSG(prefix.nick, ".withdrawdoge: %s DOGE sent to %s. Transaction ID: %s"% (desiredAmount, useraddr, txn)) - else: - self.bot.act_PRIVMSG(prefix.nick, ".withdrawdoge: Unable to create transaction. Please contact an Operator.") - else: - self.bot.act_PRIVMSG(prefix.nick, ".withdrawdoge: You only have %s DOGE. You cannot withdraw %s DOGE." % (walletbal, desiredAmount)) - ################# - else: - self.bot.act_PRIVMSG(prefix.nick, ".withdrawdoge: incorrect password.") - else: - self.bot.act_PRIVMSG(prefix.nick, ".withdrawdoge: usage: \".withdrawdoge password amount\" - \".withdrawdoge mypassword 5.0\" - ") - - cmd = self.bot.messageHasCommand(".getdepositaddr", trailing) - if cmd: - userpw = self.attr.getAttribute(prefix.nick, "password") - if userpw==None: - self.bot.act_PRIVMSG(prefix.nick, ".getdepositaddr: You must first set a password with .setpass") - else: - if len(cmd.args)==1: - if userpw == cmd.args[0]: - ################# - walletname = self.attr.getAttribute(prefix.nick, "dogeaccountname") - addr = self.doge.getAcctAddr(walletname) - self.bot.act_PRIVMSG(prefix.nick, ".getdepositaddr: Your deposit address is: %s" % addr) - ################# - else: - self.bot.act_PRIVMSG(prefix.nick, ".getdepositaddr: incorrect password.") - else: - self.bot.act_PRIVMSG(prefix.nick, ".getdepositaddr: usage: \".getdepositaddr password\"") - - - - cmd = self.bot.messageHasCommand(".login", trailing) - if cmd: - userpw = self.attr.getAttribute(prefix.nick, "password") - if userpw==None: - self.bot.act_PRIVMSG(prefix.nick, ".login: You must first set a password with .setpass") - else: - if len(cmd.args)==1: - if userpw == cmd.args[0]: - ################# - self.attr.setAttribute(prefix.nick, "loggedinfrom", prefix.hostname) - self.bot.act_PRIVMSG(prefix.nick, ".login: You have been logged in from: %s" % prefix.hostname) - ################# - else: - self.bot.act_PRIVMSG(prefix.nick, ".login: incorrect password.") - else: - self.bot.act_PRIVMSG(prefix.nick, ".login: usage: \".login password\"") - cmd = self.bot.messageHasCommand(".logout", trailing) - if cmd: - loggedin = self.attr.getAttribute(prefix.nick, "loggedinfrom") - if loggedin == None: - self.bot.act_PRIVMSG(prefix.nick, ".logout: You must first be logged in") - else: - self.attr.setAttribute(prefix.nick, "loggedinfrom", None) - self.bot.act_PRIVMSG(prefix.nick, ".logout: You have been logged out.") - - def md5(self, data): - m = hashlib.md5() - m.update(data.encode("ascii")) - return m.hexdigest() diff --git a/pyircbot/modules/NyanThread.py b/pyircbot/modules/NyanThread.py new file mode 100644 index 0000000..d25a25f --- /dev/null +++ b/pyircbot/modules/NyanThread.py @@ -0,0 +1,63 @@ +#!/usr/bin/env python +from modulebase import ModuleBase,ModuleHook +import re +from time import time +from urllib import request +from bs4 import BeautifulSoup +from bs4.element import Tag as bs_type_tag + +class NyanThread(ModuleBase): + def __init__(self, bot, moduleName): + ModuleBase.__init__(self, bot, moduleName); + self.hooks=[ModuleHook("PRIVMSG", self.check)] + self.lastrun = 0 + self.pagepattern = re.compile(r'([0-9]+)') + self.messagepattern = re.compile(r'([^<]+)', flags=re.IGNORECASE) + self.linkmessage = re.compile(r'') + + def check(self, args, prefix, trailing): + if not args[0][0]=="#": + return + cmd = self.bot.messageHasCommand(".story", trailing) + if cmd: + if time() - self.lastrun < 10: + return + + self.log.info("Nyanthread: fetching story...") + prefixObj = self.bot.decodePrefix(prefix) + page = request.urlopen("https://bitcointalk.org/index.php?topic=403335").read() + pages = self.pagepattern.findall(page.decode("ISO-8859-1")) + lastpage = pages[-1] + lastpagelink = "https://bitcointalk.org/index.php?topic=403335.%s" % lastpage[0] + self.log.info("Nyanthread: last page is %s" % lastpagelink) + page = request.urlopen(lastpagelink).read() + + bs = BeautifulSoup(page) + + body = bs.find('div', id="bodyarea") + thread = body.find('form', id="quickModForm") + posttable = thread.find('table', class_="bordercolor") + + postTrs = [] + for item in posttable: + postTrs.append(item) + + postTrs.reverse() + + for item in postTrs: + if type(item) == bs_type_tag: + message = item.find('div', class_="post") + if message: + redContent = self.messagepattern.findall(message.decode_contents()) + if len(redContent)>0: + linkmessage = self.linkmessage.findall(item.decode_contents()) + lastpagelink = "https://bitcointalk.org/index.php?topic=403335.msg%s#msg%s"%(linkmessage[0][0],linkmessage[0][0]) + if len(linkmessage)>75: + continue + self.bot.act_PRIVMSG(args[0], "%s: %s - %s" % (prefixObj.nick, redContent[0], lastpagelink)) + self.lastrun = time() + return + + self.bot.act_PRIVMSG(args[0], "%s: failed to read thread :(" % (prefixObj.nick)) + self.lastrun = time() + return diff --git a/pyircbot/modules/Seen.py b/pyircbot/modules/Seen.py new file mode 100644 index 0000000..412c676 --- /dev/null +++ b/pyircbot/modules/Seen.py @@ -0,0 +1,64 @@ +#!/usr/bin/env python +from modulebase import ModuleBase,ModuleHook +import sqlite3 +import time + +class Seen(ModuleBase): + def __init__(self, bot, moduleName): + ModuleBase.__init__(self, bot, moduleName) + self.hooks=[ModuleHook("PRIVMSG", self.lastSeen)] + self.loadConfig() + # if the database doesnt exist, it will be created + sql = self.getSql() + c=sql.cursor() + # check if our table exists + c.execute("SELECT * FROM SQLITE_MASTER WHERE `type`='table' AND `name`='seen'") + if len(c.fetchall())==0: + self.log.info("Seen: Creating database") + # if no, create it. + c.execute("CREATE TABLE `seen` (`nick` VARCHAR(32), `date` INTEGER, PRIMARY KEY(`nick`))"); + self.x = "asdf" + + def lastSeen(self, args, prefix, trailing): + # using a message to update last seen, also, the .seen query + prefixObj = self.bot.decodePrefix(prefix) + nick = prefixObj.nick + sql=self.getSql() + c = sql.cursor() + # update or add the user's row + datest=str( time.time()+(int(self.config["add_hours"])*60*60)) + c.execute("REPLACE INTO `seen` (`nick`, `date`) VALUES (?, ?)", (nick.lower(), datest )) + self.log.info("Seen: %s on %s" % (nick.lower(), datest)) + sql.commit() + if trailing.startswith(".seen"): + cmdargs = trailing.split(" "); + # query the DB for the user + if len(cmdargs)>=2: + searchnic = cmdargs[1].lower(); + c.execute("SELECT * FROM `seen` WHERE `nick`= ? ", [searchnic]) + rows = c.fetchall() + if len(rows)==1: + self.bot.act_PRIVMSG(args[0], "I last saw %s on %s (%s)."% (cmdargs[1], time.strftime("%m/%d/%y at %I:%M %p", time.localtime(rows[0]['date'])), self.config["timezone"])); + else: + self.bot.act_PRIVMSG(args[0], "Sorry, I haven't seen %s!" % cmdargs[1]) + c.close() + + def getSql(self): + # return a SQL reference to the database + path = self.getFilePath('database.sql3') + sql = sqlite3.connect(path); + sql.row_factory = self.dict_factory + return sql + + def dict_factory(self, cursor, row): + # because Lists suck for database results + d = {} + for idx, col in enumerate(cursor.description): + d[col[0]] = row[idx] + return d + + def test(self, arg): + print("TEST: %s" % arg) + print("self.x = %s" % self.x) + return arg +