Starting rebuild of eventsm watchSite and YouTube modules

This commit is contained in:
Némunaire 2012-06-16 22:41:17 +02:00
commit 5fed225358
3 changed files with 0 additions and 0 deletions

304
modules/events.py Normal file
View file

@ -0,0 +1,304 @@
# coding=utf-8
import re
import sys
from datetime import timedelta
from datetime import datetime
from datetime import date
import time
import threading
from xml.dom.minidom import parse
from xml.dom.minidom import parseString
from xml.dom.minidom import getDOMImplementation
import imodule
class Manager(threading.Thread):
def __init__(self, servers):
self.servers = servers
self.stop = False
threading.Thread.__init__(self)
def run(self):
global STREND
while not self.stop:
newStrendEvt.clear()
closer = None
#Gets the closer event
for evt in STREND.keys():
if ((closer is None or closer.end is None) or (STREND[evt].end is not None and STREND[evt].end < closer.end)) and STREND[evt].end is not None and STREND[evt].end > datetime.now():
closer = STREND[evt]
if closer is not None and closer.end is not None:
#print ("Closer: %s à %s"%(closer.name, closer.end))
timeleft = (closer.end - datetime.now()).seconds
timer = threading.Timer(timeleft, closer.alertEnd, (self.servers,))
timer.start()
#print ("Start timer (%ds)"%timeleft)
newStrendEvt.wait()
if closer is not None and closer.end is not None and closer.end > datetime.now():
timer.cancel()
class Strend:
def __init__(self, item):
if item is not None:
self.name = item.getAttribute("name")
self.start = datetime.fromtimestamp (time.mktime (time.strptime (item.getAttribute("start")[:19], "%Y-%m-%d %H:%M:%S")))
self.proprio = item.getAttribute("proprio")
self.server = item.getAttribute("server")
self.channel = item.getAttribute("channel")
if item.getAttribute("end") is not None and item.getAttribute("end") != "":
try:
self.end = datetime.fromtimestamp (time.mktime (time.strptime (item.getAttribute("end")[:19], "%Y-%m-%d %H:%M:%S")))
except:
self.end = None
else:
self.end = None
else:
self.start = datetime.now()
self.end = None
def alertEnd(self, SRVS):
for server in SRVS.keys():
if server == self.server:
if self.channel == SRVS[server].nick:
SRVS[server].send_msg_usr(self.proprio, "%s: %s arrivé à échéance."%(self.proprio, self.name))
else:
SRVS[server].send_msg(self.channel, "%s: %s arrivé à échéance."%(self.proprio, self.name))
del STREND[self.name]
newStrendEvt.set()
class Nemodule(imodule.ModuleBase):
filename = ""
events = dict()
strend = dict()
threadManager = None
newStrendEvt = threading.Event()
def launch (self, servers):
self.stop()
self.threadManager = Manager(servers)
self.threadManager.start()
def stop (self):
if self.threadManager is not None:
self.threadManager.stop = True
self.newStrendEvt.set()
def xmlparse(self, node):
"""Parse the given node and add events to the global list."""
for item in node.getElementsByTagName("strend"):
strend[item.getAttribute("name")] = Strend(item)
for item in node.getElementsByTagName("event"):
if (item.hasAttribute("year")):
year = int(item.getAttribute("year"))
else:
year = 0
if (item.hasAttribute("month")):
month = int(item.getAttribute("month"))
else:
month = 0
if (item.hasAttribute("day")):
day = int(item.getAttribute("day"))
else:
day = 0
if (item.hasAttribute("hour")):
hour = int(item.getAttribute("hour"))
else:
hour = 0
if (item.hasAttribute("minute")):
minute = int(item.getAttribute("minute"))
else:
minute = 0
if (item.hasAttribute("second")):
second = int(item.getAttribute("second"))
else:
second = 0
if year == month == day == hour == minute == second == 0:
events[item.getAttribute("name")] = (None, item.getAttribute("before_after"), None)
else:
events[item.getAttribute("name")] = (datetime(year, month, day, hour, minute, second),item.getAttribute("msg_before"), item.getAttribute("msg_after"))
def load_module(datas_path):
"""Load this module"""
global EVENTS, STREND, filename
EVENTS = {}
STREND = {}
filename = datas_path + "/events.xml"
sys.stdout.write ("Loading events ... ")
dom = parse(filename)
xmlparse (dom.getElementsByTagName('events')[0])
print ("done (%d loaded)" % len(EVENTS))
def save_module():
"""Save the dates"""
global filename
sys.stdout.write ("Saving events ... ")
impl = getDOMImplementation()
newdoc = impl.createDocument(None, 'events', None)
top = newdoc.documentElement
for name in STREND.keys():
iend = ""
if STREND[name].end is not None:
iend = ' end="%s"'%STREND[name].end
item = parseString ('<strend name="%s" start="%s" proprio="%s" server="%s" channel="%s"%s />' % (name, STREND[name].start, STREND[name].proprio, STREND[name].server, STREND[name].channel, iend)).documentElement
top.appendChild(item);
for name in EVENTS.keys():
(day, msg_before, msg_after) = EVENTS[name]
bonus=""
if day is None:
item = parseString ('<event name="%s" msg_before="%s" />' % (name, msg_before)).documentElement
else:
if day.hour != 0:
bonus += 'hour="%s" ' % day.hour
if day.minute != 0:
bonus += 'minute="%s" ' % day.minute
if day.second != 1:
bonus += 'second="%s" ' % day.second
item = parseString ('<event name="%s" year="%d" month="%d" day="%d" %s msg_after="%s" msg_before="%s" />' % (name, day.year, day.month, day.day, bonus, msg_after, msg_before)).documentElement
top.appendChild(item);
with open(filename, "w") as f:
newdoc.writexml (f)
print ("done")
def help_tiny ():
"""Line inserted in the response to the command !help"""
return "events manager"
def help_full ():
return "This module store a lot of events: ny, we, vacs, " + (", ".join(EVENTS.keys())) + "\n!eventslist: gets list of timer\n!start /something/: launch a timer"
def parseanswer(msg):
global STREND
if msg.cmd[0] == "we" or msg.cmd[0] == "week-end" or msg.cmd[0] == "weekend":
ndate = datetime.today() + timedelta(5 - datetime.today().weekday())
ndate = datetime(ndate.year, ndate.month, ndate.day, 0, 0, 1)
msg.send_chn (
msg.countdown_format (ndate,
"Il reste %s avant le week-end, courrage ;)",
"Youhou, on est en week-end depuis %s."))
return True
elif msg.cmd[0] == "new-year" or msg.cmd[0] == "newyear" or msg.cmd[0] == "ny":
msg.send_chn (
msg.countdown_format (datetime(datetime.today().year + 1, 1, 1, 0, 0, 1),
"Il reste %s avant la nouvelle année.",
"Nous faisons déjà la fête depuis %s !"))
return True
elif msg.cmd[0] == "vacances" or msg.cmd[0] == "vacs" or msg.cmd[0] == "holiday" or msg.cmd[0] == "holidays":
msg.send_chn (
msg.countdown_format (datetime(2012, 7, 30, 18, 0, 1),
"Il reste %s avant les vacances :)",
"Profitons, c'est les vacances depuis %s."))
return True
elif msg.cmd[0] == "start" and len(msg.cmd) > 1:
if msg.cmd[1] not in STREND:
STREND[msg.cmd[1]] = Strend(None)
STREND[msg.cmd[1]].server = msg.srv.id
STREND[msg.cmd[1]].channel = msg.channel
STREND[msg.cmd[1]].proprio = msg.sender
STREND[msg.cmd[1]].name = msg.cmd[1]
if len(msg.cmd) > 2:
result = re.match("([0-9]+)([smhdjSMHDJ])?", msg.cmd[2])
if result is not None:
try:
if result.group(2) is not None and (result.group(2) == "m" or result.group(2) == "M"):
STREND[msg.cmd[1]].end = datetime.now() + timedelta(minutes=int(result.group(1)))
elif result.group(2) is not None and (result.group(2) == "h" or result.group(2) == "H"):
STREND[msg.cmd[1]].end = datetime.now() + timedelta(hours=int(result.group(1)))
elif result.group(2) is not None and (result.group(2) == "d" or result.group(2) == "D" or result.group(2) == "j" or result.group(2) == "J"):
STREND[msg.cmd[1]].end = datetime.now() + timedelta(days=int(result.group(1)))
else:
STREND[msg.cmd[1]].end = datetime.now() + timedelta(seconds=int(result.group(1)))
newStrendEvt.set()
msg.send_snd ("%s commencé le %s et se terminera le %s."% (msg.cmd[1], datetime.now(), STREND[msg.cmd[1]].end))
except:
msg.send_snd ("Impossible de définir la fin de %s."% (msg.cmd[1]))
msg.send_snd ("%s commencé le %s."% (msg.cmd[1], datetime.now()))
else:
msg.send_snd ("%s commencé le %s"% (msg.cmd[1], datetime.now()))
else:
msg.send_snd ("%s existe déjà."% (msg.cmd[1]))
elif (msg.cmd[0] == "end" or msg.cmd[0] == "forceend") and len(msg.cmd) > 1:
if msg.cmd[1] in STREND:
msg.send_chn ("%s a duré %s." % (msg.cmd[1], msg.just_countdown(datetime.now () - STREND[msg.cmd[1]].start)))
if STREND[msg.cmd[1]].proprio == msg.sender or (msg.cmd[0] == "forceend" and msg.sender == msg.srv.owner):
del STREND[msg.cmd[1]]
newStrendEvt.set()
else:
msg.send_snd ("Vous ne pouvez pas terminer le compteur %s, créé par %s."% (msg.cmd[1], STREND[msg.cmd[1]].proprio))
else:
msg.send_snd ("%s n'est pas un compteur connu."% (msg.cmd[1]))
elif msg.cmd[0] == "eventslist" or msg.cmd[0] == "eventlist" or msg.cmd[0] == "eventsliste" or msg.cmd[0] == "eventliste":
msg.send_snd ("Compteurs connus : %s." % ", ".join(STREND.keys()))
elif msg.cmd[0] in STREND:
msg.send_chn ("%s commencé il y a %s." % (msg.cmd[0], msg.just_countdown(datetime.now () - STREND[msg.cmd[0]].start)))
elif msg.cmd[0] in EVENTS:
(day, msg_before, msg_after) = EVENTS[msg.cmd[0]]
if day is None:
msg.send_chn (msg_before)
else:
msg.send_chn (msg.countdown_format (day, msg_before, msg_after))
return True
else:
return False
def parseask(msg):
msgl = msg.content.lower ()
if re.match("^.*((create|new) +(a|an|a +new|an *other)? *(events?|commande?)|(nouvel(le)?|ajoute|cr[ée]{1,3}) +(un)? *([eé]v[ée]nements?|commande?)).*$", msgl) is not None:
name = re.match("^.*!([^ \"'@!]+).*$", msg.content)
if name is not None and name.group (1) not in EVENTS:
texts = re.match("^[^\"]*(avant|après|apres|before|after)?[^\"]*\"([^\"]+)\"[^\"]*((avant|après|apres|before|after)?.*\"([^\"]+)\".*)?$", msg.content)
if texts is not None and texts.group (3) is not None:
extDate = msg.extractDate ()
if extDate is None or extDate == "":
msg.send_snd ("La date de l'événement est invalide...")
else:
if texts.group (1) is not None and (texts.group (1) == "après" or texts.group (1) == "apres" or texts.group (1) == "after"):
msg_after = texts.group (2)
msg_before = texts.group (5)
if (texts.group (4) is not None and (texts.group (4) == "après" or texts.group (4) == "apres" or texts.group (4) == "after")) or texts.group (1) is None:
msg_before = texts.group (2)
msg_after = texts.group (5)
if msg_before.find ("%s") != -1 and msg_after.find ("%s") != -1:
EVENTS[name.group (1)] = (extDate, msg_before, msg_after)
save_module ()
msg.send_snd ("Nouvel événement !%s ajouté avec succès."%name.group (1))
else:
msg.send_snd ("Pour que l'événement soit valide, ajouter %s à l'endroit où vous voulez que soit ajouté le compte à rebours.")
elif texts is not None and texts.group (2) is not None:
EVENTS[name.group (1)] = (None, texts.group (2), None)
save_module ()
msg.send_snd ("Nouvelle commande !%s ajoutée avec succès."%name.group (1))
else:
msg.send_snd ("Veuillez indiquez les messages d'attente et d'après événement entre guillemets.")
elif name is None:
msg.send_snd ("Veuillez attribuer une commande à l'événement.")
else:
msg.send_snd ("Un événement portant ce nom existe déjà.")
return False
def parselisten (msg):
return False

219
modules/watchWebsite.py Normal file
View file

@ -0,0 +1,219 @@
# coding=utf-8
import http.client
import hashlib
import sys
import traceback
import socket
import time
import base64
import _thread
from urllib.parse import unquote
from xml.dom.minidom import parse
from xml.dom.minidom import parseString
from xml.dom.minidom import getDOMImplementation
import atom
import youtube
filename = ""
SITES = []
SRVS = None
class Site:
def __init__(self, item):
self.server = item.getAttribute("server")
self.page = item.getAttribute("page")
if item.getAttribute("type"):
self.type = item.getAttribute("type")
else:
self.type = "hash"
self.message = item.getAttribute("message")
self.thread = None
if item.getAttribute("time"):
self.updateTime = int(item.getAttribute("time"))
else:
self.updateTime = 60
self.lastChange = 0
self.lastpage = None
self.run = True
self.channels = list()
for channel in item.getElementsByTagName('channel'):
self.channels.append(channel.getAttribute("name"))
self.categories = dict()
for category in item.getElementsByTagName('category'):
self.categories[category.getAttribute("term")] = category.getAttribute("part")
def start (self):
self.thread = _thread.start_new_thread (startThread, (self,))
def send_message (self, msg):
global SRVS
if len(self.channels) > 0:
for server in SRVS.keys():
for chan in self.channels:
SRVS[server].send_msg (chan, msg)
else:
for server in SRVS.keys():
SRVS[server].send_global (msg)
def treat_atom (self, content):
change=False
f = atom.Atom (content)
if self.lastpage is not None:
diff = self.lastpage.diff (f)
if len(diff) > 0:
print ("[%s] Page differ!"%self.server)
diff.reverse()
for d in diff:
if self.message.count("%s") == 2 and len(self.categories) > 0:
if d.category is None or d.category not in self.categories:
messageI = self.message % (self.categories[""], "%s")
else:
messageI = self.message % (self.categories[d.category], "%s")
self.send_message (messageI % unquote (d.link))
elif self.message.count("%s") == 2:
if f.id == youtube.idAtom:
youtube.send_global (d.link2, self.message % (d.title, unquote (d.link)))
else:
self.send_message (self.message % (d.title, unquote (d.link)))
elif self.message.count("%s") == 1:
self.send_message(self.message % unquote (d.title))
else:
self.send_message(self.message)
change=True
return (f, change)
def check (self):
while self.run:
try:
#print ("Check %s/%s"%(self.server, self.page))
content = getPage(self.server, self.page)
if content is None:
return
if self.type == "atom":
(self.lastpage, change) = self.treat_atom (content)
if change:
if self.lastChange <= 0:
self.lastChange -= 1
else:
self.lastChange = 0
else:
self.lastChange += 1
else:
hash = hashlib.sha224(content).hexdigest()
if hash != self.lastpage:
if self.lastpage is not None:
self.send_message (self.message)
self.lastpage = hash
if self.lastChange <= 0:
self.lastChange -= 1
else:
self.lastChange = 0
else:
self.lastChange += 1
#Update check time intervalle
#TODO
if self.updateTime < 10:
self.updateTime = 10
if self.updateTime > 400:
self.updateTime = 400
time.sleep(self.updateTime)
except:
print ("Une erreur est survenue lors de la récupération de la page " + self.server + "/" + self.page)
exc_type, exc_value, exc_traceback = sys.exc_info()
traceback.print_exception(exc_type, exc_value, exc_traceback)
time.sleep(self.updateTime * 3)
def load_module(datas_path):
"""Load this module"""
global SITES, filename
SITES = []
filename = datas_path + "/watch.xml"
sys.stdout.write ("Loading watchsites ... ")
dom = parse(filename)
for item in dom.documentElement.getElementsByTagName("watch"):
SITES.append (Site (item))
print ("done (%d loaded)" % len(SITES))
def launch (servers):
global SRVS
SRVS = servers
for site in SITES:
site.start ()
def stop():
return
def save_module():
"""Save the module state"""
global filename
sys.stdout.write ("Saving watched sites ... ")
impl = getDOMImplementation()
newdoc = impl.createDocument(None, 'service', None)
top = newdoc.documentElement
for site in SITES:
item = parseString ('<watch server="%s" page="%s" message="%s" type="%s" time="%d" />' % (site.server, site.page, site.message, site.type, site.updateTime)).documentElement
if len(site.channels) > 0:
for chan in site.channels:
item.appendChild(parseString ('<channel name="%s" />' % (chan)).documentElement);
if len(site.categories) > 0:
for categ in site.categories.keys():
item.appendChild(parseString ('<category term="%s" part="%s"/>' % (categ, site.categories[categ])).documentElement);
#print (site.server)
top.appendChild(item);
with open(filename, "w") as f:
newdoc.writexml (f)
print ("done")
def help_tiny ():
"""Line inserted in the response to the command !help"""
return "Alert on changes on websites"
def help_full ():
return "This module is autonomous you can't interract with it."
def parseanswer (msg):
if msg.cmd[0] == "watch":
print ("print states here")
return True
return False
def parseask (msg):
return False
def parselisten (msg):
return False
def getPage (s, p):
conn = http.client.HTTPConnection(s)
try:
conn.request("GET", "/%s"%(p))
except socket.gaierror:
print ("[%s] impossible de récupérer la page %s."%(s, p))
return None
res = conn.getresponse()
data = res.read()
conn.close()
return data
def startThread(site):
site.check ()

51
modules/youtube.py Normal file
View file

@ -0,0 +1,51 @@
# coding=utf-8
import re
import http.client
idAtom = "http://musik.p0m.fr/atom.php?nemubot"
URLS = dict ()
def load_module(datas_path):
"""Load this module"""
global URLS
URLS = dict ()
def save_module():
"""Save the dates"""
return
def help_tiny ():
"""Line inserted in the response to the command !help"""
return "music extractor"
def help_full ():
return "To launch a convertion task, juste paste a youtube link (or compatible service) and wait for nemubot answer!"
def parseanswer(msg):
return False
def parseask(msg):
return False
def parselisten (msg):
global URLS
matches = [".*(http://(www\.)?youtube.com/watch\?v=([a-zA-Z0-9_-]{11})).*",
".*(http://(www\.)?youtu.be/([a-zA-Z0-9_-]{11})).*"]
for m in matches:
res = re.match (m, msg.content)
if res is not None:
#print ("seen : %s"%res.group(1))
URLS[res.group(1)] = msg
conn = http.client.HTTPConnection("musik.p0m.fr")
conn.request("GET", "/?nemubot&a=add&url=%s"%(res.group (1)))
conn.getresponse()
conn.close()
return True
return False
def send_global (origin, msg):
if origin in URLS:
URLS[origin].send_chn (msg)
del URLS[origin]