]>
gitweb.pimeys.fr Git - bots/bbc.git/blob - skeleton.py
e04be5d36de6d71b6d29187d2eecff6c2b1011d2
2 # -*- encoding: utf-8 -*-
6 # Un bot IRC qui ne fait rien. Base pour en coder un autre.
13 import socket
, ssl
, json
17 from commands
import getstatusoutput
as ex
19 # on récupère la config
24 def get_config_logfile(serveur
):
25 serveurs
={"acoeur.crans.org":"acoeur","irc.crans.org":"crans"}
26 return config
.logfile_template
%(serveurs
[serveur
])
29 return ex("ls -s %s"%(config
.thisfile
))[1].split()[0]
31 def log(serveur
,channel
,auteur
=None,message
=None):
32 f
=open(get_config_logfile(serveur
),"a")
33 if auteur
==message
==None:
34 # alors c'est que c'est pas un channel mais juste une ligne de log
35 chain
="%s %s"%(time
.strftime("%F %T"),channel
)
37 chain
="%s [%s:%s] %s"%(time
.strftime("%F %T"),channel
,auteur
,message
)
39 if config
.debug_stdout
:
43 def is_something(chain
,matches
,avant
=u
".*(?:^| )",apres
=u
"(?:$|\.| |,|;).*",case_sensitive
=False,debug
=False):
45 chain
=unicode(chain
,"utf8")
47 chain
=unicode(chain
,"utf8").lower()
48 allmatches
="("+"|".join(matches
)+")"
49 reg
=(avant
+allmatches
+apres
).lower()
53 def is_insult(chain
,debug
=True):
54 return is_something(chain
,config
.insultes
,avant
=".*(?:^| |')")
55 def is_not_insult(chain
):
56 chain
=unicode(chain
,"utf8")
57 insult_regexp
=u
"("+u
"|".join(config
.insultes
)+u
")"
58 middle_regexp
=u
"(une? (?:(?:putain|enfoiré) d(?:e |'))*|)(?:| super )(?: (?:gros|petit|grand|énorme) |)"
59 reg
=".*pas %s%s.*"%(middle_regexp
,insult_regexp
)
60 if re
.match(reg
,chain
):
64 def is_compliment(chain
,debug
=True):
65 return is_something(chain
,config
.compliment_triggers
,avant
=".*(?:^| |')")
67 return is_something(chain
,config
.tag_triggers
)
69 return is_something(chain
,config
.tesla_triggers
,avant
=u
"^",apres
=u
"$",debug
=True)
71 return is_something(chain
,config
.merci_triggers
)
73 return is_something(chain
,config
.tamere_triggers
)
74 def is_bad_action_trigger(chain
,pseudo
):
75 return is_something(chain
,config
.bad_action_triggers
,avant
=u
"^",
76 apres
="(?: [a-z]*ment)? %s($|\.| |,|;).*"%(pseudo))
77 def is_good_action_trigger(chain
,pseudo
):
78 return is_something(chain
,config
.good_action_triggers
,avant
=u
"^",
79 apres
="(?: [a-z]*ment)? %s($|\.| |,|;).*"%(pseudo))
80 def is_bonjour(chain
):
81 return is_something(chain
,config
.bonjour_triggers
,avant
=u
"^")
82 def is_bonne_nuit(chain
):
83 return is_something(chain
,config
.bonne_nuit_triggers
,avant
=u
"^")
85 return re
.match(u
"^(pan|bim|bang)( .*)?$",unicode(chain
,"utf8").lower().strip())
88 _
,_
,_
,h
,m
,s
,_
,_
,_
=time
.localtime()
89 return (conf
[0],0,0)<(h
,m
,s
)<(conf
[1],0,0)
91 return is_time(config
.daytime
)
93 return is_time(config
.nighttime
)
96 class UnicodeBotError(Exception):
98 def bot_unicode(chain
):
100 unicode(chain
,"utf8")
101 except UnicodeDecodeError as exc
:
102 raise UnicodeBotError
104 class Skeleton(ircbot
.SingleServerIRCBot
):
105 def __init__(self
,serveur
,debug
=False):
106 temporary_pseudo
=config
.irc_pseudo
+str(random
.randrange(10000,100000))
107 ircbot
.SingleServerIRCBot
.__init
__(self
, [(serveur
, 6667)],
108 temporary_pseudo
,"Ceci est l'ircname du bot", 10)
111 self
.overops
=config
.overops
112 self
.ops
=self
.overops
+config
.ops
113 self
.chanlist
=config
.chanlist
114 self
.stay_channels
=config
.stay_channels
115 self
.quiet_channels
=config
.quiet_channels
118 def give_me_my_pseudo(self
,serv
):
119 serv
.privmsg("NickServ","RECOVER %s %s"%(config
.irc_pseudo
,config
.irc_password
))
120 serv
.privmsg("NickServ","RELEASE %s %s"%(config
.irc_pseudo
,config
.irc_password
))
122 serv
.nick(config
.irc_pseudo
)
124 def on_welcome(self
, serv
, ev
):
125 self
.serv
=serv
# ça serv ira :)
126 self
.give_me_my_pseudo(serv
)
127 serv
.privmsg("NickServ","identify %s"%(config
.irc_password
))
128 log(self
.serveur
,"Connected")
130 self
.chanlist
=["#bot"]
131 for c
in self
.chanlist
:
132 log(self
.serveur
,"JOIN %s"%(c))
135 def pourmoi(self
, serv
, message
):
136 """renvoie (False,lemessage) ou (True, le message amputé de "pseudo: ")"""
139 if message
[:size
]==pseudo
and len(message
)>size
and message
[size
]==":":
140 return (True,message
[size
+1:].lstrip(" "))
142 return (False,message
)
144 def on_privmsg(self
, serv
, ev
):
145 message
=ev
.arguments()[0]
146 auteur
= irclib
.nm_to_n(ev
.source())
148 test
=bot_unicode(message
)
149 except UnicodeBotError
:
150 if config
.utf8_trigger
:
151 serv
.privmsg(auteur
, random
.choice(config
.utf8_fail_answers
).encode("utf8"))
153 message
=message
.split()
154 cmd
=message
[0].lower()
157 helpdico
={"help":["""HELP <commande>
158 Affiche de l'aide sur la commande""",None,None],
159 "join": [None, """JOIN <channel>
160 Me fait rejoindre le channel""",None],
161 "leave": [None,"""LEAVE <channel>
162 Me fait quitter le channel (sauf s'il est dans ma stay_list).""",None],
163 "quiet": [None,"""QUIET <channel>
164 Me rend silencieux sur le channel.""",None],
165 "noquiet": [None,"""NOQUIET <channel>
166 Me rend la parole sur le channel.""",None],
167 "lost": [None,"""LOST <channel>
168 Me fait perdre sur le channel.""",None],
169 "say": [None,None,"""SAY <channel> <message>
170 Me fait parler sur le channel."""],
171 "do": [None,None,"""DO <channel> <action>
172 Me fait faitre une action (/me) sur le channel."""],
173 "stay": [None,None,"""STAY <channel>
174 Ajoute le channel à ma stay_list."""],
175 "nostay": [None,None,"""NOSTAY <channel>
176 Retire le channel de ma stay_list."""],
177 "ops": [None,None,"""OPS
178 Affiche la liste des ops."""],
179 "overops": [None,None,"""OVEROPS
180 Affiche la liste des overops."""],
181 "kick": [None,None,"""KICK <channel> <pseudo> [<raison>]
182 Kicke <pseudo> du channel (Il faut bien entendu que j'y sois op)."""],
183 "die": [None,None,"""DIE
184 Me déconnecte du serveur IRC."""]
186 helpmsg_default
="Liste des commandes disponibles :\nHELP"
187 helpmsg_ops
=" JOIN LEAVE QUIET NOQUIET LOST RECONNECT"
188 helpmsg_overops
=" SAY DO STAY NOSTAY OPS OVEROPS KICK DIE"
189 op
,overop
=auteur
in self
.ops
, auteur
in self
.overops
191 helpmsg
=helpmsg_default
195 helpmsg
+=helpmsg_overops
197 helpmsgs
=helpdico
.get(message
[1].lower(),["Commande inconnue.",None,None])
199 if op
and helpmsgs
[1]:
201 helpmsg
+="\n"+helpmsgs
[1]
204 if overop
and helpmsgs
[2]:
206 helpmsg
+="\n"+helpmsgs
[2]
209 for ligne
in helpmsg
.split("\n"):
210 serv
.privmsg(auteur
,ligne
)
212 if auteur
in self
.ops
:
214 if message
[1] in self
.chanlist
:
215 serv
.privmsg(auteur
,"Je suis déjà sur %s"%(message
[1]))
217 serv
.join(message
[1])
218 self
.chanlist
.append(message
[1])
219 serv
.privmsg(auteur
,"Channels : "+" ".join(self
.chanlist
))
220 log(self
.serveur
,"priv",auteur
," ".join(message
))
222 serv
.privmsg(auteur
,"Channels : "+" ".join(self
.chanlist
))
226 if auteur
in self
.ops
and len(message
)>1:
227 if message
[1] in self
.chanlist
:
228 if not (message
[1] in self
.stay_channels
) or auteur
in self
.overops
:
229 self
.quitter(message
[1]," ".join(message
[2:]))
230 self
.chanlist
.remove(message
[1])
231 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
233 serv
.privmsg(auteur
,"Non, je reste !")
234 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
236 serv
.privmsg(auteur
,"Je ne suis pas sur %s"%(message
[1]))
240 if auteur
in self
.overops
:
242 if message
[1] in self
.stay_channels
:
243 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
244 serv
.privmsg(auteur
,"Je stay déjà sur %s."%(message
[1]))
246 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
247 self
.stay_channels
.append(message
[1])
248 serv
.privmsg(auteur
,"Stay channels : "+" ".join(self
.stay_channels
))
250 serv
.privmsg(auteur
,"Stay channels : "+" ".join(self
.stay_channels
))
254 if auteur
in self
.overops
:
256 if message
[1] in self
.stay_channels
:
257 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
258 self
.stay_channels
.remove(message
[1])
259 serv
.privmsg(auteur
,"Stay channels : "+" ".join(self
.stay_channels
))
261 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
262 serv
.privmsg(auteur
,"Je ne stay pas sur %s."%(message
[1]))
267 if auteur
in self
.overops
:
268 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
273 if auteur
in self
.ops
:
275 if message
[1] in self
.quiet_channels
:
276 serv
.privmsg(auteur
,"Je me la ferme déjà sur %s"%(message
[1]))
277 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
279 self
.quiet_channels
.append(message
[1])
280 serv
.privmsg(auteur
,"Quiet channels : "+" ".join(self
.quiet_channels
))
281 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
283 serv
.privmsg(auteur
,"Quiet channels : "+" ".join(self
.quiet_channels
))
287 if auteur
in self
.ops
:
289 if message
[1] in self
.quiet_channels
:
290 self
.quiet_channels
.remove(message
[1])
291 serv
.privmsg(auteur
,"Quiet channels : "+" ".join(self
.quiet_channels
))
292 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[successful]")
294 serv
.privmsg(auteur
,"Je ne me la ferme pas sur %s."%(message
[1]))
295 log(self
.serveur
,"priv",auteur
," ".join(message
)+"[failed]")
299 if auteur
in self
.overops
and len(message
)>2:
300 serv
.privmsg(message
[1]," ".join(message
[2:]))
301 log(self
.serveur
,"priv",auteur
," ".join(message
))
302 elif len(message
)<=2:
303 serv
.privmsg(auteur
,"Syntaxe : SAY <channel> <message>")
307 if auteur
in self
.overops
and len(message
)>2:
308 serv
.action(message
[1]," ".join(message
[2:]))
309 log(self
.serveur
,"priv",auteur
," ".join(message
))
310 elif len(message
)<=2:
311 serv
.privmsg(auteur
,"Syntaxe : DO <channel> <action>")
315 if auteur
in self
.overops
and len(message
)>2:
316 serv
.kick(message
[1],message
[2]," ".join(message
[3:]))
317 log(self
.serveur
,"priv",auteur
," ".join(message
))
318 elif len(message
)<=2:
319 serv
.privmsg(auteur
,"Syntaxe : KICK <channel> <pseudo> [<raison>]")
323 if auteur
in self
.overops
:
324 serv
.privmsg(auteur
," ".join(self
.ops
))
328 if auteur
in self
.overops
:
329 serv
.privmsg(auteur
," ".join(self
.overops
))
335 serv
.privmsg(auteur
,"Je n'ai pas compris. Essayez HELP…")
337 def on_pubmsg(self
, serv
, ev
):
338 auteur
= irclib
.nm_to_n(ev
.source())
340 message
= ev
.arguments()[0]
342 test
=bot_unicode(message
)
343 except UnicodeBotError
:
344 if config
.utf8_trigger
and not canal
in self
.quiet_channels
:
345 serv
.privmsg(canal
, (u
"%s: %s"%(auteur
,random
.choice(config
.utf8_fail_answers
))).encode("utf8"))
347 pour_moi
,message
=self
.pourmoi(serv
,message
)
348 if pour_moi
and message
.split()!=[]:
349 cmd
=message
.split()[0].lower()
351 args
=" ".join(message
.split()[1:])
354 if cmd
in ["meurs","die","crève"]:
355 if auteur
in self
.overops
:
356 log(self
.serveur
,canal
,auteur
,message
+"[successful]")
359 serv
.privmsg(canal
,("%s: %s"%(auteur
,random
.choice(config
.quit_fail_messages
))).encode("utf8"))
360 log(self
.serveur
,canal
,auteur
,message
+"[failed]")
362 elif cmd
in ["part","leave","dégage","va-t-en","tut'tiresailleurs,c'estmesgalets"]:
363 if auteur
in self
.ops
and (not (canal
in self
.stay_channels
)
364 or auteur
in self
.overops
):
366 log(self
.serveur
,canal
,auteur
,message
+"[successful]")
367 if canal
in self
.chanlist
:
368 self
.chanlist
.remove(canal
)
370 serv
.privmsg(canal
,("%s: %s"%(auteur
,random
.choice(config
.leave_fail_messages
))).encode("utf8"))
371 log(self
.serveur
,canal
,auteur
,message
+"[failed]")
373 elif cmd
in ["deviens","pseudo"]:
374 if auteur
in self
.ops
:
377 log(self
.serveur
,canal
,auteur
,message
+"[successful]")
379 if cmd
in ["meur", "meurt","meurre","meurres"] and not canal
in self
.quiet_channels
:
380 serv
.privmsg(canal
,'%s: Mourir, impératif, 2ème personne du singulier : "meurs" (de rien)'%(auteur))
381 elif cmd
in ["ping"] and not canal
in self
.quiet_channels
:
382 serv
.privmsg(canal
,"%s: pong"%(auteur))
383 if is_insult(message
) and not canal
in self
.quiet_channels
:
384 if is_not_insult(message
):
385 answer
=random
.choice(config
.compliment_answers
)
386 for ligne
in answer
.split("\n"):
387 serv
.privmsg(canal
,"%s: %s"%(auteur
,ligne
.encode("utf8")))
389 answer
=random
.choice(config
.insultes_answers
)
390 for ligne
in answer
.split("\n"):
391 serv
.privmsg(canal
,"%s: %s"%(auteur
,ligne
.encode("utf8")))
392 elif is_compliment(message
) and not canal
in self
.quiet_channels
:
393 answer
=random
.choice(config
.compliment_answers
)
394 for ligne
in answer
.split("\n"):
395 serv
.privmsg(canal
,"%s: %s"%(auteur
,ligne
.encode("utf8")))
396 if is_tesla(message
) and not canal
in self
.quiet_channels
:
397 l1
,l2
=config
.tesla_answers
,config
.tesla_actions
398 n1
,n2
=len(l1
),len(l2
)
399 i
=random
.randrange(n1
+n2
)
401 serv
.action(canal
,l2
[i
-n1
].encode("utf8"))
403 serv
.privmsg(canal
,"%s: %s"%(auteur
,l1
[i
].encode("utf8")))
404 if is_tamere(message
) and not canal
in self
.quiet_channels
:
405 answer
=random
.choice(config
.tamere_answers
)
406 for ligne
in answer
.split("\n"):
407 serv
.privmsg(canal
,"%s: %s"%(auteur
,ligne
.encode("utf8")))
408 if is_tag(message
) and not canal
in self
.quiet_channels
:
409 if auteur
in self
.ops
:
410 action
=random
.choice(config
.tag_actions
)
411 serv
.action(canal
,action
.encode("utf8"))
412 self
.quiet_channels
.append(canal
)
414 answer
=random
.choice(config
.tag_answers
)
415 for ligne
in answer
.split("\n"):
416 serv
.privmsg(canal
,"%s: %s"%(auteur
,ligne
.encode("utf8")))
417 if is_merci(message
):
418 answer
=random
.choice(config
.merci_answers
)
419 for ligne
in answer
.split("\n"):
420 serv
.privmsg(canal
,"%s: %s"%(auteur
,ligne
.encode("utf8")))
421 if is_bonjour(message
) and not canal
in self
.quiet_channels
:
423 answer
=random
.choice(config
.night_answers
)
425 answer
=random
.choice(config
.bonjour_answers
)
427 answer
=random
.choice(config
.bonsoir_answers
)
428 serv
.privmsg(canal
,answer
.format(auteur
).encode("utf8"))
429 if is_bonne_nuit(message
) and not canal
in self
.quiet_channels
:
430 answer
=random
.choice(config
.bonne_nuit_answers
)
431 serv
.privmsg(canal
,answer
.format(auteur
).encode("utf8"))
433 if not canal
in self
.quiet_channels
:
435 if re
.match((u
"^("+u
"|".join(config
.bonjour_triggers
)
436 +ur
")( {}| all| tout le monde| (à )?tous)(\.| ?!)?$"
437 ).format(mypseudo
).lower(), message
.decode("utf8").strip().lower()):
438 answer
= random
.choice(config
.bonjour_answers
)
439 serv
.privmsg(canal
,answer
.format(auteur
).encode("utf8"))
441 def on_action(self
, serv
, ev
):
442 action
= ev
.arguments()[0]
443 auteur
= irclib
.nm_to_n(ev
.source())
444 channel
= ev
.target()
446 test
=bot_unicode(action
)
447 except UnicodeBotError
:
448 if config
.utf8_trigger
and not channel
in self
.quiet_channels
:
449 serv
.privmsg(channel
, (u
"%s: %s"%(auteur
,random
.choice(config
.utf8_fail_answers
))).encode("utf8"))
453 if is_bad_action_trigger(action
,mypseudo
) and not channel
in self
.quiet_channels
:
454 l1
,l2
=config
.bad_action_answers
,config
.bad_action_actions
455 n1
,n2
=len(l1
),len(l2
)
456 i
=random
.randrange(n1
+n2
)
458 serv
.action(channel
,l2
[i
-n1
].format(auteur
).encode("utf8"))
460 serv
.privmsg(channel
,l1
[i
].format(auteur
).format(auteur
).encode("utf8"))
461 if is_good_action_trigger(action
,mypseudo
) and not channel
in self
.quiet_channels
:
462 l1
,l2
=config
.good_action_answers
,config
.good_action_actions
463 n1
,n2
=len(l1
),len(l2
)
464 i
=random
.randrange(n1
+n2
)
466 serv
.action(channel
,l2
[i
-n1
].format(auteur
).format(auteur
).encode("utf8"))
468 serv
.privmsg(channel
,l1
[i
].format(auteur
).format(auteur
).encode("utf8"))
470 def on_kick(self
,serv
,ev
):
471 auteur
= irclib
.nm_to_n(ev
.source())
472 channel
= ev
.target()
473 victime
= ev
.arguments()[0]
474 raison
= ev
.arguments()[1]
475 if victime
==self
.nick
:
476 log(self
.serveur
,"%s kické de %s par %s (raison : %s)" %(victime
,channel
,auteur
,raison
))
479 l1
,l2
=config
.kick_answers
,config
.kick_actions
480 n1
,n2
=len(l1
),len(l2
)
481 i
=random
.randrange(n1
+n2
)
483 serv
.action(channel
,l2
[i
-n1
].format(auteur
).encode("utf8"))
485 serv
.privmsg(channel
,l1
[i
].format(auteur
).encode("utf8"))
487 def quitter(self
,chan
,leave_message
=None):
488 if leave_message
==None:
489 leave_message
=random
.choice(config
.leave_messages
)
490 self
.serv
.part(chan
,message
=leave_message
.encode("utf8"))
493 quit_message
=random
.choice(config
.quit_messages
)
494 self
.die(msg
=quit_message
.encode("utf8"))
497 return self
.serv
.get_nickname()
498 nick
=property(_getnick
)
501 if __name__
=="__main__":
504 print "Usage : skeleton.py <serveur> [--debug]"
507 if "debug" in sys
.argv
or "--debug" in sys
.argv
:
511 if "--quiet" in sys
.argv
:
512 config
.debug_stdout
=False
513 serveurs
={"a♡":"acoeur.crans.org","acoeur":"acoeur.crans.org","acoeur.crans.org":"acoeur.crans.org",
514 "irc":"irc.crans.org","crans":"irc.crans.org","irc.crans.org":"irc.crans.org"}
516 serveur
=serveurs
[serveur
]
518 print "Server Unknown : %s"%(serveur)
520 bot
=Skeleton(serveur
,debug
)