### # Copyright (c) 2019, Pedro de Oliveira # All rights reserved. # # Redistribution and use in source and binary forms, with or without # modification, are permitted provided that the following conditions are met: # # * Redistributions of source code must retain the above copyright notice, # this list of conditions, and the following disclaimer. # * Redistributions in binary form must reproduce the above copyright notice, # this list of conditions, and the following disclaimer in the # documentation and/or other materials provided with the distribution. # * Neither the name of the author of this software nor the name of # contributors to this software may be used to endorse or promote products # derived from this software without specific prior written consent. # # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. ### from supybot import utils, plugins, ircmsgs, ircutils, callbacks from supybot.commands import * import supybot.dbi as dbi import supybot.utils.minisix as minisix import sqlite3 import os from urllib.parse import urlparse import arrow try: from supybot.i18n import PluginInternationalization _ = PluginInternationalization('Old') except ImportError: # Placeholder that allows to run the plugin on a bot # without the i18n module _ = lambda x: x class SqliteEtaDB(object): def __init__(self, filename): self.dbs = ircutils.IrcDict() self.filename = filename def close(self): for db in self.dbs.values(): db.close() def _getDb(self, channel): filename = plugins.makeChannelFilename(self.filename, channel) if filename in self.dbs: return self.dbs[filename] if os.path.exists(filename): db = sqlite3.connect(filename, check_same_thread=False) if minisix.PY2: db.text_factory = str self.dbs[filename] = db return db db = sqlite3.connect(filename, check_same_thread=False) if minisix.PY2: db.text_factory = str self.dbs[filename] = db cursor = db.cursor() cursor.execute("""CREATE TABLE urltbl( id INTEGER PRIMARY KEY AUTOINCREMENT, nick TEXT NOT NULL, url TEXT UNIQUE NOT NULL, dt DATETIME NOT NULL )""") db.commit() return db def _fix_url(self, url): parsed_url = urlparse(url) if parsed_url.path == "": parsed_url = parsed_url._replace(path="/") return parsed_url.geturl() def add(self, channel, url, msg): db = self._getDb(channel) fixed_url = self._fix_url(url) cursor = db.cursor() cursor.execute("""INSERT INTO urltbl (nick, url, dt) VALUES (?, ?, ?)""", (msg.nick.lower(), fixed_url, msg.receivedAt,)) db.commit() def find(self, channel, url): db = self._getDb(channel) fixed_url = self._fix_url(url) cursor = db.cursor() cursor.execute("""SELECT nick, dt FROM urltbl WHERE url=?""", (fixed_url,)) return cursor.fetchone() URLDB = plugins.DB('Old', {'sqlite3': SqliteEtaDB}) class Old(callbacks.Plugin): """This plugin records URLs mentioned in a channel, and reports if it is old.""" def __init__(self, irc): self.__parent = super(Old, self) self.__parent.__init__(irc) self.db = URLDB() def doPrivmsg(self, irc, msg): if ircmsgs.isCtcp(msg) and not ircmsgs.isAction(msg): return if msg.channel: if ircmsgs.isAction(msg): text = ircmsgs.unAction(msg) else: text = msg.args[1] for url in utils.web.urlRe.findall(text): exists = self.db.find(msg.channel, url) if exists is None: self.log.debug('Adding %u to db.', url) self.db.add(msg.channel, url, msg) else: orig_nick = exists[0] orig_dt = exists[1] if orig_nick != msg.nick.lower(): no_hilight_nick = orig_nick[:1] + "" + orig_nick[1:] past = arrow.get(orig_dt) now = arrow.get(msg.receivedAt) dt_str = past.humanize(now) irc.reply("BAH! {}'s link is OLD! (shown {} by {})".format( msg.nick.lower(), dt_str, no_hilight_nick ), prefixNick=False) Class = Old # vim:set shiftwidth=4 softtabstop=4 expandtab textwidth=79: