Passed
Branch master (ed257a)
by Mikael
03:02
created

irc2phpbb.lunch()   A

Complexity

Conditions 3

Size

Total Lines 15
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 10
nop 1
dl 0
loc 15
rs 9.9
c 0
b 0
f 0
1
#! /usr/bin/env python
2
# -*- coding: utf-8 -*-
3
4
#import some stuff
5
import sys
6
import socket
7
import string
8
import random
9
import os #not necassary but later on I am going to use a few features from this
10
import feedparser # http://wiki.python.org/moin/RssLibraries
11
import shutil
12
import codecs
13
from collections import deque
14
from datetime import datetime
15
import re
16
import urllib2
17
from bs4 import BeautifulSoup
18
import time
19
import json
20
from datetime import date
21
22
import phpmanual
23
import dev_mozilla
24
25
# Local module file
26
#import fix_bad_unicode
27
28
29
#
30
# Settings
31
#
32
HOST='irc.bsnet.se' 			# The server we want to connect to
33
PORT=6667 								# The connection port which is usually 6667
34
NICK='marvin' 						# The bot's nickname
35
IDENT='********'         # Password to identify for nick
36
REALNAME='Mr Marvin Bot'
37
OWNER='mos' 							# The bot owner's nick
38
CHANNEL='#db-o-webb1'      # The default channel for the bot
39
#CHANNEL='#dbwebb'        # The default channel for the bot
40
INCOMING='incoming'			  # Directory for incoming messages
41
DONE='done'			  				# Directory to move all incoming messages once processed
42
readbuffer='' 						# Here we store all the messages from server
43
HOME='https://github.com/mosbth/irc2phpbb'
44
FEED_FORUM='http://dbwebb.se/forum/feed.php'
45
FEED_LISTEN='http://ws.audioscrobbler.com/1.0/user/mikaelroos/recenttracks.rss'
46
#FEED_LISTEN='http://ws.audioscrobbler.com/1.0/user/djazzradio/recenttracks.rss'
47
48
SMHI_PROGNOS='http://www.smhi.se/vadret/vadret-i-sverige/Vaderoversikt-Sverige-meteorologens-kommentar?meteorologens-kommentar=http%3A%2F%2Fwww.smhi.se%2FweatherSMHI2%2Flandvader%2F.%2Fprognos15_2.htm'
49
#SUNRISE='http://www.timeanddate.com/astronomy/sweden/jonkoping' Stopped working
50
SUNRISE='http://www.timeanddate.com/sun/sweden/jonkoping'
51
52
LOGFILE='irclog.txt'        # Save a log with latest messages
53
LOGFILEMAX=20
54
irclog=deque([],LOGFILEMAX) # Keep a log of the latest messages
55
56
57
#
58
# Manage character encoding issues for incoming messages
59
# http://stackoverflow.com/questions/938870/python-irc-bot-and-encoding-issue
60
#
61
def decode_irc(raw, preferred_encs = ["UTF-8", "CP1252", "ISO-8859-1"]):
62
  changed = False
63
  for enc in preferred_encs:
64
    try:
65
      res = raw.decode(enc)
66
      changed = True
67
      break
68
    except:
69
      pass
70
  if not changed:
71
    try:
72
      enc = chardet.detect(raw)['encoding']
73
      res = raw.decode(enc)
74
    except:
75
      res = raw.decode(enc, 'ignore')
76
  return res
77
78
79
80
#
81
#Function to parse incoming messages
82
#
83
def parsemsg(msg):
84
	complete=msg[1:].split(':',1) #Parse the message into useful data
85
	info=complete[0].split(' ')
86
	msgpart=complete[1]
87
	sender=info[0].split('!')
88
	if msgpart[0]=='`' and sender[0]==OWNER: #Treat all messages starting with '`' as command
89
		cmd=msgpart[1:].split(' ')
90
		if cmd[0]=='op':
91
			s.send('MODE '+info[2]+' +o '+cmd[1]+'n')
92
		if cmd[0]=='deop':
93
			s.send('MODE '+info[2]+' -o '+cmd[1]+'n')
94
		if cmd[0]=='voice':
95
			s.send('MODE '+info[2]+' +v '+cmd[1]+'n')
96
		if cmd[0]=='devoice':
97
			s.send('MODE '+info[2]+' -v '+cmd[1]+'n')
98
		if cmd[0]=='sys':
99
			syscmd(msgpart[1:],info[2])
100
101
	if msgpart[0]=='-' and sender[0]==OWNER : #Treat msgs with - as explicit command to send to server
102
		cmd=msgpart[1:]
103
		s.send(cmd+'n')
104
		print 'cmd='+cmd
105
106
107
#This piece of code takes the command and executes it printing the output to ot.txt. Then ot.txt is
108
#read and displayed to the given channel. Multiline output is shown by using '|'.
109
def syscmd(commandline,channel):
110
    cmd=commandline.replace('sys ','')
111
    cmd=cmd.rstrip()
112
    os.system(cmd+' >temp.txt')
113
    a=open('temp.txt')
114
    ot=a.read()
115
    ot.replace('n','|')
116
    a.close()
117
    s.send('PRIVMSG '+channel+' :'+ot+'n')
118
    return 0
119
120
121
# Send and occasionally print the message sent.
122
def sendMsg(s, msg):
123
  print(msg.rstrip('\r\n'))
124
  s.send(msg)
125
126
127
# Send and log a PRIV message
128
def sendPrivMsg(s, msg):
129
  global irclog
130
  irclog.append({'time':datetime.now().strftime("%H:%M").rjust(5), 'user':NICK.ljust(8), 'msg':msg})
131
  #irclog.append("%s %s %s" % (datetime.now().strftime("%H:%M").rjust(5), NICK.ljust(8), msg))
132
  print "PRIVMSG %s :%s\r\n" % (CHANNEL, msg)
133
  sendMsg(s,"PRIVMSG %s :%s\r\n" % (CHANNEL, msg))
134
135
136
#Read all files in the directory incoming, send them as a message if they exists and then move the
137
#file to directory done.
138
def readincoming(dir):
139
	listing = os.listdir(dir)
140
	for infile in listing:
141
		filename=dir + '/' + infile
142
		#text=codecs.open(filename, 'r', 'utf-8').read()
143
		text=file(filename).read()
144
		msg="PRIVMSG %s :%s\r\n" % (CHANNEL, text)
145
		sendMsg(s,msg)
146
		try:
147
			shutil.move(filename, DONE)
148
		except Exception:
149
			os.remove(filename)
150
151
152
#Connect
153
#Create the socket  & Connect to the server
154
s=socket.socket( )
155
print "Connecting: %s:%d" % (HOST, PORT)
156
s.connect((HOST, PORT))
157
158
#Send the nick to server
159
sendMsg(s,'NICK %s\r\n' % NICK)
160
161
#Identify to server
162
sendMsg(s,'USER  %s %s dbwebb.se :%s\r\n' % (NICK, HOST, REALNAME))
163
164
#This is my nick, i promise!
165
sendMsg(s,'PRIVMSG nick IDENTIFY %s\r\n' % IDENT)
166
167
#Join a channel
168
sendMsg(s,'JOIN %s\r\n' % CHANNEL)
169
170
171
#Wait and listen
172
#We recieve the server input in a variable line; if you want to see the servers messages,
173
#use print line. Once we connect to the server, we join a channel. Now whenever we recieve
174
#any PRIVMSG, we call a function which does the appropriate action. The next few lines are
175
#used to reply to a servers PING. Until this point, the bot just sits idle in a channel.
176
#To make it active we use the parsemsg function.
177
#PRIVMSG are usually of this form:
178
# :nick!username@host PRIVMSG channel/nick :Message
179
msgs=['Ja, vad kan jag göra för Dig?', 'Låt mig hjälpa dig med dina strävanden.', 'Ursäkta, vad önskas?',
180
'Kan jag stå till din tjänst?', 'Jag kan svara på alla dina frågor.', 'Ge me hög-fem!',
181
'Jag svarar endast inför mos, det är min enda herre.', 'mos är kungen!',
182
'Oh, ursäkta, jag slumrade visst till.', 'Fråga, länka till exempel samt source.php/gist/codeshare och vänta på svaret.']
183
184
hello=['Hej själv! ', 'Trevligt att du bryr dig om mig. ', 'Det var länge sedan någon var trevlig mot mig. ',
185
'Halloj, det ser ut att bli mulet idag. ',
186
]
187
188
smile=[':-D', ':-P', ';-P', ';-)', ':-)', '8-)']
189
190
lunchQuote=['ska vi ta %s?',
191
'ska vi dra ned till %s?',
192
'jag tänkte käka på %s, ska du med?',
193
'På %s är det mysigt, ska vi ta där?']
194
195
lunchBTH=['thairestaurangen vid korsningen',
196
'det är lite mysigt i fiket jämte demolabbet',
197
'Indiska',
198
'Pappa curry',
199
'boden uppe på parkeringen',
200
'Bergåsa kebab',
201
'Pasterian',
202
'Villa Oscar',
203
'Eat here',
204
'Bistro J']
205
206
lunchStan=['Olles krovbar',
207
'Lila thai stället',
208
'donken',
209
'tex mex stället vid subway',
210
'Subway',
211
'Nya peking',
212
'kebab house',
213
'Royal thai',
214
'thai stället vid hemmakväll',
215
'Gelato',
216
'Indian garden',
217
'Sumo sushi',
218
'Pasterian i stan',
219
'Biobaren',
220
'Michelangelo']
221
222
lunchHassleholm=['pastavagnen på torget',
223
'Freds',
224
'mcDonalds',
225
'subway',
226
'kinabuffé på Cats',
227
'valentino',
228
'lotterilådan',
229
'casablance',
230
'det där stället i gallerian',
231
'infinity',
232
'östervärn',
233
'argentina',
234
'T4']
235
236
quote=['I could calculate your chance of survival, but you won\'t like it.',
237
'I\'d give you advice, but you wouldn\'t listen. No one ever does.',
238
'I ache, therefore I am.',
239
'I\'ve seen it. It\'s rubbish. (About a Magrathean sunset that Arthur finds magnificent)',
240
'Not that anyone cares what I say, but the Restaurant is on the other end of the universe.',
241
'I think you ought to know I\'m feeling very depressed.',
242
'My capacity for happiness," he added, "you could fit into a matchbox without taking out the matches first.',
243
'Arthur: "Marvin, any ideas?" Marvin: "I have a million ideas. They all point to certain death."',
244
'"What\'s up?" [asked Ford.] "I don\'t know," said Marvin, "I\'ve never been there."',
245
'Marvin: "I am at a rough estimate thirty billion times more intelligent than you. Let me give you an example. Think of a number, any number." Zem: "Er, five." Marvin: "Wrong. You see?"',
246
'Zaphod: "Can it Trillian, I\'m trying to die with dignity. Marvin: "I\'m just trying to die."']
247
248
lyssna=['Jag gillar låten', 'Senaste låten jag lyssnade på var', 'Jag lyssnar just nu på',
249
'Har du hört denna låten :)', 'Jag kan tipsa om en bra låt ->']
250
251
attack=['Aaaaarrggh mateys! You will walk the plank!',
252
'Nej, jag orkar inte =(',
253
'Yippee-ki-yay, motherf*cker!',
254
'DEAAAAAAAAAAATH!',
255
'You\'re in for a world of pain',
256
'For the Horde!',
257
'The Almighty tells me he can get me out of this mess, but he\'s pretty sure you\'re fuc*ed.',
258
'There\'s nothing stronger than the heart of a volunteer.']
259
260
slaps=[' in the face with a rotten old fish.',
261
' around a bit with a large trout.',
262
' in the face with a keyboard.',
263
' around with a glove.',
264
' over the head with a fluffy pillow.',
265
' about the head and shoulders with a rubber chicken.',
266
' with a large squid... I hope you like seafood.',
267
' about the head and shoulders with a rubber chicken.'
268
]
269
270
weekdays = [
271
  "Idag är det måndag.",
272
  "Idag är det tisdag.",
273
  "Idag är det onsdag.",
274
  "Idag är det torsdag.",
275
  "Idag är det fredag.",
276
  "Idag är det lördag.",
277
  "Idag är det söndag.",
278
]
279
280
281
282
def lunch(where):
283
  """
284
  Generates where to eat either in centrum or around bth (or Hässleholm)
285
  """
286
  quote=lunchQuote[random.randint(0, len(lunchQuote) - 1)]
287
  msg=''
288
  if where == 'stan':
289
      msg=quote % lunchStan[random.randint(0, len(lunchStan) -1)]
290
  elif where == 'hassleholm':
291
      index = random.randint(0, len(lunchHassleholm) - 1)
292
      msg=quote % lunchHassleholm[index]
293
  else:
294
      msg=quote % lunchBTH[random.randint(0,len(lunchBTH)-1)]
295
296
  return msg;
297
298
299
300
def videoOfToday():
301
  """
302
  Check what day it is and provide a url to a suitable video together with a greeting.
303
  """
304
  dayNum = date.weekday(date.today())
305
  msg = weekdays[dayNum]
306
307
  if dayNum == 0:
308
    msg += " En passande video är https://www.youtube.com/watch?v=lAZgLcK5LzI."
309
  elif dayNum == 4:
310
    msg += " En passande video är https://www.youtube.com/watch?v=kfVsfOSbJY0."
311
  elif dayNum == 5:
312
    msg += " En passande video är https://www.youtube.com/watch?v=GVCzdpagXOQ."
313
  else:
314
    msg += " Jag har ännu ingen passande video för denna dagen."
315
316
  return msg
317
318
319
320
#
321
# Main loop
322
#
323
while 1:
324
  json.dump(list(irclog), file(LOGFILE, 'w'), False, False, False, False, indent=2) #Write IRC to logfile
325
  readincoming(INCOMING)
326
  readbuffer=readbuffer+s.recv(1024)
327
  temp=string.split(readbuffer, "\n")
328
  readbuffer=temp.pop( )
329
330
  for line in temp:
331
    untouchedLine = line #This is needed to preserve capital letters, otherwise dev_mozilla module does not work properly.
332
    line = decode_irc(line)
333
    #print "HERE %s" % (line.encode('utf-8', 'ignore'))
334
335
    line=string.rstrip(line)
336
    line=string.split(line)
337
    row=' '.join(line[3:]).replace(':',' ').replace(',',' ').replace('.',' ').replace('?',' ').strip().lower()
338
    row=row.split()
339
    print "%s" % (line)
340
    #print "%s" % (row)
341
342
    if line[0]=="PING":
343
      sendMsg(s,"PONG %s\r\n" % line[1])
344
345
    if line[1]=='PRIVMSG' and line[2]==CHANNEL:
346
347
      if line[3]==u':\x01ACTION':
348
        irclog.append({'time':datetime.now().strftime("%H:%M").rjust(5), 'user':'* ' + re.search('(?<=:)\w+', line[0]).group(0).encode('utf-8', 'ignore'), 'msg':' '.join(line[4:]).lstrip(':').encode('utf-8', 'ignore')})
349
350
      else:
351
        #irclog.append({'time':datetime.now().strftime("%H:%M").rjust(5), 'user':re.search('(?<=:)\w+', line[0]).group(0).ljust(8), 'msg':' '.join(line[3:]).lstrip(':')})
352
        #irclog.append({'time':datetime.now().strftime("%H:%M").rjust(5), 'user':re.search('(?<=:)\w+', line[0]).group(0).encode('utf-8', 'ignore'), 'msg':' '.join(line[3:]).lstrip(':').encode('utf-8', 'ignore')})
353
        irclog.append({'time':datetime.now().strftime("%H:%M").rjust(5), 'user':re.search('(?<=:)\w+', line[0]).group(0).encode('utf-8', 'ignore'), 'msg':' '.join(line[3:]).lstrip(':').encode('utf-8', 'ignore')})
354
        #(datetime.now().strftime("%H:%M").rjust(5), re.search('(?<=:)\w+', line[0]).group(0).ljust(8), ' '.join(line[3:]).lstrip(':')))
355
356
    if line[1]=='PRIVMSG' and line[2]==CHANNEL and NICK in row:
357
358
      if 'lyssna' in row or 'lyssnar' in row or 'musik' in row:
359
        feed=feedparser.parse(FEED_LISTEN)
360
        sendPrivMsg(s,"%s %s" % (lyssna[random.randint(0,len(lyssna)-1)], feed["items"][0]["title"].encode('utf-8', 'ignore')))
361
362
      elif ('latest' in row or 'senaste' in row or 'senast' in row) and ('forum' in row or 'forumet' in row):
363
        feed=feedparser.parse(FEED_FORUM)
364
        sendPrivMsg(s,"Forumet: \"%s\" av %s http://dbwebb.se/f/%s" % (feed["items"][0]["title"].encode('utf-8', 'ignore'), feed["items"][0]["author"].encode('utf-8', 'ignore'), re.search('(?<=p=)\d+', feed["items"][0]["id"].encode('utf-8', 'ignore')).group(0)))
365
366
      elif 'smile' in row or 'le' in row or 'skratta' in row or 'smilies' in row:
367
        sendPrivMsg(s,"%s" % (smile[random.randint(0,len(smile)-1)]))
368
369
      elif unicode('källkod', 'utf-8') in row or 'source' in row:
370
        sendPrivMsg(s,"I PHP-kurserna kan du länka till source.php. Annars delar du koden som en gist (https://gist.github.com) eller i CodeShare (http://codeshare.io).")
371
372
      elif ('budord' in row or 'stentavla' in row) and ('1' in row or '#1' in row):
373
        sendPrivMsg(s,"Ställ din fråga, länka till exempel och source.php. Häng kvar och vänta på svar.")
374
375
      elif ('budord' in row or 'stentavla' in row) and ('2' in row or '#2' in row):
376
        sendPrivMsg(s,"Var inte rädd för att fråga och fråga tills du får svar: http://dbwebb.se/f/6249")
377
378
      elif ('budord' in row or 'stentavla' in row) and ('3' in row or '#3' in row):
379
        sendPrivMsg(s,"Öva dig ställa smarta frågor: http://dbwebb.se/f/7802")
380
381
      elif ('budord' in row or 'stentavla' in row) and ('4' in row or '#4' in row):
382
        sendPrivMsg(s,"When in doubt - gör ett testprogram. http://dbwebb.se/f/13570")
383
384
      elif ('budord' in row or 'stentavla' in row) and ('5' in row or '#5' in row):
385
        sendPrivMsg(s,"Hey Luke - use the source! http://catb.org/jargon/html/U/UTSL.html")
386
387
      elif 'lunch' in row or 'mat' in row or unicode('äta', 'utf-8') in row:
388
        if 'stan' in row or 'centrum' in row:
389
            sendPrivMsg(s,"%s" % lunch('stan'))
390
        elif unicode('hässleholm', 'utf-8') in row:
391
            sendPrivMsg(s,"%s" % lunch('hassleholm'))
392
        else:
393
            sendPrivMsg(s,"%s" % lunch('bth'))
394
395
      elif 'quote' in row or 'citat' in row or 'filosofi' in row or 'filosofera' in row:
396
        sendPrivMsg(s,"%s" % (quote[random.randint(0,len(quote)-1)]))
397
398
      elif ('idag' in row or 'dagens' in row) and ('video' in row or 'youtube' in row or 'tube' in row):
399
        sendPrivMsg(s,"%s" % videoOfToday())
400
401
      elif 'hem' in row or (('vem' in row or 'vad' in row) and (unicode('är', 'utf-8') in row)):
402
        sendPrivMsg(s,"Jag är en tjänstvillig själ som gillar webbprogrammering. Jag bor på github: %s och du kan diskutera mig i forumet http://dbwebb.se/forum/viewtopic.php?f=21&t=20"  % (HOME))
403
404
      elif unicode('hjälp', 'utf-8') in row or 'help' in row:
405
        sendPrivMsg(s,"[ vem är | forum senaste | lyssna | le | lunch | citat | budord 1 (2, 3, 4, 5) | väder | solen | hjälp | php | js/javascript | attack | slap | dagens video ]")
406
407
      elif unicode('väder', 'utf-8') in row or unicode('vädret', 'utf-8') in row or 'prognos' in row or 'prognosen' in row or 'smhi' in row:
408
        soup = BeautifulSoup(urllib2.urlopen(SMHI_PROGNOS))
409
        sendPrivMsg(s,"%s. %s. %s" % (soup.h1.text.encode('utf-8', 'ignore'), soup.h4.text.encode('utf-8', 'ignore'), soup.h4.findNextSibling('p').text.encode('utf-8', 'ignore')))
410
411
      elif 'sol' in row or 'solen' in row or unicode('solnedgång', 'utf-8') in row or unicode('soluppgång', 'utf-8') in row:
412
413
        try:
414
          soup = BeautifulSoup(urllib2.urlopen(SUNRISE))
415
          spans = soup.find_all("span", { "class" : "three" })
416
          sunrise = spans[0].text.encode('utf-8', 'ignore')
417
          sunset = spans[1].text.encode('utf-8', 'ignore')
418
          sendPrivMsg(s,"Idag går solen upp %s och ner %s. Iallafall i trakterna kring Jönköping." % (sunrise, sunset))
419
420
        except Exception as e:
421
          sendPrivMsg(s,"Jag hittade tyvär inga solar idag :( så jag håller på och lär mig hur Python kan räkna ut soluppgången, återkommer.")
422
423
        #div = soup.find(id="qfacts")
424
        #sunrise = div.p.next_sibling.span.next_sibling.text.encode('utf-8', 'ignore')
425
        #sunset = div.p.next_sibling.p.br.span.next_sibling.text.encode('utf-8', 'ignore')
426
        #endPrivMsg(s,"Idag går solen upp %s och ner %s. Iallafall i trakterna kring Jönköping." % (sunrise, sunset))
427
428
      elif unicode('snälla', 'utf-8') in row or 'hej' in row or 'tjena' in row or 'morsning' in row  or unicode('mår', 'utf-8') in row  or unicode('hallå', 'utf-8') in row or 'hallo' in row or unicode('läget', 'utf-8') in row or unicode('snäll', 'utf-8') in row or 'duktig' in row  or unicode('träna', 'utf-8') in row  or unicode('träning', 'utf-8') in row  or 'utbildning' in row or 'tack' in row or 'tacka' in row or 'tackar' in row or 'tacksam' in row:
429
        sendPrivMsg(s,"%s %s %s" % (smile[random.randint(0,len(smile)-1)], hello[random.randint(0,len(hello)-1)], msgs[random.randint(0,len(msgs)-1)]))
430
431
      elif 'attack' in row:
432
        sendPrivMsg(s,"%s" % (attack[random.randint(0,len(attack)-1)]))
433
434
      elif 'upprop' in row:
435
        sendPrivMsg(s, "Titta vad jag hittade: 3v upprop vårterminen 2015 - http://dbwebb.se/forum/viewtopic.php?f=30&t=3613")
436
437
      elif 'stats' in row or 'ircstats' in row:
438
        sendPrivMsg(s, "Statistik för kanalen finns här: http://dbwebb.se/irssistats/db-o-webb.html")
439
440
      elif 'slap' in row:
441
        #print('\r\nSlap!\r\n')
442
        if len(row) >= 3 and row[1] == 'slap':
443
          sendPrivMsg(s, "\001ACTION slaps " + row[2] + slaps[random.randint(0,len(slaps)-1)] + "\001")
444
445
      elif 'php' in row:
446
        if len(row) >= 3 and row[1] == 'php':
447
448
          try:
449
            function = row[2].encode('utf-8', 'ignore')
450
            result = phpmanual.getShortDescr(function)
451
            sendPrivMsg(s, result)
452
453
          except:
454
            sendPrivMsg(s, "php fungerar inte för tillfället. Ska fixa det.")
455
456
      elif 'js' in row or 'javascript' in row:
457
        if len(row) >= 3 and (row[1] == 'javascript' or row[1] == 'js'):
458
459
          try:
460
            function = untouchedLine.split()
461
            function = function[len(function)-1]
462
            result = dev_mozilla.getResultString(function)
463
            sendPrivMsg(s, result)
464
465
          except:
466
            sendPrivMsg(s, "js fungerar inte för tillfället. Ska fixa det.")
467