diff --git a/nxy/bot.py b/nxy/bot.py index 0858f7f..471f948 100644 --- a/nxy/bot.py +++ b/nxy/bot.py @@ -1,5 +1,4 @@ # -*- coding: utf-8 -*- -import sqlite3 import json import sys import os @@ -24,7 +23,7 @@ CFG_DEV = { } -# TODO: imdb, youtube, intensifies, pay, owe, rape (owe), ddg, regex, tell +# TODO: imdb, youtube, pay, owe, rape (owe), ddg, regex, tell def main(cfg_file): load_dotenv('.env') with open(cfg_file, 'r') as fp: diff --git a/nxy/plugins/__init__.py b/nxy/plugins/__init__.py index dd1eb05..4fcb329 100644 --- a/nxy/plugins/__init__.py +++ b/nxy/plugins/__init__.py @@ -1,4 +1,5 @@ # -*- coding: utf-8 -*- +from irc3.plugins.command import Commands from irc3 import IrcBot MODULE = __name__ @@ -8,6 +9,7 @@ class BasePlugin(object): def __init__(self, bot: IrcBot): self.bot = bot self.log = bot.log + self.guard = bot.get_plugin(Commands).guard class Plugin(BasePlugin): diff --git a/nxy/plugins/bitcoin.py b/nxy/plugins/bitcoin.py index 2491985..3d6bcb1 100644 --- a/nxy/plugins/bitcoin.py +++ b/nxy/plugins/bitcoin.py @@ -16,8 +16,7 @@ class Bitcoin(Plugin): ] @command - async def btc(self, mask: IrcString, channel: IrcString, - args: DocOptDict) -> str: + async def btc(self, mask: IrcString, channel: IrcString, args: DocOptDict): """Bitcoin command. %%btc """ diff --git a/nxy/plugins/ctcp.py b/nxy/plugins/ctcp.py index efca263..c668687 100644 --- a/nxy/plugins/ctcp.py +++ b/nxy/plugins/ctcp.py @@ -19,7 +19,7 @@ class CTCP(Plugin): 'irc3.plugins.command', ] - async def ctcp(self, ctcp: str, mask: IrcString, args: DocOptDict) -> str: + async def ctcp(self, ctcp: str, mask: IrcString, args: DocOptDict): nick = args.get('') or mask.nick name = ctcp.upper() ctcp = await self.bot.ctcp_async(nick, name, timeout=self.TIMEOUT) @@ -36,7 +36,7 @@ class CTCP(Plugin): @command async def ping(self, mask: IrcString, channel: IrcString, - args: DocOptDict) -> str: + args: DocOptDict): """CTCP ping command. %%ping [] """ @@ -58,7 +58,7 @@ class CTCP(Plugin): @command async def finger(self, mask: IrcString, channel: IrcString, - args: DocOptDict) -> str: + args: DocOptDict): """CTCP finger command. %%finger [] """ @@ -66,15 +66,14 @@ class CTCP(Plugin): @command async def time(self, mask: IrcString, channel: IrcString, - args: DocOptDict) -> str: + args: DocOptDict): """CTCP time command. %%time [] """ return await self.ctcp('TIME', mask, args) @command - async def ver(self, mask: IrcString, channel: IrcString, - args: DocOptDict) -> str: + async def ver(self, mask: IrcString, channel: IrcString, args: DocOptDict): """CTCP version command. %%ver [] """ diff --git a/nxy/plugins/mcmaniac.py b/nxy/plugins/mcmaniac.py index c83a13f..1039bad 100644 --- a/nxy/plugins/mcmaniac.py +++ b/nxy/plugins/mcmaniac.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- from docopt import Dict as DocOptDict from irc3.utils import IrcString -from irc3.plugins.command import command, Commands +from irc3.plugins.command import command from . import DatabasePlugin from ..utils import parse_int @@ -22,18 +22,17 @@ class McManiac(DatabasePlugin): """ cmd = args.get('') item = args.get('') - guard = self.bot.get_plugin(Commands).guard if cmd and item: - if guard.has_permission(mask, 'admin'): + if self.guard.has_permission(mask, 'admin'): if cmd == 'add': self.cur.execute('insert into mcmaniac (item) values (?)', [item]) if cmd == 'del': - order, index, op = parse_int(item, select=False) + index, order, op = parse_int(item, select=False) if not index: return - self.cur.execute('''delete from mcmaniac where id = - (select id from mcmaniac a where ? = (select count(id) + self.cur.execute('''delete from mcmaniac where id = + (select id from mcmaniac a where ? = (select count(id) from mcmaniac b where a.id {op} b.id) order by id {order}) '''.format(op=op, order=order), [index]) self.con.commit() @@ -45,7 +44,7 @@ class McManiac(DatabasePlugin): index = parse_int(index) if not index: return - order, index, _ = index + index, order, _ = index order = 'id {order}'.format(order=order) extra = 'offset ?' binds = [index] @@ -58,6 +57,6 @@ class McManiac(DatabasePlugin): (select count(id) from mcmaniac) as len from mcmaniac a order by {order} limit 1 {extra} '''.format(order=order, extra=extra), binds) - item = self.cur.fetchone() - if item: - return '[{idx}/{len}] {item}'.format(**item) + result = self.cur.fetchone() + if result: + return '[{idx}/{len}] {item}'.format(**result) diff --git a/nxy/plugins/quotes.py b/nxy/plugins/quotes.py index d8a9014..789468e 100644 --- a/nxy/plugins/quotes.py +++ b/nxy/plugins/quotes.py @@ -2,7 +2,6 @@ from docopt import Dict as DocOptDict from irc3.utils import IrcString from irc3.plugins.command import command -import random import irc3 import re @@ -20,42 +19,53 @@ class Quotes(DatabasePlugin): # noinspection PyUnusedLocal @command(options_first=True) - def q(self, mask: IrcString, channel: IrcString, args: DocOptDict) -> str: + def q(self, mask: IrcString, channel: IrcString, args: DocOptDict): """ Manage quotes. %%q ... - %%q [...] + %%q [] """ cmd = args.get('') nick = args[''] - quote = args.get('') - if cmd: - if cmd == 'add': - nick = self.REGEX.match(nick).group(1) - if nick not in self.db: - self.db[nick] = [] - quote = ' '.join(quote) - if quote not in self.db[nick]: - self.db[nick].append(quote) - elif cmd == 'del': - try: - self.db[nick].pop(parse_int(quote)) - if not self.db[nick]: - del self.db[nick] - except (KeyError, IndexError, TypeError): - return '' - self._db.SIGINT() - else: - if quote: - try: - quote = self.db[nick][parse_int(quote)] - except (KeyError, IndexError, TypeError): - return '' + item = args.get('') + print(cmd, nick, item) + if cmd and item: + if self.guard.has_permission(mask, 'admin'): + if cmd == 'add': + nick = self.REGEX.match(nick).group(1) + self.cur.execute('insert into quotes (nick, item) ' + 'values (?, ?)', [nick, ' '.join(item)]) + if cmd == 'del': + index, order, op = parse_int(''.join(item), select=False) + if not index: + return + self.cur.execute('''delete from quotes where id = + (select id from quotes a where nick like ? and ? = + (select count(id) from quotes b where a.id {op} b.id) + order by id {order}) + '''.format(op=op, order=order), [nick, index]) + self.con.commit() else: - quote = random.choice(self.db[nick]) - return '[{index}/{total}] <{nick}> {quote}'.format( - index=self.db[nick].index(quote) + 1, - total=len(self.db[nick]), - nick=nick, - quote=quote, - ) + self.bot.notice(mask.nick, 'Permission denied') + else: + index = args.get('') + binds = [nick] + if index: + index = parse_int(index) + if not index: + return + index, order, _ = index + order = 'id {order}'.format(order=order) + extra = 'offset ?' + binds.append(index) + else: + order = 'random()' + extra = '' + self.cur.execute('''select nick, item, + (select count(id) from quotes b where a.id >= b.id) as idx, + (select count(id) from quotes) as len + from quotes a where nick like ? order by {order} limit 1 {extra} + '''.format(order=order, extra=extra), binds) + result = self.cur.fetchone() + if result: + return '[{idx}/{len}] <{nick}> {item}'.format(**result) diff --git a/nxy/plugins/useless.py b/nxy/plugins/useless.py index 4bb7cb5..3f27978 100644 --- a/nxy/plugins/useless.py +++ b/nxy/plugins/useless.py @@ -56,9 +56,10 @@ class Useless(Plugin): self.bot.privmsg(channel, face) @command - def jn(self, mask: IrcString, channel: IrcString, args: DocOptDict) -> str: + def jn(self, mask: IrcString, channel: IrcString, args: DocOptDict): """Yes or no command. %%jn + %%jn """ choice = random.choice(['{green}Ja', '{maroon}Nein']) return fmt('{nick}: {bold}{color}%s' % choice, nick=mask.nick) @@ -82,8 +83,7 @@ class Useless(Plugin): nick=args['']) @command - def hack(self, mask: IrcString, channel: IrcString, - args: DocOptDict) -> str: + def hack(self, mask: IrcString, channel: IrcString, args: DocOptDict): """Hack command. %%hack [] """ @@ -93,16 +93,14 @@ class Useless(Plugin): return 'hacking{nick}...'.format(nick=nick) @command - def gay(self, mask: IrcString, channel: IrcString, - args: DocOptDict) -> str: + def gay(self, mask: IrcString, channel: IrcString, args: DocOptDict): """Gay command (alias to rainbow). %%gay ... """ return self.rainbow(mask, channel, args) @command - def rainbow(self, mask: IrcString, channel: IrcString, - args: DocOptDict) -> str: + def rainbow(self, mask: IrcString, channel: IrcString, args: DocOptDict): """Rainbow command. %%rainbow ... """ @@ -116,8 +114,7 @@ class Useless(Plugin): return fmt(''.join(word)) @command - def wrainbow(self, mask: IrcString, channel: IrcString, - args: DocOptDict) -> str: + def wrainbow(self, mask: IrcString, channel: IrcString, args: DocOptDict): """Word Rainbow command. %%wrainbow ... """ diff --git a/nxy/utils.py b/nxy/utils.py index f41e63e..07bd0eb 100644 --- a/nxy/utils.py +++ b/nxy/utils.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- from requests import request, Response +from datetime import timedelta from pprint import pprint import re @@ -30,27 +31,21 @@ FORMATTING = dict( underline='\x1F', # underlined text swap='\x16', # swap bg and fg colors ("reverse video") reset='\x0F', # reset all formatting - # COLORS - # white='\x0300', # white - # black='\x0301', # black - # blue='\x0302', # blue (navy) - # green='\x0303', # green - # red='\x0304', # red - # maroon='\x0305', # brown (maroon) - # purple='\x0306', # purple - # orange='\x0307', # orange (olive) - # yellow='\x0308', # yellow - # ltgreen='\x0309', # light green (lime) - # teal='\x0310', # teal (a green/blue cyan) - # ltcyan='\x0311', # light cyan (cyan / aqua) - # ltblue='\x0312', # light blue (royal) - # pink='\x0313', # pink (light purple / fuchsia) - # grey='\x0314', # grey - # ltgrey='\x0315', # light grey (silver) **COLORS ) # @formatter:on + +TIME_REGEX = re.compile(r'(\d+)([smhdwy])') +TIME_DICT = { + 's': ['seconds', 1], + 'm': ['minutes', 60], + 'h': ['hours', 3600], + 'd': ['days', 86400], + 'w': ['weeks', 604800], + 'y': ['years', 31449600], +} + # Debug helper pp = pprint @@ -65,22 +60,19 @@ async def req(method: str, url: str, **kwargs) -> Response: def time_to_sec(text: str) -> int: - match = re.match(r'(\d+)([smhdwy])', text) + match = TIME_REGEX.match(text) if match: - num, unit = match.groups() - num = int(num) - if unit == 's': - return num - elif unit == 'm': - return num * 60 - elif unit == 'h': - return num * 3600 - elif unit == 'd': - return num * 86400 - elif unit == 'w': - return num * 604800 - elif unit == 'y': - return num * 52 * 604800 + unit, num = match + return num * TIME_DICT[unit][1] + + +def time_delta(text: str) -> timedelta: + match = TIME_REGEX.match(text) + if match: + unit, num = match + if unit == 'years': + num *= 52 + return timedelta(**{TIME_DICT[unit][0]: num}) def parse_int(val: str, select: bool = True) -> tuple: @@ -96,7 +88,7 @@ def parse_int(val: str, select: bool = True) -> tuple: op = '>=' if select: val -= 1 - return order, val, op + return val, order, op except ValueError: pass diff --git a/schema.sql b/schema.sql index aa4ea93..1ef38a5 100644 --- a/schema.sql +++ b/schema.sql @@ -1,8 +1,8 @@ create table if not exists quotes ( id integer primary key autoincrement, nick text not null, - value text not null, - unique (nick, value collate nocase) + item text not null, + unique (nick, item collate nocase) ); create table if not exists mcmaniac (