PageRenderTime 70ms CodeModel.GetById 24ms RepoModel.GetById 1ms app.codeStats 0ms

/beats.py

https://gitlab.com/kalix/beats
Python | 317 lines | 257 code | 17 blank | 43 comment | 23 complexity | 8da07c4b26940e02aef105d0fded6157 MD5 | raw file
  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. import sys
  4. import math
  5. import re
  6. import salary
  7. import unvisit
  8. import medborgarlon
  9. import swatch
  10. import mapcode
  11. import help
  12. from twisted.internet import reactor, task, defer, protocol
  13. from twisted.python import log
  14. from twisted.words.protocols import irc
  15. from twisted.web.client import getPage
  16. from twisted.application import internet, service
  17. from datetime import datetime
  18. from time import localtime, timezone
  19. import urllib2
  20. import json, requests, pprint
  21. import ast
  22. import feedparser
  23. import reimport
  24. from datetime import timedelta, date, datetime
  25. import bitstamp.client
  26. import duckduckgo
  27. import wolframalpha
  28. HOST, PORT = 'lindnet.eu.se.undermind.net', 6667
  29. #Settings for photo theme
  30. theme = ["Självporträtt","Frukost","Sött","Skor","Brevlåda","Himmel","Droppar","Ord på A", "Färg", "Ljus","Klockan 10", "Vardag", "Vitt", "Kork", "Reflektioner", "Säng", "Gammalt", "Natur", "Solglasögon", "Tak", "Solnedgång", "Dörr", "Två saker", "I hyllan", "Bubbla", "I väskan", "Leksak", "Tvätt", "Vän", "Liten", "Mjuk", "Utsikt", "Händer", "Ord", "Främling", "Klockan 15", "Middag", "Knapp", "Sol", "Gläje", "Ljud", "Glädje", "I garderoben", "Blått", "Kaffe", "Telefon", "Något nytt", "Tid", "Ord på K", "Ogillar", "I kylskåpet", "Barndom", "Is", "Natt", "Njutning", "Pengar", "Vikt", "Vardag", "Stor", "Upp", "Frukt", "Granne", "Klockan 17", "Ett leende", "Fönster", "Rött", "Gaffel", "En skylt", "Moln", "Solglasögon", "Ett hörn", "Roligt", "Nyckel", "Djur", "Namn", "Sopor", "Fötter", "Avslappning", "Kök", "Post", "I plånboken", "Trappor", "Krage", "Hår", "Flaska", "Cirkel", "Orange", "Yngre", "Fred", "Mamma", "Läsa", "Rosa", "Ovanlig", "Nummer", "I garaget", "Lukt", "Personlighet", "ICA", "Där du står", "Teknologi", "Morgon", "Hatt", "Konst", "Gult", "Nerifrån", "I luften", "Latex", "Gullig", "Ord på L", "Upptagen", "På golvet", "Köksbord", "Stol", "Öga", "Finger", "Platta", "Klockan 21", "Spegel", "Lugn", "Tandborste", "Sked", "Ute", "En", "Logga", "Blomma", "Pil", "Ansikte", "Mynt", "Redo", "Mat", "Hål", "Idag", "I fickan", "Hemma", "Hud", "Dröm", "Klocka", "Stig", "Kort", "Klockan 19", "Gömt", "Långt borta", "Ljus", "Ord på S", "Hjälte", "Tre saker", "Favorit", "Ärtor", "Känsla", "Kläder", "TV", "Fordon", "Svart", "Träd", "Tacksam", "Otrolig", "Skugga", "Oreda", "Två saker", "Silluett", "Ord på P", "Ränder", "Klockan 6", "Musik", "I din hand", "Tyst", "Upp-och-ner", "Par", "Cykel", "Ensam", "Metall", "Kniv", "Hej", "Genom", "Mjölk", "Ritual", "Förändring", "Skarp", "Lila", "På vägen", "På väggen", "Kärlek", "Ord på D", "Perspektiv", "Går", "Klockan 12", "Grönt", "Plats", "Byggd", "Horisont", "Tur", "Tystnad", "Rök", "Löv", "Kopp", "Vision", "Ny", "Sömn", "Strand", "Ett rum", "På hyllan", "Riktning", "Tröst", "Uppifrån", "Juice", "Värme", "Fotsteg", "Lök", "Fågel", "Insiprerande", "Bok", "Trä", "Ledighet", "Fin", "Rund", "Hjälp", "Tyg", "I fönstret", "Datum", "Närbild", "Brunt", "Val", "Inne", "Bortglömd", "Motljus", "Dryck", "Detalj", "Rötter", "Kall", "Orättvisa", "Mjuk", "Visp", "Långsam", "Naturlig", "Vuxen", "Ord på T", "Skörd", "Klockan 24", "Inramad", "Arg", "Gåva", "Aktivitet", "Ort", "Fel", "100 stycken", "Form", "Rutor", "Intressant", "Besök", "Fransar", "Klockan 13", "Ord på R", "Ja", "Träning", "Glas", "Lila", "Spiral", "Öppen", "Balkong", "Hjul", "Talrik", "Mörkt", "I lådan", "Vackert", "Volym", "Siffra", "Ovant", "Tapet", "Banken", "Muskel", "Söm", "Glugg", "I trädgården", "Samtycke", "Ägg", "Tillsammans", "Alla", "Sil", "Hon", "Ledsen", "I trappan", "Klockan 8", "Grått", "Flingor", "Bakom", "Jord", "Enkel", "Härlig", "Jakt", "Sladdar", "Fram", "Krok", "Magnet", "Paraply", "Ord på Å", "Cirklar", "Rufsig", "Utrymme", "Öl", "Plast", "Näsa", "Stad", "Film", "Ärr", "Öga", "Lura", "Väntan", "Ost", "Saker", "Resa", "Bläck", "Livsviktigt", "Klockan 15", "En sak", "Farlig", "Sträng", "Varm", "Ord på E", "Instrument", "Vinkel", "Kedja", "I backen", "Bröd", "Framtiden", "Kastrull", "Trist", "Majs", "Barndom", "Nål", "Imperfekt", "Klackar", "Kam", "Arbete", "Korg", "Dragkedja", "Nej", "Bak", "Pankaka", "Rätt", "Ord på V", "Matta", "El", "Hjärta", "I flaskan", "Enkel", "Stickad", "Glitter", "Transparant", "Lunch", "Han", "Tidning", "Driva", "Dubbel", "Mössa", "Lucka", "Klockan 14", "Tillbaka", "Rött", "Sång", "Telefon", "Rörelse", "Situation", "Soffa", "Rader" ,"I år"]
  31. epoch = date(2014,1,1)
  32. def str_to_class(str):
  33. return getattr(sys.modules[__name__], str)
  34. class MyFirstIRCProtocol(irc.IRCClient):
  35. nickname = 'beats'
  36. private = False
  37. def signedOn(self):
  38. # This is called once the server has acknowledged that we sent
  39. # both NICK and USER.
  40. for channel in self.factory.channels:
  41. self.join(channel)
  42. # Obviously, called when a PRIVMSG is received.
  43. def privmsg(self, user, channel, message):
  44. nick, _, host = user.partition('!')
  45. message = message.strip()
  46. if swatch.findBeats(message):
  47. if channel == self.nickname or self.private:
  48. self.private = False
  49. # When channel == self.nickname, the message was sent to the bot
  50. # directly and not to a channel. So we will answer directly too:
  51. d.addCallback(self._send_message, nick)
  52. self._send_message(swatch.beat2time(swatch.findBeats(message)), nick)
  53. else:
  54. # Otherwise, send the answer to the channel, and use the nick
  55. # as addressing in the message itself:
  56. self._send_message(swatch.beat2time(swatch.findBeats(message)), channel)
  57. # scan all massages for urls dn.se, expressen.se aftonbladet.se
  58. # then unvisit them return a formated link
  59. if unvisit.findURL(message):
  60. if channel == self.nickname or self.private:
  61. self.private = False
  62. # When channel == self.nickname, the message was sent to the bot
  63. # directly and not to a channel. So we will answer directly too:
  64. d.addCallback(self._send_message, nick)
  65. self._send_message(unvisit.findURL(message), nick)
  66. else:
  67. # Otherwise, send the answer to the channel, and use the nick
  68. # as addressing in the message itself:
  69. self._send_message(unvisit.findURL(message), channel)
  70. # Scan all massages for google maps URLS
  71. # return with a mapcode
  72. if mapcode.findGoogleMapURL(message):
  73. if channel == self.nickname or self.private:
  74. self.private = False
  75. # When channel == self.nickname, the message was sent to the bot
  76. # directly and not to a channel. So we will answer directly too:
  77. d.addCallback(self._send_message, nick)
  78. self._send_message(mapcode.findGoogleMapURL(message), nick)
  79. else:
  80. # Otherwise, send the answer to the channel, and use the nick
  81. # as addressing in the message itself:
  82. self._send_message(mapcode.findGoogleMapURL(message), channel)
  83. # Scan all massages for mapcodes (see: mapcode.com)
  84. # return with a google link with coordinates
  85. if mapcode.findMapcode(message):
  86. if channel == self.nickname or self.private:
  87. self.private = False
  88. # When channel == self.nickname, the message was sent to the bot
  89. # directly and not to a channel. So we will answer directly too:
  90. d.addCallback(self._send_message, nick)
  91. self._send_message(mapcode.findMapcode(message), nick)
  92. else:
  93. # Otherwise, send the answer to the channel, and use the nick
  94. # as addressing in the message itself:
  95. self._send_message(mapcode.findMapcode(message), channel)
  96. if not message.startswith('!'): # not a trigger command
  97. return # do nothing
  98. command, sep, rest = message.lstrip('!').partition(' ')
  99. # Get the function corresponding to the command given.
  100. command = command.replace("ö","o")
  101. func = getattr(self, 'command_' + command, None)
  102. # Or, if there was no function, ignore the message.
  103. if func is None:
  104. return
  105. # maybeDeferred will always return a Deferred. It calls func(rest), and
  106. # if that returned a Deferred, return that. Otherwise, return the return
  107. # value of the function wrapped in twisted.internet.defer.succeed. If
  108. # an exception was raised, wrap the traceback in
  109. # twisted.internet.defer.fail and return that.
  110. d = defer.maybeDeferred(func, rest)
  111. # Add callbacks to deal with whatever the command results are.
  112. # If the command gives error, the _show_error callback will turn the
  113. # error into a terse message first:
  114. d.addErrback(self._show_error)
  115. # Whatever is returned is sent back as a reply:
  116. if channel == self.nickname or self.private:
  117. self.private = False
  118. # When channel == self.nickname, the message was sent to the bot
  119. # directly and not to a channel. So we will answer directly too:
  120. d.addCallback(self._send_message, nick)
  121. else:
  122. # Otherwise, send the answer to the channel, and use the nick
  123. # as addressing in the message itself:
  124. d.addCallback(self._send_message, channel, nick)
  125. def command_reload(self, rest):
  126. reimport.reimport(unvisit)
  127. reimport.reimport(help)
  128. reimport.reimport(salary)
  129. reimport.reimport(medborgarlon)
  130. reimport.reimport(swatch)
  131. reimport.reimport(mapcode)
  132. def command_help(self, rest):
  133. self.private = True
  134. input = rest.replace(",",".")
  135. return help.section()
  136. def command_medborgare(self, rest):
  137. self.private = True
  138. input = rest.replace(",",".")
  139. if(len(input)<1):
  140. return """Välkommen till medborgarkontoret, här kan du registrera dig som merborgare i #kalix detta ger dig rätten till medborgarlön.
  141. Använd kommandot: \n !medborgare registrering [nick] [kontonummer] \n
  142. för att bli medborgare, ersätt kontonummer med din bitcoin-address. \n Glöm inte att betala frivillig skatt till: 14DYxibJ4hzng4T7i9oeVUc3aATymQvLtR"""
  143. elif(input.split()[0].upper() == 'REGISTRERING'):
  144. return """Välkommen till #kalix, %s \n detta personnummer kommer du kunna använda för att ändra uppgifter, random handläggare kommer att kontrollera dina uppgifter innan utbetalningar görs.""" % medborgarlon.registerCitizen(input.split()[1], input.split()[2])
  145. else:
  146. return "Felaktigt kommando"
  147. def command_lon(self, rest):
  148. return(salary.get())
  149. def command_calc(self, rest):
  150. client = wolframalpha.Client("X2AY6V-99EUWXYAAG")
  151. res = client.query(str(rest))
  152. return next(res.results).text.encode('utf8').replace("\\:0e3f","")
  153. def command_g(self, rest):
  154. url = 'http://ajax.googleapis.com/ajax/services/search/web?'
  155. params = dict(
  156. v='1.0',
  157. q=rest
  158. )
  159. data = requests.get(url=url, params=params)
  160. binary = data.content
  161. output = json.loads(binary)
  162. title = output['responseData']['results'][0]['titleNoFormatting'].encode('ascii', 'ignore')
  163. url = output['responseData']['results'][0]['url']
  164. rtStr = ("Google: {0} {1}".format(title, url))
  165. return rtStr.decode('utf8').encode('iso-8859-1')
  166. def command_duck(self, rest):
  167. return duckduckgo.get_zci(str(rest)).encode('iso-8859-1')
  168. def command_temp(self, rest):
  169. input = rest.replace(",",".")
  170. if(len(input)<1):
  171. tempKalix = "http://api.temperatur.nu/tnu_1.12.php?p=kalix&verbose&cli=2"
  172. feed = feedparser.parse( tempKalix )
  173. rtStr = "%s C i Kalix" % feed['entries'][0]['temp']
  174. return rtStr.decode('utf8').encode('iso-8859-1')
  175. if(input.split()[0].upper() == 'KALIX'):
  176. tempKalix = "http://api.temperatur.nu/tnu_1.12.php?p=kalix&verbose&cli=2"
  177. feed = feedparser.parse( tempKalix )
  178. rtStr = "%s C i Kalix" % feed['entries'][0]['temp']
  179. return rtStr.decode('utf8').encode('iso-8859-1')
  180. elif(input.split()[0].upper() == 'NYBORG'):
  181. tempKalix = "http://api.temperatur.nu/tnu_1.12.php?p=kalix-nyborg&verbose&cli=2"
  182. feed = feedparser.parse( tempKalix )
  183. rtStr = "%s C i Nyborg" % feed['entries'][0]['temp']
  184. return rtStr.decode('utf8').encode('iso-8859-1')
  185. elif(input.split()[0].upper() == 'JKPG'):
  186. tempKalix = "http://api.temperatur.nu/tnu_1.12.php?p=torpa&verbose&cli=2"
  187. feed = feedparser.parse( tempKalix )
  188. rtStr = "%s C i Jkpg" % feed['entries'][0]['temp']
  189. return rtStr.decode('utf8').encode('iso-8859-1')
  190. elif(input.split()[0].upper() == 'LJUNGBY'):
  191. tempKalix = "http://api.temperatur.nu/tnu_1.12.php?p=fjallgatan&verbose&cli=2"
  192. feed = feedparser.parse( tempKalix )
  193. rtStr = "%s C i Ljungby" % feed['entries'][0]['temp']
  194. return rtStr.decode('utf8').encode('iso-8859-1')
  195. elif(input.split()[0].upper() == 'GBG'):
  196. tempKalix = "http://api.temperatur.nu/tnu_1.12.php?p=goteborg_ostra&verbose&cli=2"
  197. feed = feedparser.parse( tempKalix )
  198. rtStr = "%s C i GBG" % feed['entries'][0]['temp']
  199. return rtStr.decode('utf8').encode('iso-8859-1')
  200. elif(input.split()[0].upper() == 'STHLM'):
  201. tempKalix = "http://api.temperatur.nu/tnu_1.12.php?p=tallkrogen&verbose&cli=2"
  202. feed = feedparser.parse( tempKalix )
  203. rtStr = "%s C i Stockholm" % feed['entries'][0]['temp']
  204. return rtStr.decode('utf8').encode('iso-8859-1')
  205. def command_beat(self, rest):
  206. beats = swatch.time2beat(rest)
  207. return beats
  208. def command_time(self, rest):
  209. beats = swatch.time2beat(rest)
  210. return beats
  211. def command_tema(self, rest):
  212. from datetime import date
  213. today = date.today()
  214. dtstr = rest
  215. if len(dtstr) == 0:
  216. dtstr = "idag"
  217. if(dtstr == "idag"):
  218. delta = today - epoch
  219. say_theme = "Dagens fototema är: %s" % theme[int(delta.days)]
  220. elif dtstr == "imorgon":
  221. delta = today - epoch
  222. say_theme = "Morgondagens fototema är: %s" % theme[int(delta.days)+1]
  223. elif dtstr == "igår":
  224. delta = today - epoch
  225. say_theme = "Gårdagens fototema var: %s" % theme[int(delta.days)-1]
  226. elif dtstr == "help":
  227. say_theme = "Parametrar: idag, igår, imorgon, t.ex: 2/12"
  228. else:
  229. dtstr = dtstr.split("/",1)
  230. datestr = '2014-%s-%s' % (dtstr[1], dtstr[0])
  231. date = datetime.strptime(datestr, '%Y-%m-%d').date()
  232. delta = date - epoch
  233. say_theme = "Fototema för %s är: %s" % (datestr, theme[int(delta.days)])
  234. return say_theme
  235. def _send_message(self, msg, target, nick=None):
  236. if nick:
  237. msg = '%s' % (msg)
  238. self.msg(target, msg)
  239. def _show_error(self, failure):
  240. return failure.getErrorMessage()
  241. def command_ping(self, rest):
  242. return 'Pong.'
  243. def command_saylater(self, rest):
  244. when, sep, msg = rest.partition(' ')
  245. when = int(when)
  246. d = defer.Deferred()
  247. # A small example of how to defer the reply from a command. callLater
  248. # will callback the Deferred with the reply after so many seconds.
  249. reactor.callLater(when, d.callback, msg)
  250. # Returning the Deferred here means that it'll be returned from
  251. # maybeDeferred in privmsg.
  252. return d
  253. def command_uptime(self,rest):
  254. with open('/proc/uptime', 'r') as f:
  255. uptime_seconds = float(f.readline().split()[0])
  256. uptime_string = str(timedelta(seconds = uptime_seconds))
  257. return uptime_string
  258. class MyFirstIRCFactory(protocol.ReconnectingClientFactory):
  259. protocol = MyFirstIRCProtocol
  260. channels = ['#kalix', '#minecraft', '#undermind', '#kalix-test']
  261. #channels = ['#kalix-test']
  262. if __name__ == '__main__':
  263. # This runs the program in the foreground. We tell the reactor to connect
  264. # over TCP using a given factory, and once the reactor is started, it will
  265. # open that connection.
  266. reactor.connectTCP(HOST, PORT, MyFirstIRCFactory())
  267. # Since we're running in the foreground anyway, show what's happening by
  268. # logging to stdout.
  269. log.startLogging(sys.stdout)
  270. # And this starts the reactor running. This call blocks until everything is
  271. # done, because this runs the whole twisted mainloop.
  272. reactor.run()
  273. # This runs the program in the background. __name__ is __builtin__ when you use
  274. # twistd -y on a python module.
  275. elif __name__ == '__builtin__':
  276. # Create a new application to which we can attach our services. twistd wants
  277. # an application object, which is how it knows what services should be
  278. # running. This simplifies startup and shutdown.
  279. application = service.Application('MyFirstIRCBot')
  280. # twisted.application.internet.TCPClient is how to make a TCP client service
  281. # which we can attach to the application.
  282. ircService = internet.TCPClient(HOST, PORT, MyFirstIRCFactory())
  283. ircService.setServiceParent(application)
  284. # twistd -y looks for a global variable in this module named 'application'.
  285. # Since there is one now, and it's all set up, there's nothing left to do.