Plugins build on top of Supybot to be used with LamperiBot

plugin.py 6.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. # encoding: UTF-8
  2. ###
  3. # Copyright (c) 2016, Toni Fadjukoff
  4. # All rights reserved.
  5. #
  6. # Redistribution and use in source and binary forms, with or without
  7. # modification, are permitted provided that the following conditions are met:
  8. #
  9. # * Redistributions of source code must retain the above copyright notice,
  10. # this list of conditions, and the following disclaimer.
  11. # * Redistributions in binary form must reproduce the above copyright notice,
  12. # this list of conditions, and the following disclaimer in the
  13. # documentation and/or other materials provided with the distribution.
  14. # * Neither the name of the author of this software nor the name of
  15. # contributors to this software may be used to endorse or promote products
  16. # derived from this software without specific prior written consent.
  17. #
  18. # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  19. # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  20. # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  21. # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
  22. # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  23. # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  24. # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  25. # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
  26. # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
  27. # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  28. # POSSIBILITY OF SUCH DAMAGE.
  29. ###
  30. import time
  31. from dateutil.rrule import *
  32. import supybot.utils as utils
  33. from supybot.commands import *
  34. import supybot.plugins as plugins
  35. import supybot.ircutils as ircutils
  36. import supybot.schedule as schedule
  37. import supybot.callbacks as callbacks
  38. try:
  39. from supybot.i18n import PluginInternationalization
  40. _ = PluginInternationalization('Timer')
  41. except ImportError:
  42. # Placeholder that allows to run the plugin on a bot
  43. # without the i18n module
  44. _ = lambda x: x
  45. class Timer(callbacks.Plugin):
  46. """Command based scheduling for triggers"""
  47. def __init__(self, irc):
  48. self.__parent = super(Timer, self)
  49. self.__parent.__init__(irc)
  50. self.events = {}
  51. def _makeCommandFunction(self, irc, msg, message):
  52. nickprefix = msg.prefix.split("!")[0] + ": " if ircutils.isChannel(msg.args[0]) else ""
  53. message = format("echo %s%s", nickprefix, message)
  54. tokens = callbacks.tokenize(message)
  55. def f():
  56. del self.events[str(f.eventId)]
  57. self.Proxy(irc.irc, msg, tokens)
  58. return f
  59. @staticmethod
  60. def _parseDate(arg):
  61. day = 0
  62. month = 0
  63. if len(arg) == 6 and arg[2] == arg[5] == "." and arg[0:2].isdigit() and arg[3:5].isdigit():
  64. day = int(arg[0:2])
  65. month = int(arg[3:5])
  66. elif len(arg) == 5 and arg[2] == arg[4] == "." and arg[0:2].isdigit() and arg[3:4].isdigit():
  67. day = int(arg[0:2])
  68. month = int(arg[3:4])
  69. elif len(arg) == 5 and arg[1] == arg[4] == "." and arg[0:1].isdigit() and arg[2:4].isdigit():
  70. day = int(arg[0:1])
  71. month = int(arg[2:4])
  72. elif len(arg) == 4 and arg[1] == arg[3] == "." and arg[0:1].isdigit() and arg[2:3].isdigit():
  73. day = int(arg[0:1])
  74. month = int(arg[2:3])
  75. if 0 < day < 32 and 0 < month < 13:
  76. return month, day
  77. return None
  78. @staticmethod
  79. def _parseTime(arg):
  80. if ":" in arg:
  81. hours, minutes = arg.split(":")
  82. elif "." in arg:
  83. hours, minutes = arg.split(".")
  84. elif len(arg) == 4:
  85. hours = arg[0:2]
  86. minutes = arg[2:4]
  87. elif len(arg) == 3:
  88. hours = arg[0]
  89. minutes = arg[1:3]
  90. elif len(arg) in (1,2):
  91. hours = arg
  92. minutes = "0"
  93. else:
  94. hours = None
  95. minutes = None
  96. if hours == None or len(hours) not in (1,2) or len(minutes) not in (1,2):
  97. return
  98. try:
  99. hours = int(hours)
  100. except ValueError as e:
  101. return
  102. try:
  103. minutes = int(minutes)
  104. except ValueError as e:
  105. return
  106. if minutes >= 60:
  107. hours += int(minutes / 60)
  108. minutes = minutes % 60
  109. if hours >= 24:
  110. hours = hours % 24
  111. return hours, minutes
  112. def _resolveTime(self, irc, dateArg, timeArg):
  113. month = mday = hours = minutes = None
  114. if dateArg != None:
  115. (month, mday) = self._parseDate(dateArg)
  116. (hours, minutes) = self._parseTime(timeArg)
  117. return list(rrule(MINUTELY, count = 1, bymonth = month, bymonthday = mday,
  118. byhour = hours, byminute = minutes))[0]
  119. def _testDate(date):
  120. return Timer._parseDate(date) != None
  121. def _testTime(time):
  122. return Timer._parseTime(time) != None
  123. def _scheduleOnce(self, irc, msg, message, scheduleTime):
  124. #irc.reply(format("Scheduled at %s", scheduleTime))
  125. f = self._makeCommandFunction(irc, msg, message)
  126. id = schedule.addEvent(f, scheduleTime)
  127. f.eventId = id
  128. self.events[str(id)] = f
  129. def timer(self, irc, msg, args, dateArg, timeArg, message):
  130. """[date] <time> <message>
  131. Set a message to be played back later.
  132. """
  133. scheduleTime = self._resolveTime(irc, dateArg, timeArg).timestamp()
  134. self._scheduleOnce(irc, msg, message, scheduleTime)
  135. timer = wrap(timer, [optional(('something', None, _testDate)), ('something', None, _testTime), 'text'])
  136. def food(self, irc, msg, args, minutes, message):
  137. """[minuutit] [viesti]
  138. Huomauta viestillä muutaman minuutin päästä.
  139. Pikakomennot: pizza 12 minuuttia, makaronilaatikko 60 minuuttia, ranskalaiset 30 minuuttia
  140. """
  141. irc.reply(format('Meikä kiekaisee sitten %i minuutin päästä %s', minutes, message))
  142. scheduleTime = time.time() + minutes * 60
  143. self._scheduleOnce(irc, msg, message, scheduleTime)
  144. food = wrap(food, ['positiveInt', 'text'])
  145. Class = Timer
  146. # vim:set shiftwidth=4 softtabstop=4 expandtab textwidth=79: