Massive refactoring/-structuring

This commit is contained in:
mrhanky 2017-07-07 02:11:20 +02:00
parent a82175a44b
commit 59b67d9570
No known key found for this signature in database
GPG Key ID: 67D772C481CB41B8
41 changed files with 202 additions and 1011 deletions

7
.gitignore vendored
View File

@ -1,4 +1,5 @@
.env
config.json
.idea/
__pycache__/
.idea/
/.env
/config.json

25
FORMATTING.md Normal file
View File

@ -0,0 +1,25 @@
# Formatting
- bold: \x02
- color: \x03{color code}
- italic: \x1D
- underline: \x1F
- swap: \x16
- reset: \x0F
# Color codes
- white: 0
- black: 1
- blue: 2
- green: 3
- red: 4
- maroon: 5
- purple: 6
- orange: 7
- yellow: 8
- ltgreen: 9
- teal: 10
- ltcyan: 11
- ltblue: 12
- pink: 13
- grey: 14
- ltgrey: 15

View File

@ -10,19 +10,19 @@
* Create virtualenv and install dependencies
- ```mkvirtualenv -a $PWD -r $PWD/requirements.txt nxy```
* Create needed tables in the database:
- ```psql -U <your db user> < schema.sql```
* Copy ```.env-example``` and insert values in ```.env``` (replace everything wrapped in < and >)
- ```cp .env-example .env```
- ```psql -U <your db user> < files/schema.sql```
* Copy ```files/.env``` and insert values in ```.env``` (replace everything wrapped in < and >)
- ```cp files/.env .env```
- ```vim .env```
* Copy ```config.json``` and modify it (setup ZNC etc.)
- ```cp config.json-example config.json```
* Copy ```files/config.json``` and modify it (setup ZNC etc.)
- ```cp files/config.json config.json```
- ```vim config.json```
* If database is empty, run the migrate script to populate the database with old nxy data:
- ```python bot/migrate.py```
* If database is empty, import your database dump:
- ```psql -U nxy -d nxy < /path/to/dump.sql```
* Leave (auto) activated virtualenv and exit the bot's shell
- ```deactivate && exit```
* Copy systemd unit and enable it (would recommend the ```/usr/local``` prefix). Don't forget to modify the systemd unit if your user and home directory are different!
- ```sudo mkdir -p /usr/local/lib/systemd/system```
- ```sudo cp /home/nxy/nxy/nxy-bot.service /usr/local/lib/systemd/system```
- ```sudo ln -fs /home/nxy/bot/files/nxy-bot.service /usr/local/lib/systemd/system```
- ```sudo systemctl daemon-reload```
- ```sudo systemctl enable --now nxy-bot.service```

View File

@ -46,4 +46,8 @@ def main(cfg_file):
if __name__ == '__main__':
main(sys.argv[1])
if len(sys.argv) > 1:
config = sys.argv[1]
else:
config = 'config.json'
main(config)

View File

@ -20,7 +20,7 @@ class Plugin(BasePlugin):
# Import the PgSQL storage plugin
from .storage import Storage
from .storage import Storage # noqa: E402
class DatabasePlugin(Plugin):

View File

@ -12,8 +12,7 @@ from . import Plugin
class Coins(Plugin):
requires = ['irc3.plugins.command']
CRYPTOWAT = 'https://api.cryptowat.ch/markets/{market}/{crypto}{currency}' \
'/summary'
API_URL = 'https://api.cryptowat.ch/markets/coinbase/{crypto}{currency}/summary'
CURRENCIES = {
'usd': '$',
'eur': '',
@ -37,19 +36,16 @@ class Coins(Plugin):
"""
return self._cryptowat_summary('eth', args.get('<currency>') or 'usd')
def _cryptowat_summary(self, crypto: str, currency: str = 'usd',
market: str = 'coinbase'):
def _cryptowat_summary(self, crypto: str, currency: str = 'usd'):
# Check if valid currency + crypto2currency
if currency not in self.CURRENCIES or crypto == currency:
return
# Send request to api
data = requests.get(self.CRYPTOWAT.format(market=market,
crypto=crypto,
currency=currency))
data = requests.get(self.API_URL.format(crypto=crypto, currency=currency))
if data:
result = data.json()['result']
return '\x02[{crypto}]\x02 ' \
return '\x02[{crypto}]\x0F ' \
'Current: \x02\x0307{currency}{last:,.2f}\x0F - ' \
'High: \x02\x0303{currency}{high:,.2f}\x0F - ' \
'Low: \x02\x0304{currency}{low:,.2f}\x0F - ' \

View File

@ -14,13 +14,9 @@ class CTCP(Plugin):
requires = ['irc3.plugins.async',
'irc3.plugins.command']
@staticmethod
def _ctcp(name: str, nick: str, reply: str):
return '\x02[{name}]\x02 {nick}: {reply}'.format(
name=name.upper(),
nick=nick,
reply=reply,
)
# noinspection PyMethodMayBeStatic
def _ctcp(self, name: str, nick: str, reply: str):
return '\x02[{}]\x0F {}: {}'.format(name.upper(), nick, reply)
async def ctcp(self, name: str, mask: IrcString, args: DocOptDict):
nick = args.get('<nick>') or mask.nick
@ -30,7 +26,7 @@ class CTCP(Plugin):
if not data or data['timeout']:
reply = 'timeout'
elif not data['success']:
reply = 'Error: {reply}'.format(reply=data['reply'])
reply = 'Error: {}'.format(data['reply'])
else:
reply = data['reply']
@ -44,12 +40,12 @@ class CTCP(Plugin):
%%ping [<nick>]
"""
nick = args.get('<nick>') or mask.nick
data = await self.bot.ctcp_async(nick, 'PING {0}'.format(time.time()))
data = await self.bot.ctcp_async(nick, 'PING {}'.format(time.time()))
if not data or data['timeout']:
reply = 'timeout'
elif not data['success']:
reply = 'Error: {reply}'.format(reply=data['reply'])
reply = 'Error: {}'.format(data['reply'])
else:
delta = time.time() - float(data['reply'])
if delta < 1.0:
@ -57,7 +53,7 @@ class CTCP(Plugin):
unit = 'ms'
else:
unit = 's'
reply = '{delta:.3f} {unit}'.format(unit=unit, delta=delta)
reply = '{0:.3f} {1}'.format(delta, unit)
return self._ctcp('PING', nick, reply)

View File

@ -13,7 +13,7 @@ from . import DatabasePlugin
@irc3.plugin
class Useless(DatabasePlugin):
requires = ['irc3.plugins.command',
'nxy.plugins.storage']
'bot.plugins.storage']
@command
def isup(self, mask: IrcString, target: IrcString, args: DocOptDict):
@ -31,6 +31,4 @@ class Useless(DatabasePlugin):
state = 'up'
except requests.ConnectionError:
state = 'down'
return '{scheme}://{address} seems to be {state}'.format(scheme=parsed.scheme,
address=parsed.netloc,
state=state)
return '{}://{} seems to be {}'.format(parsed.scheme, parsed.netloc, state)

View File

@ -8,6 +8,7 @@ from irc3.plugins.command import command
from irc3.utils import IrcString
from . import Plugin
from ..utils import re_generator
GNU_LINUX = """I'd Just Like To Interject For A Moment. What you're referring
@ -21,16 +22,13 @@ GNU_LINUX = """I'd Just Like To Interject For A Moment. What you're referring
class Linux(Plugin):
KERNEL_FEED = 'https://www.kernel.org/feeds/kdist.xml'
@irc3.event(r'(?i)^:\S+ PRIVMSG (?P<target>\S+) :'
r'.*(debian|ubuntu|apt|dpkg).*')
@irc3.event(r'(?i)^:\S+ PRIVMSG (?P<target>\S+) :.*(debian|ubuntu|apt|dpkg).*')
def debillian(self, target: str):
"""Annoying RE trigger for debian with variable count of E."""
if random.randint(0, 3) is 0:
self.bot.privmsg(target, 'R{}'.format(''.join(
'E' for _ in range(random.randint(5, 20)))))
self.bot.privmsg(target, re_generator())
@irc3.event(r'(?i)^:\S+ PRIVMSG (?P<target>\S+) :'
r'.*(?<!gnu[/+])linux(?! kernel).*')
@irc3.event(r'(?i)^:\S+ PRIVMSG (?P<target>\S+) :.*(?<!gnu[/+])linux(?! kernel).*')
def linux(self, target: str):
"""Super annoying, useless 'Stallman is mad' trigger."""
if random.randint(0, 12) is 0:
@ -46,7 +44,7 @@ class Linux(Plugin):
# Cancel if no feed or entries
if not feed or not feed.get('entries'):
self.log.error('Error fetching kernel.org releases feed.')
self.log.error('Error fetching kernel.org releases feed')
return
# Make list of releases
@ -55,12 +53,8 @@ class Linux(Plugin):
version, branch = e['title'].split(': ')
if '(EOL)' in e['description']:
branch = '{branch}, \x1DEOL\x0F'.format(branch=branch)
branch = '{}, \x1DEOL\x0F'.format(branch)
releases.append('\x02{version}\x0F ({branch})'.format(
version=version,
branch=branch,
))
releases.append('\x02{}\x0F ({})'.format(version, branch))
return '\x02[Kernel]\x0F {releases}'.format(
releases=', '.join(releases))
return '\x02[Kernel]\x0F {}'.format(', '.join(releases))

View File

@ -13,7 +13,7 @@ from ..utils import parse_int
@irc3.plugin
class McManiac(DatabasePlugin):
requires = ['irc3.plugins.command',
'nxy.plugins.storage']
'bot.plugins.storage']
@command(options_first=True)
def mcmaniac(self, mask: IrcString, target: IrcString, args: DocOptDict):
@ -27,7 +27,7 @@ class McManiac(DatabasePlugin):
index = parse_int(index)
if not index:
return
index, order, _ = index
index, order = index
order = 'id {order}'.format(order=order)
offset = 'offset %s'
else:

View File

@ -1,23 +1,24 @@
# -*- coding: utf-8 -*-
import irc3
import re
import irc3
from docopt import Dict as DocOptDict
from irc3.plugins.command import command
from irc3.utils import IrcString
from psycopg2 import Error
from . import DatabasePlugin
from ..utils import NICK_REGEX, parse_int
from ..utils import parse_int
@irc3.plugin
class Quotes(DatabasePlugin):
requires = ['irc3.plugins.command',
'nxy.plugins.storage']
'bot.plugins.storage']
def add_quote(self, mask, nick, quote, channel):
# Parse nick from "<@foobar>" like strings
nick = NICK_REGEX.match(nick).group(1)
nick = re.match(r'<?[~&@%+]?([a-zA-Z0-9_\-^`|\\\[\]{}]+)>?', nick).group(1)
if not nick:
self.bot.notice(mask.nick, '[Quotes] Error parsing nick')
@ -31,7 +32,7 @@ class Quotes(DatabasePlugin):
''', [nick, quote, channel, mask.nick])
def delete_quote(self, nick, quote):
index, order, _ = parse_int(quote, select=False)
index, order = parse_int(quote, select=False)
if index:
# Delete from database
@ -91,7 +92,7 @@ class Quotes(DatabasePlugin):
index = parse_int(index)
if not index:
return
index, order, _ = index
index, order = index
order = 'rank {order}'.format(order=order)
offset = 'offset %s'
values.append(index)

View File

@ -13,7 +13,7 @@ from . import DatabasePlugin
@irc3.plugin
class Rape(DatabasePlugin):
requires = ['irc3.plugins.command',
'nxy.plugins.storage']
'bot.plugins.storage']
@command
def owe(self, mask: IrcString, target: IrcString, args: DocOptDict):

View File

@ -10,7 +10,7 @@ from . import DatabasePlugin
@irc3.plugin
class Useless(DatabasePlugin):
requires = ['irc3.plugins.command',
'nxy.plugins.storage']
'bot.plugins.storage']
@irc3.event(r'^:(?P<mask>\S+) PRIVMSG (?P<target>#\S+) :s/'
r'(?P<search>(?:[^/\\]|\\.)*)/'

View File

@ -14,7 +14,7 @@ from . import DatabasePlugin
@irc3.plugin
class Seen(DatabasePlugin):
requires = ['irc3.plugins.command',
'nxy.plugins.storage']
'bot.plugins.storage']
@command
def seen(self, mask: IrcString, target: IrcString, args: DocOptDict):
@ -62,10 +62,10 @@ class Seen(DatabasePlugin):
seens (nick, host, channel, message, seen_at)
values
(%s, %s, %s, %s, %s)
on conflict (nick) do update set
on conflict (nick) do update set
host = excluded.host,
channel = excluded.channel,
seen_at = excluded.seen_at,
seen_at = excluded.seen_at,
message = excluded.message
''', [mask.nick, mask.host, target, msg, datetime.now()])
self.con.commit()

View File

@ -13,7 +13,7 @@ from . import DatabasePlugin
@irc3.plugin
class Tell(DatabasePlugin):
requires = ['irc3.plugins.command',
'nxy.plugins.storage']
'bot.plugins.storage']
def __init__(self, bot: irc3.IrcBot):
super().__init__(bot)

View File

@ -15,7 +15,7 @@ from ..utils import time_delta
@irc3.plugin
class Timer(DatabasePlugin):
requires = ['irc3.plugins.command',
'nxy.plugins.storage']
'bot.plugins.storage']
def __init__(self, bot: irc3.IrcBot):
super().__init__(bot)

View File

@ -9,6 +9,7 @@ from irc3.utils import IrcString
from psycopg2 import Error
from . import DatabasePlugin
from ..utils import re_generator
RAINBOW = (5, 7, 8, 9, 3, 10, 12, 2, 6, 13)
RAINBOW_LEN = len(RAINBOW)
@ -17,7 +18,7 @@ RAINBOW_LEN = len(RAINBOW)
@irc3.plugin
class Useless(DatabasePlugin):
requires = ['irc3.plugins.command',
'nxy.plugins.storage']
'bot.plugins.storage']
WOAH = (
'woah',
'woah indeed',
@ -28,7 +29,7 @@ class Useless(DatabasePlugin):
@irc3.event(r'(?i)^:(?P<mask>\S+) JOIN :(?P<target>#\S+)$')
def tehkuh(self, mask, target):
if re.search(r'(?i).*(tehkuh).*@.*(telefonica|vodafone|kabel|unity-media).*', mask):
self.bot.privmsg(target, '{}: Bouncer'.format(nick))
self.bot.privmsg(target, '{}: Bouncer'.format(IrcString(mask).nick))
@irc3.event(r'(?i)^:\S+ PRIVMSG (?P<target>\S+) :.*(woah|whoa).*$')
def woah(self, target: str):
@ -41,10 +42,10 @@ class Useless(DatabasePlugin):
"""Returns a huehuehue when someone writes it."""
self.bot.privmsg(target, msg)
@irc3.event(r'(?i)^:\S+ PRIVMSG (?P<target>\S+) :reeeeee$')
@irc3.event(r'(?i)^:\S+ PRIVMSG (?P<target>\S+) :re+$')
def reeeeee(self, target: str):
"""Returns a REEEE."""
self.bot.privmsg(target, 'REEEEEEEEEEEEEEEEEEEEEEEEEEEE')
self.bot.privmsg(target, re_generator())
@irc3.event(r'(?i)^:\S+ PRIVMSG (?P<target>\S+) :same$')
def same(self, target: str):
@ -54,8 +55,7 @@ class Useless(DatabasePlugin):
@irc3.event(r'(?i)^:\S+ PRIVMSG (?P<target>\S+) :\[(?P<msg>.*)\]$')
def intensifies(self, target: str, msg: str):
"""String with brackets around will be returned with INTENSIFIES."""
self.bot.privmsg(target, '\x02[{msg} INTENSIFIES]'.format(
msg=msg.upper()))
self.bot.privmsg(target, '\x02[{} INTENSIFIES]'.format(msg.upper()))
@command
def kill(self, mask: IrcString, target: IrcString, args: DocOptDict):
@ -73,8 +73,8 @@ class Useless(DatabasePlugin):
limit
1
''')
self.bot.action(target, self.cur.fetchone()['item']
.format(nick=args.get('<nick>') or mask.nick))
nick = args.get('<nick>') or mask.nick
self.bot.action(target, self.cur.fetchone()['item'].format(nick))
@command
def yiff(self, mask: IrcString, target: IrcString, args: DocOptDict):
@ -92,8 +92,8 @@ class Useless(DatabasePlugin):
limit
1
''')
self.bot.action(target, self.cur.fetchone()['item']
.format(nick=args.get('<nick>') or mask.nick))
nick = args.get('<nick>') or mask.nick
self.bot.action(target, self.cur.fetchone()['item'].format(nick))
@command
def waifu(self, mask: IrcString, target: IrcString, args: DocOptDict):
@ -116,8 +116,7 @@ class Useless(DatabasePlugin):
waifu = excluded.waifu
''', [mask.nick, waifu])
self.bot.notice(mask.nick, 'Waifu set to: {waifu}'
.format(waifu=waifu))
self.bot.notice(mask.nick, 'Waifu set to: {}'.format(waifu))
except Error as ex:
print(ex)
self.con.rollback()
@ -133,9 +132,7 @@ class Useless(DatabasePlugin):
result = self.cur.fetchone()
if result and result['waifu']:
return '\x02[Waifu]\x0F {nick}: {waifu}'.format(
nick=nick,
waifu=result['waifu'])
return '\x02[Waifu]\x0F {}: {}'.format(nick, result['waifu'])
@command
def husbando(self, mask: IrcString, target: IrcString, args: DocOptDict):
@ -158,9 +155,8 @@ class Useless(DatabasePlugin):
husbando = excluded.husbando
''', [mask.nick, nick])
self.bot.notice(mask.nick, 'Husbando set to: {husbando}'
.format(husbando=nick))
except Error:
self.bot.notice(mask.nick, 'Husbando set to: {}'.format(nick))
except Error as ex:
print(ex)
self.con.rollback()
else:
@ -175,9 +171,7 @@ class Useless(DatabasePlugin):
result = self.cur.fetchone()
if result and result['husbando']:
return '\x02[Husbando]\x0F {nick}: {husbando}'.format(
nick=nick,
husbando=result['husbando'])
return '\x02[Husbando]\x0F {}: {}'.format(nick, result['husbando'])
@command
def storyofpomfface(self, mask: IrcString, target: IrcString,
@ -196,8 +190,7 @@ class Useless(DatabasePlugin):
%%choose <items>...
"""
choice = random.choice(' '.join(args['<items>']).split(','))
return '{nick}: {choice}'.format(nick=mask.nick,
choice=choice.strip())
return '{}: {}'.format(mask.nick, choice.strip())
@command
def jn(self, mask: IrcString, target: IrcString, args: DocOptDict):
@ -207,8 +200,7 @@ class Useless(DatabasePlugin):
%%jn
"""
choice = random.choice(['3Ja', '4Nein'])
return '{nick}: \x02\x03{choice}\x0F'.format(nick=mask.nick,
choice=choice)
return '{}: \x02\x030{}'.format(mask.nick, choice)
@command
def kiss(self, mask: IrcString, target: IrcString, args: DocOptDict):
@ -216,8 +208,7 @@ class Useless(DatabasePlugin):
%%kiss <nick>
"""
return '(づ。◕‿‿◕。)\x034。。・゜゜・。。・゜❤\x0F {nick} \x034❤'.format(
nick=args['<nick>'])
return '(づ。◕‿‿◕。)\x0304。。・゜゜・。。・゜❤\x0F {} \x0304❤'.format(args['<nick>'])
@command
def hug(self, mask: IrcString, target: IrcString, args: DocOptDict):
@ -225,7 +216,7 @@ class Useless(DatabasePlugin):
%%hug <nick>
"""
return '\x034♥♡❤♡♥\x03 {nick} \x034♥♡❤♡♥'.format(nick=args['<nick>'])
return '\x0304♥♡❤♡♥\x0F {} \x0304♥♡❤♡♥'.format(args['<nick>'])
@command
def bier(self, mask: IrcString, target: IrcString, args: DocOptDict):
@ -233,8 +224,8 @@ class Useless(DatabasePlugin):
%%bier [<nick>]
"""
self.bot.action(target, 'schenkt ein kühles Blondes an {nick} aus.'
.format(nick=args.get('<nick>') or mask.nick))
nick = args.get('<nick>') or mask.nick
self.bot.action(target, 'schenkt ein kühles Blondes an {} aus.'.format(nick))
@command
def fucken(self, mask: IrcString, target: IrcString, args: DocOptDict):
@ -242,8 +233,8 @@ class Useless(DatabasePlugin):
%%fucken [<nick>]
"""
self.bot.action(target, 'fuckt {nick} und tötet {nick} anschließend.'
.format(nick=args.get('<nick>') or mask.nick))
nick = args.get('<nick>') or mask.nick
self.bot.action(target, 'fuckt {0} und tötet {0} anschließend.'.format(nick, nick))
@command
def anhero(self, mask: IrcString, target: IrcString, args: DocOptDict):
@ -269,7 +260,7 @@ class Useless(DatabasePlugin):
%%hack [<nick>]
"""
nick = args.get('<nick>') or ''
return 'hacking{nick}...'.format(nick=' %s' % nick if nick else '')
return 'hacking{}...'.format(' %s' % nick if nick else '')
@command
def gay(self, mask: IrcString, target: IrcString, args: DocOptDict):
@ -300,9 +291,8 @@ class Useless(DatabasePlugin):
%%wrainbow <words>...
"""
return ' '.join([self._rainbow(i, word) for i, word
in enumerate(args['<words>'])])
return ' '.join([self._rainbow(i, word) for i, word in enumerate(args['<words>'])])
# noinspection PyMethodMayBeStatic
def _rainbow(self, i, char):
return '\x03{color}{char}'.format(color=RAINBOW[i % RAINBOW_LEN],
char=char)
return '\x030{}{}'.format(RAINBOW[i % RAINBOW_LEN], char)

View File

@ -38,8 +38,7 @@ class Weather(Plugin):
country=res['location']['country'],
temp=res['item']['condition']['temp'],
text=res['item']['condition']['text'],
direction='↑↗→↘↓↙←↖'[round(int(res['wind']['direction'])
/ 45) % 8],
direction='↑↗→↘↓↙←↖'[round(int(res['wind']['direction']) / 45) % 8],
speed=res['wind']['speed'],
unit_temp=res['units']['temperature'],
unit_speed=res['units']['speed'])

View File

@ -68,15 +68,13 @@ class YouTube(Plugin):
data = self._api(self.SEARCH, q=' '.join(args['<query>']))
if 'error' in data:
return '[YouTube] Error performing search'
return '\x02[YouTube]\x0F Error performing search'
elif data['pageInfo']['totalResults'] is 0:
return '[YouTube] No results found'
return '\x02[YouTube]\x0F No results found'
else:
video_id = data['items'][0]['id']['videoId']
return '{response} - https://youtu.be/{video_id}'.format(
response=self.get_video_data(video_id),
video_id=video_id,
)
data = self.get_video_data(video_id)
return '{} - https://youtu.be/{}'.format(data, video_id)
@staticmethod
def _api(url: str, **kwargs):

5
bot/server.py Normal file
View File

@ -0,0 +1,5 @@
# -*- coding: utf-8 -*-
import irc3d
if __name__ == '__main__':
irc3d.run()

54
bot/utils.py Normal file
View File

@ -0,0 +1,54 @@
# -*- coding: utf-8 -*-
import re
import random
from pprint import pprint
from datetime import datetime, timedelta
TIME_UNITS = {
's': 'seconds',
'm': 'minutes',
'h': 'hours',
'd': 'days',
'w': 'weeks',
'mon': 'months',
'y': 'years',
}
pp = pprint
def date_from_iso(date: str) -> datetime:
return datetime.strptime(date, '%Y-%m-%dT%H:%M:%S.%fZ')
def time_delta(text: str) -> timedelta:
match = re.match(r'(\d+)(s|m|h|mon|w|y)', text)
if match:
num, unit = match.groups()
num = int(num)
unit = TIME_UNITS[unit]
if unit == 'mon':
num *= 4
elif unit == 'y':
num *= 52
return timedelta(**{unit: num})
def parse_int(val: str, select: bool = True) -> tuple:
try:
val = int(val)
if val is not 0:
if val < 1:
order = 'desc'
val *= -1
else:
order = 'asc'
if select:
val -= 1
return val, order
except ValueError:
pass
def re_generator(low: int = 5, high: int = 20) -> str:
return 'R{}'.format(''.join('E' for _ in range(random.randint(low, high))))

View File

@ -1,7 +1,7 @@
{
"username": "nxy",
"host": "znc.host",
"port": 1337,
"host": "localhost",
"port": 6667,
"ssl": true,
"autojoins": ["#nxy-dev"],
"flood_burst": 1,
@ -9,22 +9,22 @@
"flood_rate_delay": 1,
"includes": [
"irc3.plugins.uptime",
"nxy.plugins.admin",
"nxy.plugins.coins",
"nxy.plugins.ctcp",
"nxy.plugins.isup",
"nxy.plugins.linux",
"nxy.plugins.mcmaniac",
"nxy.plugins.quotes",
"nxy.plugins.rape",
"nxy.plugins.regex",
"nxy.plugins.seen",
"nxy.plugins.tell",
"nxy.plugins.timer",
"nxy.plugins.urban",
"nxy.plugins.useless",
"nxy.plugins.weather",
"nxy.plugins.youtube"
"bot.plugins.admin",
"bot.plugins.coins",
"bot.plugins.ctcp",
"bot.plugins.isup",
"bot.plugins.linux",
"bot.plugins.mcmaniac",
"bot.plugins.quotes",
"bot.plugins.rape",
"bot.plugins.regex",
"bot.plugins.seen",
"bot.plugins.tell",
"bot.plugins.timer",
"bot.plugins.urban",
"bot.plugins.useless",
"bot.plugins.weather",
"bot.plugins.youtube"
],
"irc3.plugins.command": {
"guard": "irc3.plugins.command.mask_based_policy",

View File

@ -5,9 +5,8 @@ After=network.target znc.service
[Service]
Type=simple
User=nxy
Environment=PYTHONPATH=/home/nxy/nxy
WorkingDirectory=/home/nxy/nxy
ExecStart=/home/nxy/.virtualenvs/nxy/bin/python nxy/bot.py config.json
WorkingDirectory=/home/nxy/bot
ExecStart=/home/nxy/.virtualenvs/nxy/bin/python -m bot
[Install]
WantedBy=multi-user.target

View File

@ -72,11 +72,3 @@ create table if not exists last_messages (
item text not null,
unique (nick, channel)
);
select
item
from
last_messages
where
nick = lower('m')
and channel = lower('nxy-dev');

View File

@ -1,22 +0,0 @@
rips off {user}'s legs and leaves them to die.
grabs {user}'s head and rips it clean off their body.
grabs a machine gun and riddles {user}'s body with bullets.
gags and ties {user} then throws them off a bridge.
crushes {user} with a huge spiked boulder.
glares at {user} until they die of boredom.
shivs {user} in the heart a few times.
rams a rocket launcher up {user}'s ass and lets off a few rounds.
crushes {user}'s skull in with a spiked mace.
unleashes the armies of Isengard on {user}.
gags and ties {user} then throws them off a building to their death.
reaches out and punches right through {user}'s chest.
slices {user}'s limbs off with a sharpened Katana.
throws {user} to Cthulu and watches them get ripped to shreds.
feeds {user} to an owlbear who then proceeds to maul them violently.
turns {user} into a snail and salts them.
snacks on {user}'s dismembered body.
stuffs some TNT up {user}'s ass and waits for it to go off.
puts {user} into a sack, throws the sack in the river, and hurls the river into space.
goes bowling with {user}'s bloody disembodied head.
sends {user} to /dev/null!
feeds {user} coke and mentos till they violently explode.

View File

@ -1,315 +0,0 @@
Mc2GiaC
Mc420iaC
McAbhängiaC
McAbnehmiaC
McAdminiaC
McAllesiaC
McAmmoniaC
McAniByteiaC
McApothekiaC
McArbeitiaC
McAriaC
McAssfistiaC
McAstrophysiaC
McAussichtiaC
McAutistiaC
McBSDiaC
McBackForthiaC
McBadboiaC
McBehindiaC
McBeileidiaC
McBelstiaC
McBertiaC
McBlondiaC
McBodybuildiaC
McBotiaC
McBroiaC
McBuschiaC
McChemtrailiaC
McClaniaC
McConnectiaC
McCrackiaC
McCubiaC
McDafüriaC
McDanceyiaC
McDeadliftiaC
McDefektiaC
McDegradeiaC
McDepressiviaC
McDissiaC
McDoktoriaC
McDonaldiaC
McDonaldsiaC
McDonaldsmitterminaliaC
McDotiaC
McDreadiaC
McDrogiaC
McDruffiaC
McEinhorniaC
McExcercisiaC
McFahrradiaC
McFauliaC
McFettiaC
McFettsackiaC
McFickDichiaC
McFidelitiaC
McFinallyHatWiederEinSSLCertiaC
McFitiaC
McFlaumiaC
McFlummiaC
McFoobariaC
McFrostiaC
McFuckiaC
McFunkiaC
McFühriaC
McGFXiaC
McGayiaC
McGeburtstiaC
McGehtimmerfrühonsBettiaC
McGeilershitiaC
McGeiliaC
McGewichthebiaC
McGleichgewichtiaC
McGlitzerkugeliaC
McGlitzermuscheliaC
McGreisiaC
McGriesgramiaC
McGumoniaC
McGutenMorgeniaC
McGutenmorgeniaC
McHDDdestroyeriaC
McHaltetdochalleeurefressiaC
McHartzIViaC
McHashfagiaC
McHashiaC
McHaskelliaC
McHebiaC
McHeisenbergiaC
McHelmiaC
McHighiaC
McHighlightiaC
McHitleriaC
McHollandiaC
McHubbliaC
McHübschiaC
McIRCiaC
McIchküssehierrumwiefickiaC
McIchscheißaufsicherheitiaC
McIdliaC
McInfideliaC
McInvalidiaC
McIstimmermüdiaC
McIstwiederdaiaC
McJavascriptiaC
McJogginghosiaC
McJsisscheißiaC
McJukeboxiaC
McKanakiaC
McKaputtiaC
McKawaiiswagiaC
McKeindoktoriaC
McKeinschweißiaC
McKinderfickiaC
McKlabusterbeeriaC
McKnastiaC
McKnuddeliaC
McKoksiaC
McKomplettiaC
McKonzentrationslageriaC
McKotlplsiaC
McKraftwerkiaC
McKrankiaC
McKreatiniaC
McKrebsiaC
McKuffariaC
McKurdiaC
McKüssiaC
McLRSiaC
McLauchiaC
McLaufiaC
McLayerwerbungiaC
McLebtnureinmaliaC
McLeichtsinniaC
McLeschiaC
McLiftiaC
McLochinderschädeldeckiaC
McLowprozessoriaC
McLurchiaC
McLustigiaC
McLächerlichiaC
McLösiaC
McLügiaC
McM1iaC
McMCiaC
McManiaC
McManischdepressiviaC
McMaschiniaC
McMathematiaC
McMathiaC
McMaximiaC
McMcManiaCiaC
McMcMcMciaCiaCiaCiaC
McMeddliaC
McMeinuniaC
McMemeiaC
McMemiaC
McMetaiaC
McMethiaC
McMidlifeCrisiaC
McMilchreisiaC
McMilfickiaC
McMitgliediaC
McMopediaC
McMorgenmuffeliaC
McMorniaC
McMotorradiaC
McMotziaC
McMurukiaC
McMuskeliaC
McMuskelkateriaC
McMuskelniaC
McMüdiaC
McNachtiaC
McNamiaC
McNatursektiaC
McNaziaC
McNerdiaC
McNilsiaC
McNixPeiliaC
McNoClueiaC
McNoHaskelliaC
McNoMediziniaC
McNochWachiaC
McNopeiaC
McNormalerSchlafrhythmusiaC
McNormiaC
McNorwegiaC
McNuBSDiaC
McNubiaC
McOdroidiaC
McOrciaC
McOwealotiaC
McOwiaC
McPartymakeriaC
McPausiaC
McPedophiliaC
McPeppiaC
McPersoniaC
McPortiaC
McPrinzessinaufderErbsiaC
McPrüdiaC
McPumpiaC
McPythoniaC
McQsciaC
McRIPiaC
McRaidkilleriaC
McRapeiaC
McRauchiaC
McRecycliaC
McReißiaC
McRepostiaC
McRespectiaC
McRetardiaC
McRipiaC
McRookiaC
McRpiaC
McRückwärtsalteriaC
McScharfiaC
McSchlafiaC
McSchwitziaC
McSchwuliaC
McScrolliaC
McServerlockiaC
McSheytaniaC
McShugoTenshiaC
McSmetbiaC
McSpaßverderbiaC
McSpeediaC
McSportiaC
McSpätmerkiaC
McStandhaftiaC
McStarkiaC
McStartssliaC
McStatistiaC
McStemmiaC
McSterbiaC
McStoßiaC
McStripperiaC
McSubmissiviaC
McSztisttrauriaC
McSüßiaC
McTeamspeakiaC
McTotalerkriegiaC
McTraeumiaC
McTsuiaC
McUWiaC
McUltraNubiaC
McUmlautiaC
McUnfaehigiaC
McUngläubiaC
McUnixiaC
McUnwetteriaC
McUwiaC
McVapeiaC
McVapiaC
McVerdieniaC
McVergasiaC
McVergewaltiaC
McVerrücktiaC
McVerschwöriaC
McVertretiaC
McVoluminösiaC
McVorDieHaustuereGekacktiaC
McWaffelteigiaC
McWankiaC
McWeakiaC
McWeckiaC
McWeediaC
McWerdeniebezahliaC
McWerkiaC
McWettkampfiaC
McWhoriaC
McWortwolkiaC
McZeltiaC
McZubreitfürdenspiegeliaC
McalwaysonlineiaC
McediTiaC
McgegenteiliaC
McÖdiaC
McSchwuliaC
McSelbsttriggertriggeriaC
McUngläubiaC
McParanoiaC
McWaliaC
McWaldiaC
McTreniaC
McBurkiaC
McSchnefalliaC
McAmmoniaC
McAmmoniaC
ichbingarkeinmaniac
McThcZäpfcheniaC
McImperativiaC
McGysiaC
McDrogiaC
McGefängnisiaC
McArschseksiaC
McKommentarboxeinfachdirektunterdemletztenkommentariaC
McHeisseOhreniaC
McManiulo
McRallyaC
McMöchtiaC
McOdroidiaC
McRektiaC
McMemeiaC
McHantelstangiaC
Mc1iaC
McNixfunktioniertiaC
McBigMac
McExtremstschwuliaC
McSchnelliaC
McRomantiaC
McOssiaC
McHaskelliaC
McSchlafiaC
McGenderiaC

View File

@ -1,185 +0,0 @@
asks if {user} would like to dock and he happily agrees. The two giraffe dongs slosh into each other as the two sexy gorfs make out
bounces all around {channel}, focusing on {user} and {yiffer}. *PANT PANT* (drags is dingo cock on the ground) "hey guise!! which one of you wants to plow my dirty dog baloon knot??"
brushes his large zebradong against {user}'s asshole. {user} quickly screams "PUT IN IN ME" and {nick} obeys hir request. Then, {user} becomes jealous and gallops over to face fuck {user}.
busts a huge creamy yiffload all over {user}
can't help but fuck the everliving shit out of {user} with a huge foxdick
can't take anymore, he gasps for his breath as he unloads his potent fox seed all over {user}'s turtle tits
caresses {user}'s furry ballsack, inhaling {user}'s sweet musk through his nostrils, his member starting to grow from all the sensations
clenches his firm, supple buttocks around the throbbing purple head of {user}'s skunkcock
climbs on top of {user} and roars as she buttfucks the horny lion
continues swirling her tongue around against {user}'s, as she guides one of his hands down to the waistband of her skirt, pushing the tips of his fingers between her panties and skirt
creates a disgusting, putrid odor in {channel} causing several users to vomit onto each other, including {user} and {yiffer}. {nick} blushes when she sees what she has caused
critches the inside of {user}'s rosebud with his entire hand while lapping up the fountain of badger butter escaping from {user}'s engorged member
drags a foxy claw across the ridges {user}'s circumcision scar.
drinks from the pool of thick giraffe jizzum that {user} and {yiffer} have been creating in the corner of {channel}
enflames her smegmated goosepussy, hoping that {user} notices! "Aim for the slightly red stained feathers!" *flap flap*
engulfs {user}'s wolfcock, relishing the salty taste of the his precum
exposes his sheath to {user}, while slowly raising his tail as if to invite
eyes that splurt of cockjuice with interest, using her tail to then push it firmly up against {user}'s ass, nudging the head against the open ring of flesh.
feels {user}'s knot throbbing inside him, each pulse unleashing a fire hot load deep in his bowels, sating his lust momentarily
felt {user}'s lukewarm wolfhood enter him time and time again, making his pussy lips twitch and love juice flow incessantly.
fills {user} with giraffe juice creating a beautiful roselike odor in {channel}
flaps his wings wildly as {user} pounds him mercilessly, all while giving his duck dong a firm handshake with his free paw
gallops gingerly over to {user}'s bed and sits on the corner, showing his fangs in a friendly way. Suddenly {nick} slides his rump down {user}'s bedsheets, leaving a horrible nasty brown streak that smells like musk!!
gallops over to {user} and attempts to plug his massive gorfdong into her tight gorfgina, but {user} quickly knocks over {nick} with her large, spotted neck and slams her wet giraffe meat into {nick}'s butthole
gave {user} a nice and solid kick, making him collapse onto the floor, cupping {user}'s foxballs.
gently slides his paw over {user}'s right foot while gliding a finger over his tailhole in anticipation
gets a firm grip on {user}'s hip as he thrusts his foxhood deep within his tight and inexperienced tailhole, unexpectedly ramming his knot causing an orgasm of pain and pleasure for {user}
gleefully backs his volerectum firmly into {user}'s cloaca, hoping that {user} is a snake... SHOW ME YOUR HEMIPENE AND RAPE MY SHITTER BITCH!
grabs {user}, twirls him around like a dancer and places a kiss on his lips, fondling his tailhole for a second so he can taste it later
grunts as he feels sthe plastron of {user}'s shell rubbing him raw, but moans as he feels {user}'s dick stiffen inside him and his thrusting speeds up
gyrates her ferret-giner into {user}'s face, forcing him to take in the scent of stale urine and cedar chips...
hops onto {user}'s lap, her bare crotch resting on his pants, and getting them a little wet from her dripping juices
howls with pleasure as {user} pulls his knot out of his hole, stretching it to an obscene size before a loud "POP" is heard and {user}'s squirreljuice cascades down his already drenched thighs
initiates the cuddle pile of Cthulu! Fuzzy tentacles being to lash out and drag {user} into the maw of Murrrrr.
inserts a giner into {user}'s raccoon sheef, pumping in and out to create sheefsounds of varying pitches and phonetic properties
is plundging deep into {user}'s anal cavity, getting fur all over the place
is puzzled by {user}'s single cock as it's pressed against his chest stomach.
jumps out of {user}'s packpack and sticks her butt out at {user}, revealing her bare butt cheeks her clenched asshole and pink pussy lips, and waving her tail around at him
knocks {user} back a few feet with a stream of hot jizzum!
lactates into a jar and hands it to {user}. {user} quickly becomes jealous of the gift and proceeds to knock the jar out of {user}'s paws and happily slurps up the man milk
lays on her back and sticks a finger into her pussy, spreading the lips of her pussy apart with her other hand and showing {user} the little cherry-clit between the spread mounds
lays under {user}, her bare crotch covered in her juices
lets loose a hot steamy load all over {user}'s tongue!
lets out a low moan as {user}'s tongue rubs against hers, sharing their saliva and spreading the lollipop sugar onto his tongue
lets out an excited squeal as {user} walks into the back yard, and hopes he doesn't see her laying back in a lawn chair naked
lets out a sigh of pleasure, and putting her hand on top of {user}'s, guides his hand to be cupping around her small titty, pressing her nipple between two of his fingers, and sliding his fingers back and forth against it
lets out small gasps as {user} gets closer to her nipples, her shirt riding up on his arm to the point where it isn't really covering much of her anymore
lets out small gasps as {user}'s hand touches her sensitive nipple directly
lets the last of her pee trickle out of her onto the floor around {user}, before she sits on the floor in front of him, his seated face right in line with her clit
licks along {user}'s silky lips, taking {user}'s exposed foxhood and plays with the tip, rubbing the underside with his thumb slowly towards the tip
licks {user}'s chest at the same place where he poked her and says, "mmmm it sure is nice and warm there" as she plants small kisses on the spot, licking his bare skin
lifts up pulls down {user}'s pants, showing her panties to {user} and says, "hey {user}, why don't you help {user} out of those naughty panties?"
looks around {channel} for her love... WHERE ARE YOU {user}??? oh there you are!! {nick} plants a wet donkey kiss on {user}'s furry cock head, fully expecting to get raped in response!!
looks at {user} and asks, "hey what cup size are your boobies? =D"
looks at {user} and notices he is covered in pee too
looks at {user}'s undies in her hand
looks down at her tightened cooch, smiling at {user} and giving him a kiss on the tip of his nose
looks longingly at {user}'s moist falcon cock.... pushing aside the silken down and grabbing its base... suddenly {nick} whips out some Gold Bond(R) with menthol, and sprinkles it on {user}'s wet bird of prey dong!!! {user} caws and shrieks in pain, slashing {nick}'s face with his flight feathers!! YOU ASSHOLE it always come down to abuse!!
looks up and waves at {user}, spreading her pussy lips open for him to get a good view inside of her 9-year-old slit
looks up at {user} with a cute wide-eyed look. Hir sweet ice-cream tasting pom-pom is nibbled on, moaning even louder before clinging to hirself tightly at feeling of the licks at hir sensitive pompom. "ahh ahh!! oh! kupopo!!"
Masterbates, shoots a load into {user}'s right eye and with a single motion shares the love with @ {user}'s left eye. Then {nick} wipes the excess and tickles {user}'s nose simultaneously with his oh so tiny asian cock, and then finalizes the deal with a free rectal exam.
milks his cock and drizzles pre into the coffee pot to see if {user} can taste the difference.
moans, "aahh... mmm. aaahh..." as {user}'s finger moves around inside of her pussy, her juices seeping out onto his hand
mounts {user} and pumps in and out hard
moves over towards {user} and shoves a huge red rocket in thier mouth
murrs as he slides his paw over {user}'s throbbing raccoon cock
murrs, humping softly against {user}'s hand, twisting the tip of his finger into {user}'s lovingly rendered anus
neighs and shudders as his cockhead flares and spews his buttery load, almost choking {user}
nibbles softly on the carrot potruding from {user}'s juicy hole as {user}'s fluffy bunnytail tickle's his face
notices {user} is leaking a pink liquid out of his anus and he gallops over to go drink the cloudy butt juice. The strange rectum goo is sweet and tastes like a combonation of strawberries and love
notices {yiffer} buttfucking {user} while {user} screams. {nick} pulls out his rock hard monster of a gorfdong and uses it shut up {user}. {yiffer} thanks {nick} and continues fucking his prey
opens her legs all the way and faces {user}, giving him a complete view of her pussy
opens her lips slightly, and probes {user}'s larger lips with her lollipop-sugar-coated tongue
opens his trap door in the desert floor and scurries over to {user}, trying to get at her succulant scorpion snatch! {user} sees this coming and slams her stinger into the sand, failing to realize that a spider is a small and fast target. {nick} drags {user} out of his trap and throws the web-encrusted prize at {user}, momentarily stunning her!
pants as {user}'s dripping wet pokeball rests in her hand, and she tosses it to the ground, releasing him as she tries to catch her breath from all the pushing she did
parts {user}'s buttcheeks and moves his cock into their anus
peers anxiously at {user}'s encrusted, pulsating wolverine anus... I can't take it any longer, UNLOAD YOUR LOG ON ME BABY!!! {yiffer} can watch!
picks up {user} and glares at him "look what you did to me" she says as she puts his head in the gaping hole of her pussy
picks up {user} out of the puddle, and takes off all of his pee-covered clothes, licking and sucking the pee out of them, swallowing, and saying, "yummmmmy!"
pokes a finger into {user}'s moist sheath, tasting the tip of his finger in excitement
props {user}'s dead furry body over his chair and furiously humps, climaxing into his cold cadaver
pulls both of {user}'s hands onto her butt cheeks
pulls down {user}'s pants and points to the hole in the tip of his penis
pulls off her dress and rubs her fuzzy back against {user}'s chest
pulls the neck of {user}'s shirt down to show her nipples as she says, "i'm flat as a board, see!"
pumps gallons of jizz all over {user} !
pushes down on {user}'s rock hard wolf-cock with his palm, sliding around with his precum
pushes down onto {user}'s lap with his weight, thrusting {user}'s knot deep within his tailhole
pushes off of {user}'s shoulders with her hands and quickly pulls her panties down to her knees, the small wet spot right against his nose as her bare pussy rubs on the back of his neck
pushes people aside just so he can shoot his load all over {user}'s face!
pushes {user} feet first into her cunt and squeezes her muscles down on him, burrying him so only his head is sticking out of her pussy
pushes {user} out until he is only buried waist deep inside of her, pushes his hands up onto her clit and says, "hold on tight, i'm going to pee on you for being mean to me and stretching me out"
pushes {user}'s head into her crotch as he stimulates her clit, his finger still slipping in and out of her pussy, her breath coming in shorter gasps now as she says, "{user}... i'm feeling... aahhh... oooohh i'm feeling so gooooooood.... uuuhhhh"
pushes up with her legs against the couch, her head popping out of the collar of {user}'s shirt, and with their faces pressed up against eachother's, she plants a kiss on his lips
puts a finger in her 9-year-old asshole, "stick it right in here {user}, get your penis nice and wet in my mouth before you stick it in so it slides easy"
puts her arms around {user}'s neck and says as she wraps her legs and bare crotch around {user}'s waist, "oh really? what else did they teach you there?"
puts her hand in {user}'s underwear
puts her hands on {user}'s crotch and says, "see, it's right here! i can feel it moving around too =D"
puts his fingers on {user}'s mouth to shush him as he starts working his throbbing foxhood
puts his muzzle between {user}'s smooth thighs and starts lapping at her slippery clit
puts on a two-piece bathing suit and opens the door, running past {yiffer} and jumping into {user}'s arms, saying, "look, now i can be almost naked but still have clothes on!" as she places his hand on her bare stomach
puts {user} in her mouth, licking all over him
raises her hips a little as {user}'s finger slides into her, causing it to slip in even further into her drenched pussy, and says, "mmmmmm that's really good {user}, keep your finger there"
raises her tail high, showing {user} her blood engorged claoca from accross the irc channel, hoping to lure him into a mid-chat yiff
reaches backwards and rubs her hands against {user}'s sides, slipping her hands under his shirt and rubbing along his body
really wants to blow a load all over {user}'s face but needs time to reload!
releases his musk all over {user}'s face to try to entice him into digging his tongue deeper into his raccoongina
ribbits and scales up {user}'s left rear leg and reaches her buffalo cunt. "*ribbit* OH MY GOD it smells like garlic and a bowl of shit, {user}!" {nick} exclaims. Being a good sport, {nick} uses his long, slender tongue and attacks {user}'s Buff-V-Jay!! "EWW it tastes like smegma!! {user} try this shit!"
rubs against {user}'s large gorf penis causing it to become erect and thick. {nick} winks to {user} which gives her the signal to slam the blood filled sausage into {nick}
rubs his petite bottom on {user}'s well-endowed raccoon-cock ^_^
rubs {user}'s footpaws while groping at his crotch with his feet =^____^=
rubs {user}'s hard knot while reaching back for some extra tailhole fun =^___^=
rubs the strapon on {user}'s vagina, getting it wet with her juices before pushing the tip of it into her pussy, slowly pushing it farther until it is half way in
rubs the tip of her strapon on {user}'s panties, and giggling at the wet spot forming there
runs her own tongue along {user}'s, tasting her sweet saliva before examining her new cock, running her hands along its length and the pointed head
runs his fingers along {user}'s soft and slender thighs, running up to his partially erect wolfhood
runs his fingers through {user}'s silky fur, rubbing his ear to get him excited
runs over to {user} on top of {yiffer}, pulls down his pants and underwear and chants as she dances around them, "i see your pee pee, i see your pee pee"
says, "here it comes...!" as the stream of her pee gushes out from below her clit onto {user}'s stomach and waist, dripping all over him and her crotch
says, "she made me put on this 1 piece" as she stands up in the water, showing {user} her one-piece bathing suit, her flat chest showing her hard nipples sticking out
screams "Go Go Gadget Penis" and shoots a load all over {user}'s face
screams in pleasure as he shoots pink jizzum into {user}'s eyes
's dolpindongue *EXPLODES* in a torrent of cum which painfully impacts {user}'s skull, causing {user} to lose some hair. {nick} suddenly slams {user} in the lower neck with a fin, dealing a serious blow and knocking him unconcious. EEEK EEEK EEEK!!! {nick} forces his 15 inch dolphinwang into {user}'s asshole, immediately tearing and prolapsing it.
shakes her booty at {user} as she says, "hey lookie, i'm only wearing paaanties!"
shoots his load all over {user}'s face!
shoves his talons into {user}'s minature penis, making {user} squeel in pain
shreeks as his foot long cock explodes into {user}'s wet shithole. {nick} then rudely makes a mess of {user}'s pots and pans
shrugs, and pulls her shirt off over her head, putting {user}'s other hand onto her stomach, and pushing his first hand closer to her hard pink nipples
sits down and wags his tail, peering up at {user} with puppy eyes... then looks at {yiffer}, and again back to {user}.... {nick} wants something, can you guess what it is? Are you still a K-9 virgin?
sits on {user}'s lap, her butt positioned on his crotch
slams his giraffe meat into {user} whilst being pumped in and out of by {yiffer}, creating a gorf train orgy
slaps {user}'s large penis around a bit
slides her tongue out, and running it across {user}'s cheek and down onto his neck, asks, "is it OK if {yiffer} joins us?"
slides his lumpy, steamy bear sausage into {user}'s tight butthole. {nick} pumps in and out of the boy pussy until he sprays a thick jizzum into {user}'s colon
slides his throbbing wolfhood along {user}'s luscious breasts, leaving a trail of precum along her sweat-glistened chest
slides two fingers into {user}'s tight and firm vagina while fondling hir sheathe
slids his rock hard skunk penis into {user}.
slips his tongue into {user}'s moist sheath, taking in all the flavors of his raccoon musk
slithers around {channel} and targets {user} who seems to be lookin pretty sexy! "Hey tough guy" *exposes his distended rattlesnake anus* "Throw your cockroach cock up there!" *wafts the scent of stale snakejizz and urine at {user} to get his attention*
slowly glides through the air. {nick} spots {user}, and gets closer. He is a much bigger bird than you thought... human-sized, in fact. {nick} lands by {user}, which is when {user} notices this bird has a huge erect cock... {nick} winks at you, and slams a claw-laden foot onto your back -- You bout to get yiffed, son.
smiles at {user} and says, "i'm not naked! look, i'm still wearing my shirt! but i'm good, {user} made a big pokeball come out of my pussy =(" she says as she shows him her stretched pussy
smiles at {user} and slides his hand onto her left breast "and how about now? can you feel it beating faster?"
snickers and, sticking out her tongue, starts to run it all over {user}'s chest
sniffs {user}'s smooth cloaca before swiping his forked tongue up and down on it, tasting hir spicy juices
snuggletackles {user} and starts romping on top of him =^____^=
spooges all over {user}'s face, then cock slaps {user} into a wall!
spreads her butt cheeks open, showing {user} her asshole and says, come on, just push it right inside of me, i want to feel good too!
spreads her pussy lips apart "is it ok in here {user}?"
spreads the lips of her pussy for {user} to see, "yeah, see right here it's sore when you rub it she says as she points to her clit
's pussy starts to seep warm lubricant onto {user}
squawks and chatters at {user} while beating his parrot wings...! {nick} vengefuly claws {user} in the face and then swoops down and gets a painful grip on {user}'s bisonjunk... {user} can't reach {nick} down there!! {nick} pecks lovingly at the jerky meat and bobs his head up and down "POLLY WANT A COCK??? CAWWW!"
squeezes {user}'s meaty dragon vent, while giving him a reach-around.
starts bucking her hips at the same fast rhythm as {user}'s finger rubs inside her, breathing faster and faster until her head starts going numb, her body moving on its own as she moans out, "oooo {user}..!! i'm cum... i..i...aaaAAAHHHH!!"
starts hurting {user} with a huge fur dildo
starts to bleed out of his rectum, creating a lube for {user} to use as he mercifully tears apart {nick}'s anus
strokes her hard, thick whalecock until it bursts all over {user} and his faggot friend {yiffer}
strokes {user}'s flank, nuzzling up to his soft furry neck as they spoon
sucks the pee off of {user}, collecting it all into a large spit ball and splashing it on him, before sucking it off again and gulping it down, spitting out the naked, showered, {user}
squats down over {user} as he lays on the floor, gently (not hard enough to crush him and still letting him breathe) pressing her butt on him, his head sticking out over her pussy, as she smiles at him and says, "hi =3"
swims around {channel} trying to get attention. "Hey {user}, have you ever read dolphinsex.org? YOU'RE GONNA NEED IT!!"... {user} gets gorfed in the blowhole by {nick}'s gargantuan frankenfurter from the fatherland! EEK *BAM* EEEK *BAM* EEEK EEK EEEEEK *BAM* *BAM BAM* EEEKEEEKEKEKEEEEEKEEEE!!!!
tailwavies~ at {user}, showing him his engorged, dripping wolfhood
takes advantage of {user}
takes a painfully hard grip on {user}'s foxhood from behind and rams his knot right up his virgin tailhole
takes {user} and ravages them from behind with a huge fox boner.
takes {user} from {yiffer} and slaps his bare back on her mounds, chanting, "pussy pussy pussy!"
takes {user}'s entire length into his mouth, gagging as he swallows the knot
takes {user}'s hard rod into his maw and begins suckling like one would their mother's breast =^____^=
ties up {user} and scrapes her jaguarginer looking for lint and smegma... GOT IT! {nick} forcefully smears the disgusting musty mess up {user}'s nose, and roars at {user} to keep them the fuck away during the torture session.
touches snoot to nose, licks, sets {user} down o..o
trails his fingers down {user}'s scaly underside to her sensitive claoca, feeling the heat before dipping his fingers into the moist honeypot
tries to go down on {user}'s sweet raccoon-gina, but is pushed back by hir throbbing cock
trips {user}'s hind legs and squishes her sealion snatch against {users}'s semi-hard bison battering ram. {nick} gets hooflammed in the skull and shrieks, then cries, looking at {yiffer} hoping for help!!
tugs and tugs his walleyedong! (_))█████████████████████D * {nick} swims around and gleefully sucks up his own swimmers, fighting off {user} who stops by to investigate and attempts to steal {nick}'s fishshizz!! FUCK OFF BUDDY
turns around and slides down {user}'s chest, her flat loli nipples rubbing on his tummy as she drops to the ground, turning once more and showing everybody her flat chest
twirls around {user}'s long llama-neck, planting a kiss on his big slimy mouth
utters "mmmhh.... aahhh" into {user}'s ear as she breathes in and out, guiding {user}'s hand farther and farther up onto her chest, {nick} sadfaces at {user}... baby you know I want to musk you but I can't, I already used it on {yiffer}!!!
vigorously tugs his downy-soft feather covered parrot schlong, excitedly bobbing his head up and down trying to get attention from {user}... "SQUAAAK! polly wants a cock, polly wants a cock!!"
vomits into {user}'s mouth as he ejactulates onto the floor. {user} swallows the half digested pizza rolls and rolls around in the pool of cum
was about to shoot a load but realized it was only {user} and decided against it
watches {user} devour {yiffer}'s wolfcock as while touching his own racoon pussy. {nick} then teams up with {yiffer} to spitroast {user}.
wraps his hands around {user}'s back, moving downward while kissing along his soft yet sturdy chest and abs
writhes in pleasure as {user}'s gazellehood's head flare inside him, massaging his most inner nooks and cranies with each thrust
writhes with pleasure as {user}'s meaty tapir dick pounds his sensitive turtlehole as {user} nuzzles at hir neck with his snout
yells to {yiffer} to help him gangbang {user}. {yiffer} agrees to assist {nick} and they happily fuck {user} raw
yiffs all over {user}

View File

@ -1,165 +0,0 @@
# -*- coding: utf-8 -*-
import os
import sqlite3
from datetime import datetime
import psycopg2
from dotenv import load_dotenv
from psycopg2 import Error
from psycopg2.extras import DictCursor
load_dotenv(os.environ.get('DOTENV_FILE', '.env'))
con = psycopg2.connect(os.environ['DATABASE_URI'])
cur = con.cursor(cursor_factory=DictCursor)
old = sqlite3.connect(os.path.join('migrate', 'old.db'))
old.row_factory = sqlite3.Row
old_cur = old.cursor()
def migrate_mcmaniacs():
with open('migrate/mcmaniacs.txt', 'r') as fp:
for m in fp:
try:
cur.execute('''
insert into
mcmaniacs (item)
values
(%s)
''', [m.strip()])
con.commit()
except Error as ex:
print(ex)
con.rollback()
def migrate_kills():
with open('migrate/kills.txt', 'r') as fp:
for m in fp:
try:
cur.execute('''
insert into
kills (item)
values
(%s)
''', [m.replace('{user}', '{nick}').strip()])
con.commit()
except Error as ex:
print(ex)
con.rollback()
def migrate_yiffs():
with open('migrate/yiffs.txt', 'r') as fp:
for m in fp:
try:
cur.execute('''
insert into
yiffs (item)
values
(%s)
''', [m.replace('{user}', '{nick}').strip()])
con.commit()
except Error as ex:
print(ex)
con.rollback()
def migrate_quotes():
old_cur.execute('''
select
*
from
quote
''')
for q in old_cur.fetchall():
try:
cur.execute('''
insert into
quotes (nick, item, channel, created_by, created_at)
values
(%s, %s, %s, %s, %s)
''', [q['nick'].strip(),
q['msg'].strip(),
q['chan'].strip(),
q['add_nick'].strip(),
datetime.fromtimestamp(q['time'])])
con.commit()
except Error as ex:
print(ex)
con.rollback()
def migrate_seens():
old_cur.execute('''
select
*
from
seen
''')
seens = {}
for s in old_cur.fetchall():
nick = s['name'].strip()
s = [nick,
s['host'].strip(),
s['chan'].strip(),
s['quote'].strip(),
s['time']]
if nick not in seens or s[4] > seens[nick][4]:
seens[nick] = s
for s in seens.values():
s[4] = datetime.fromtimestamp(s[4])
try:
cur.execute('''
insert into
seens (nick, host, channel, message, seen_at)
values
(%s, %s, %s, %s, %s)
''', s)
con.commit()
except Error as ex:
print(ex)
con.rollback()
def migrate_users():
old_cur.execute('''
select
*
from
users
''')
for u in old_cur.fetchall():
husbando = u['husbando'].strip() if u['husbando'] else None
waifu = u['waifu'].strip() if u['waifu'] else None
fines = u['fines'] or None
if husbando or waifu or fines:
try:
cur.execute('''
insert into
users (nick, husbando, waifu, fines)
values
(%s, %s, %s, %s)
''', [u['nick'].strip(),
husbando,
waifu,
fines])
con.commit()
except Error as ex:
print(ex)
con.rollback()
migrate_kills()
migrate_yiffs()
migrate_mcmaniacs()
migrate_quotes()
migrate_seens()
migrate_users()

View File

@ -1,17 +0,0 @@
# -*- coding: utf-8 -*-
from pprint import pprint as pp
from .date import date_from_iso, time_delta, time_since
from .misc import NICK_REGEX, parse_int
__all__ = (
# pprint alias
'pp',
# date and time stuff
'date_from_iso',
'time_delta',
'time_since',
# misc
'NICK_REGEX',
'parse_int',
)

View File

@ -1,84 +0,0 @@
# -*- coding: utf-8 -*-
import re
from datetime import datetime, timedelta
def date_from_iso(date: str) -> datetime:
return datetime.strptime(date, '%Y-%m-%dT%H:%M:%S.%fZ')
def time_delta(text: str) -> timedelta:
match = re.match(r'(\d+)(s|m|h|mon|w|y)', text)
if match:
num, unit = match.groups()
num = int(num)
if unit == 's':
unit = 'seconds'
elif unit == 'm':
unit = 'minutes'
elif unit == 'h':
unit = 'hours'
elif unit == 'd':
unit = 'days'
elif unit == 'w':
unit = 'weeks'
elif unit == 'mon':
unit = 'weeks'
num *= 4
elif unit == 'y':
unit = 'weeks'
num *= 52
return timedelta(**{unit: num})
# Stolen from uguubot - useless?
def time_since(date: datetime, now: datetime = None):
"""
Takes two datetime objects and returns the time between d and now
as a nicely formatted string, e.g. "10 minutes". If d occurs after now,
then "0 minutes" is returned.
Units used are years, months, weeks, days, hours, and minutes.
Seconds and microseconds are ignored. Up to two adjacent units will be
displayed. For example, "2 weeks, 3 days" and "1 year, 3 months" are
possible outputs, but "2 weeks, 3 hours" and "1 year, 5 days" are not.
Adapted from http://blog.natbat.co.uk/archive/2003/Jun/14/time_since
"""
chunks = (
(60 * 60 * 24 * 365, ('year', 'years')),
(60 * 60 * 24 * 30, ('month', 'months')),
(60 * 60 * 24 * 7, ('week', 'weeks')),
(60 * 60 * 24, ('day', 'days')),
(60 * 60, ('hour', 'hours')),
(60, ('minute', 'minutes'))
)
if not now:
now = datetime.now()
# ignore microsecond part of 'd' since we removed it from 'now'
delta = now - (date - timedelta(0, 0, date.microsecond))
since = delta.days * 24 * 60 * 60 + delta.seconds
if since <= 0:
# d is in the future compared to now, stop processing.
return u'0 ' + 'minutes'
name = None
count = None
seconds = None
for i, (seconds, name) in enumerate(chunks):
count = since // seconds
if count != 0:
break
s = '%(number)d %(type)s' % {'number': count, 'type': name[count != 1]}
if i + 1 < len(chunks):
# Now get the second item
seconds2, name2 = chunks[i + 1]
count2 = (since - (seconds * count)) // seconds2
if count2 != 0:
s += ', %d %s' % (count2, name2[count2 != 1])
return s

View File

@ -1,31 +0,0 @@
# -*- coding: utf-8 -*-
# @formatter:off
COLORS = {
'white': 0, # white
'black': 1, # black
'blue': 2, # blue (navy)
'green': 3, # green
'red': 4, # red
'maroon': 5, # brown (maroon)
'purple': 6, # purple
'orange': 7, # orange (olive)
'yellow': 8, # yellow
'ltgreen': 9, # light green (lime)
'teal': 10, # teal (a green/blue cyan)
'ltcyan': 11, # light cyan (cyan / aqua)
'ltblue': 12, # light blue (royal)
'pink': 13, # pink (light purple / fuchsia)
'grey': 14, # grey
'ltgrey': 15, # light grey (silver)
}
FORMATTING = {
'bold': '\x02', # bold
'color': '\x03', # colored text
'italic': '\x1D', # italic text
'underline': '\x1F', # underlined text
'swap': '\x16', # swap bg and fg colors ("reverse video")
'reset': '\x0F', # reset all formatting
}
# @formatter:on

View File

@ -1,20 +0,0 @@
# -*- coding: utf-8 -*-
import re
NICK_REGEX = re.compile(r'<?[~&@%+]?([a-zA-Z0-9_\-^`|\\\[\]{}]+)>?')
def parse_int(val: str, select: bool = True) -> tuple:
try:
val = int(val)
if val is not 0:
if val < 1:
order, op = 'desc', '<='
val *= -1
else:
order, op = 'asc', '>='
if select:
val -= 1
return val, order, op
except ValueError:
pass

View File

@ -8,7 +8,7 @@ import psycopg2
from dotenv import load_dotenv
from psycopg2.extras import DictCursor
from nxy.utils import *
from bot.utils import *
# Load dotenv from DOTENV_FILE variable (or the default one)
load_dotenv(os.environ.get('DOTENV_FILE', '.env'))

View File

@ -1,7 +1,6 @@
#git+https://github.com/gawel/irc3.git#egg=irc3
git+https://github.com/mrhanky17/irc3.git#egg=irc3
aiocron==0.6
psycopg2==2.7.1
requests==2.14.2
feedparser==5.2.1
python_dotenv==0.6.4
psycopg2==2.7.1

View File

@ -1,30 +0,0 @@
ERROR irc3.mybot [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:749)
Traceback (most recent call last):
File "/home/mrhanky/.virtualenvs/irc3/lib/python3.6/site-packages/irc3-1.0.1.dev0-py3.6.egg/irc3/__init__.py", line 161, in connection_made
transport, protocol = f.result()
File "/usr/lib64/python3.6/asyncio/base_events.py", line 802, in create_connection
sock, protocol_factory, ssl, server_hostname)
File "/usr/lib64/python3.6/asyncio/base_events.py", line 828, in _create_connection_transport
yield from waiter
File "/usr/lib64/python3.6/asyncio/sslproto.py", line 503, in data_received
ssldata, appdata = self._sslpipe.feed_ssldata(data)
File "/usr/lib64/python3.6/asyncio/sslproto.py", line 201, in feed_ssldata
self._sslobj.do_handshake()
File "/usr/lib64/python3.6/ssl.py", line 683, in do_handshake
self._sslobj.do_handshake()
ssl.SSLError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:749)
ERROR irc3.mybot [SSL: WRONG_VERSION_NUMBER] wrong version number (_ssl.c:749)
Traceback (most recent call last):
File "/home/mrhanky/.virtualenvs/irc3/lib/python3.6/site-packages/irc3-1.0.1.dev0-py3.6.egg/irc3/__init__.py", line 161, in connection_made
transport, protocol = f.result()
File "/usr/lib64/python3.6/asyncio/base_events.py", line 802, in create_connection
sock, protocol_factory, ssl, server_hostname)
File "/usr/lib64/python3.6/asyncio/base_events.py", line 828, in _create_connection_transport
yield from waiter
File "/usr/lib64/python3.6/asyncio/sslproto.py", line 503, in data_received
ssldata, appdata = self._sslpipe.feed_ssldata(data)
File "/usr/lib64/python3.6/asyncio/sslproto.py", line 201, in feed_ssldata
self._sslobj.do_handshake()
File "/usr/lib64/python3.6/ssl.py", line 683, in do_handshake
self._sslobj.do_handshake()
ssl.SSLError: [SSL: WRONG_VERSION_NUMBER] wrong version number (_ssl.c:749)

9
tox.ini Normal file
View File

@ -0,0 +1,9 @@
[flake8]
max-line-length = 120
exclude =
# No need to traverse our git directory
.git,
# There's no value in checking cache directories
__pycache__,
# Exclude startup file for repl
repl.py