Introducing nemubot v4 directories architecture
This commit is contained in:
parent
fabdbc7c47
commit
35ae6b6245
26 changed files with 102 additions and 86 deletions
78
bin/nemubot
Executable file
78
bin/nemubot
Executable file
|
|
@ -0,0 +1,78 @@
|
|||
#!/usr/bin/python3
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Nemubot is a modulable IRC bot, built around XML configuration files.
|
||||
# Copyright (C) 2012 Mercier Pierre-Olivier
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# 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 Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import sys
|
||||
import os
|
||||
import imp
|
||||
import traceback
|
||||
|
||||
from nemubot import Bot
|
||||
from nemubot import prompt
|
||||
from nemubot.prompt.builtins import load_file
|
||||
from nemubot import importer
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Create bot context
|
||||
context = Bot(0, "FIXME")
|
||||
|
||||
# Load the prompt
|
||||
prmpt = prompt.Prompt()
|
||||
|
||||
# Register the hook for futur import
|
||||
sys.meta_path.append(importer.ModuleFinder(context, prmpt))
|
||||
|
||||
#Add modules dir path
|
||||
if os.path.isdir("./modules/"):
|
||||
context.add_modules_path(
|
||||
os.path.realpath(os.path.abspath("./modules/")))
|
||||
|
||||
# Parse command line arguments
|
||||
if len(sys.argv) >= 2:
|
||||
for arg in sys.argv[1:]:
|
||||
if os.path.isdir(arg):
|
||||
context.add_modules_path(arg)
|
||||
else:
|
||||
load_file(arg, context)
|
||||
|
||||
print ("Nemubot v%s ready, my PID is %i!" % (context.version_txt,
|
||||
os.getpid()))
|
||||
while prmpt.run(context):
|
||||
try:
|
||||
# Reload context
|
||||
imp.reload(bot)
|
||||
context = bot.hotswap(context)
|
||||
# Reload prompt
|
||||
imp.reload(prompt)
|
||||
prmpt = prompt.hotswap(prmpt)
|
||||
# Reload all other modules
|
||||
bot.reload()
|
||||
print ("\033[1;32mContext reloaded\033[0m, now in Nemubot %s" %
|
||||
context.version_txt)
|
||||
except:
|
||||
print ("\033[1;31mUnable to reload the prompt due to errors.\033[0"
|
||||
"m Fix them before trying to reload the prompt.")
|
||||
exc_type, exc_value, exc_traceback = sys.exc_info()
|
||||
sys.stderr.write (traceback.format_exception_only(exc_type,
|
||||
exc_value)[0])
|
||||
|
||||
print ("\nWaiting for other threads shuts down...")
|
||||
|
||||
# Indeed, the server socket is waiting for receiving some data
|
||||
|
||||
sys.exit(0)
|
||||
186
bin/nemuspeak
Executable file
186
bin/nemuspeak
Executable file
|
|
@ -0,0 +1,186 @@
|
|||
#!/usr/bin/python3
|
||||
# coding=utf-8
|
||||
|
||||
import sys
|
||||
import signal
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
import traceback
|
||||
from datetime import datetime
|
||||
from datetime import timedelta
|
||||
import _thread
|
||||
|
||||
if len(sys.argv) <= 1:
|
||||
print ("This script takes exactly 1 arg: a XML config file")
|
||||
sys.exit(1)
|
||||
|
||||
def onSignal(signum, frame):
|
||||
print ("\nSIGINT receive, saving states and close")
|
||||
sys.exit (0)
|
||||
signal.signal(signal.SIGINT, onSignal)
|
||||
|
||||
if len(sys.argv) == 3:
|
||||
basedir = sys.argv[2]
|
||||
else:
|
||||
basedir = "./"
|
||||
|
||||
import xmlparser as msf
|
||||
import message
|
||||
import IRCServer
|
||||
|
||||
SMILEY = list()
|
||||
CORRECTIONS = list()
|
||||
g_queue = list()
|
||||
talkEC = 0
|
||||
stopSpk = 0
|
||||
lastmsg = None
|
||||
|
||||
def speak(endstate):
|
||||
global lastmsg, g_queue, talkEC, stopSpk
|
||||
talkEC = 1
|
||||
stopSpk = 0
|
||||
|
||||
if lastmsg is None:
|
||||
lastmsg = message.Message(b":Quelqun!someone@p0m.fr PRIVMSG channel nothing", datetime.now())
|
||||
|
||||
while not stopSpk and len(g_queue) > 0:
|
||||
srv, msg = g_queue.pop(0)
|
||||
lang = "fr"
|
||||
sentence = ""
|
||||
force = 0
|
||||
|
||||
#Skip identic body
|
||||
if msg.content == lastmsg.content:
|
||||
continue
|
||||
|
||||
if force or msg.time - lastmsg.time > timedelta(0, 500):
|
||||
sentence += "A {0} heure {1} : ".format(msg.time.hour, msg.time.minute)
|
||||
force = 1
|
||||
|
||||
if force or msg.channel != lastmsg.channel:
|
||||
if msg.channel == srv.owner:
|
||||
sentence += "En message priver. " #Just to avoid é :p
|
||||
else:
|
||||
sentence += "Sur " + msg.channel + ". "
|
||||
force = 1
|
||||
|
||||
action = 0
|
||||
if msg.content.find("ACTION ") == 1:
|
||||
sentence += msg.nick + " "
|
||||
msg.content = msg.content.replace("ACTION ", "")
|
||||
action = 1
|
||||
for (txt, mood) in SMILEY:
|
||||
if msg.content.find(txt) >= 0:
|
||||
sentence += msg.nick + (" %s : "%mood)
|
||||
msg.content = msg.content.replace(txt, "")
|
||||
action = 1
|
||||
break
|
||||
|
||||
for (bad, good) in CORRECTIONS:
|
||||
if msg.content.find(bad) >= 0:
|
||||
msg.content = (" " + msg.content + " ").replace(bad, good)
|
||||
|
||||
if action == 0 and (force or msg.sender != lastmsg.sender):
|
||||
sentence += msg.nick + " dit : "
|
||||
|
||||
if re.match(".*(https?://)?(www\\.)?ycc.fr/[a-z0-9A-Z]+.*", msg.content) is not None:
|
||||
msg.content = re.sub("(https?://)?(www\\.)?ycc.fr/[a-z0-9A-Z]+", " U.R.L Y.C.C ", msg.content)
|
||||
|
||||
if re.match(".*https?://.*", msg.content) is not None:
|
||||
msg.content = re.sub(r'https?://[^ ]+', " U.R.L ", msg.content)
|
||||
|
||||
if re.match("^ *[^a-zA-Z0-9 ][a-zA-Z]{2}[^a-zA-Z0-9 ]", msg.content) is not None:
|
||||
if sentence != "":
|
||||
intro = subprocess.call(["espeak", "-v", "fr", "--", sentence])
|
||||
#intro.wait()
|
||||
|
||||
lang = msg.content[1:3].lower()
|
||||
sentence = msg.content[4:]
|
||||
else:
|
||||
sentence += msg.content
|
||||
|
||||
spk = subprocess.call(["espeak", "-v", lang, "--", sentence])
|
||||
#spk.wait()
|
||||
|
||||
lastmsg = msg
|
||||
|
||||
if not stopSpk:
|
||||
talkEC = endstate
|
||||
else:
|
||||
talkEC = 1
|
||||
|
||||
|
||||
class Server(IRCServer.IRCServer):
|
||||
def treat_msg(self, line, private = False):
|
||||
global stopSpk, talkEC, g_queue
|
||||
try:
|
||||
msg = message.Message (line, datetime.now(), private)
|
||||
if msg.cmd == 'PING':
|
||||
self.send_pong(msg.content)
|
||||
elif msg.cmd == 'PRIVMSG' and self.accepted_channel(msg.channel):
|
||||
if msg.nick != self.owner:
|
||||
g_queue.append((self, msg))
|
||||
if talkEC == 0:
|
||||
_thread.start_new_thread(speak, (0,))
|
||||
elif msg.content[0] == "`" and len(msg.content) > 1:
|
||||
msg.cmds = msg.cmds[1:]
|
||||
if msg.cmds[0] == "speak":
|
||||
_thread.start_new_thread(speak, (0,))
|
||||
elif msg.cmds[0] == "reset":
|
||||
while len(g_queue) > 0:
|
||||
g_queue.pop()
|
||||
elif msg.cmds[0] == "save":
|
||||
if talkEC == 0:
|
||||
talkEC = 1
|
||||
stopSpk = 1
|
||||
elif msg.cmds[0] == "add":
|
||||
self.channels.append(msg.cmds[1])
|
||||
print (cmd[1] + " added to listened channels")
|
||||
elif msg.cmds[0] == "del":
|
||||
if self.channels.count(msg.cmds[1]) > 0:
|
||||
self.channels.remove(msg.cmds[1])
|
||||
print (msg.cmds[1] + " removed from listened channels")
|
||||
else:
|
||||
print (cmd[1] + " not in listened channels")
|
||||
except:
|
||||
print ("\033[1;31mERROR:\033[0m occurred during the processing of the message: %s" % line)
|
||||
exc_type, exc_value, exc_traceback = sys.exc_info()
|
||||
traceback.print_exception(exc_type, exc_value, exc_traceback)
|
||||
|
||||
|
||||
config = msf.parse_file(sys.argv[1])
|
||||
|
||||
for smiley in config.getNodes("smiley"):
|
||||
if smiley.hasAttribute("txt") and smiley.hasAttribute("mood"):
|
||||
SMILEY.append((smiley.getAttribute("txt"), smiley.getAttribute("mood")))
|
||||
print ("%d smileys loaded"%len(SMILEY))
|
||||
|
||||
for correct in config.getNodes("correction"):
|
||||
if correct.hasAttribute("bad") and correct.hasAttribute("good"):
|
||||
CORRECTIONS.append((" " + (correct.getAttribute("bad") + " "), (" " + correct.getAttribute("good") + " ")))
|
||||
print ("%d corrections loaded"%len(CORRECTIONS))
|
||||
|
||||
for serveur in config.getNodes("server"):
|
||||
srv = Server(serveur, config["nick"], config["owner"], config["realname"], serveur.hasAttribute("ssl"))
|
||||
srv.launch(None)
|
||||
|
||||
def sighup_h(signum, frame):
|
||||
global talkEC, stopSpk
|
||||
sys.stdout.write ("Signal reçu ... ")
|
||||
if os.path.exists("/tmp/isPresent"):
|
||||
_thread.start_new_thread(speak, (0,))
|
||||
print ("Morning!")
|
||||
else:
|
||||
print ("Sleeping!")
|
||||
if talkEC == 0:
|
||||
talkEC = 1
|
||||
stopSpk = 1
|
||||
signal.signal(signal.SIGHUP, sighup_h)
|
||||
|
||||
print ("Nemuspeak ready, waiting for new messages...")
|
||||
prompt=""
|
||||
while prompt != "quit":
|
||||
prompt=sys.stdin.readlines ()
|
||||
|
||||
sys.exit(0)
|
||||
Loading…
Add table
Add a link
Reference in a new issue