Bla, added install instructions

This commit is contained in:
mrhanky 2017-07-04 15:22:20 +02:00
parent 57df82943b
commit 928ad44db4
No known key found for this signature in database
GPG Key ID: 67D772C481CB41B8
16 changed files with 209 additions and 103 deletions

View File

@ -1 +1,3 @@
PASSWORD=password
DATABASE_URI=postgresql://<pgsql user>:<pgsql password>@<pgsql password>:<pgsql port>/<pgsql database>
GOOGLE_API_KEY=<google api key>
PASSWORD=<znc password>

1
.gitignore vendored
View File

@ -1,4 +1,3 @@
*.sqlite
.env
.idea/
__pycache__/

View File

@ -1,68 +1,16 @@
# Todo
* [ ] joke Trigger Erzählt einen schlechten Witz
* [ ] .seen trigger returns the last message and date the user was seen in the channel
# Done
* [x] .help - lists all available commands (builtin)
* [x] .uptime - prints bot uptime (builtin)
## plugins/admin
* [x] .reload - reloads a plugin or the whole bot
## plugins/coins
* [x] .btc - prints current btc values
* [x] .eth - prints current eth values
## plugins/ctcp
* [x] .finger - does a FINGER ctcp
* [x] .ping - does a PING ctcp
* [x] .time - does a TIME ctcp
* [x] .ver - does a VERSION ctcp
## plugins/database
## plugins/linux
* [x] useless gnu/linux event
* [x] .kernel - displays current linux kernel info
## plugins/mcmaniac
* [x] regex event for Mc(.*)iaC which adds a McManiaC
* [x] .mcmaniac - shows a McManiaC (random or by index)
## plugins/quotes
* [x] .q - prints, adds or removes a quote
## plugins/rape
* [x] .owe command
* [x] .rape command
## plugins/seen
## plugins/tell
* [x] .tell - stores a message for a user and sends it to him when he writes a message in any channel (shows activity)
## plugins/timer
* [x] .timer - sets a timer for a specified amount of time and a name
## plugins/urban
* [x] .ud - gets a definition from urban dictionary
## plugins/useless
* [x] .gay - colors text in rainbow colors
* [x] .hack - prints "hacking..."
* [x] .jn - returns yes or no for a given question
* [x] .kiss - kisses a user
* [x] .rainbow - same as .gay
* [x] .storyofpomfface - ....
* [x] Bier Trigger nxy schenkt ein kühles blondes an $nick aus
* [x] REEEEEE Trigger REEEEEEEEEEEEEEEEEEEEEEEEEEEE
* [x] Fucken Trigger nxy fuckt $nick und tötet $nick anschließend.
* [x] .choose - picks a random entry from a list seperated with commas
* [x] .sudoku/.anhero - kicks the user that executes that command
## plugins/weather
* [x] .weather - prints the weather for a given location
## plugins/youtube
* [x] .yt - search for a video on youtube
* [x] youtube url parser - returns video information if a youtube link is posted
# Installation
* Open shell as user nxy will run
* Install virtualenvwrapper and source it
- ```source $(which virtualenvwrapper.sh)```
* Clone repo
- ```git clone https://gitfap.de/mrhanky/nxy.git```
* Create virtualenv and install dependencies
- ```mkvirtualenv -a $PWD/nxy -r $PWD/nxy/requirements.txt nxy```
* Copy ```.env-example``` and insert values in ```.env``` (replace everything wrapped in < and >)
- ```cp .env-example .env```
- ```vim .env```
* Leave (auto) activated virtualenv and
- ```deactivate```
* Copy systemd unit (would recommend the ```/usr/local``` prefix)
- ```sudo mkdir -p /usr/local/lib/systemd/system```
- ```sudo cp $PWD/nxy/nxy-bot.service /usr/local/lib/systemd/system```

View File

@ -13,10 +13,12 @@
"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",

12
nxy-bot.service Normal file
View File

@ -0,0 +1,12 @@
[Unit]
Description=nxy python irc bot
After=network.target znc.service
[Service]
Type=simple
User=nxy
WorkingDirectory=$BOTDIR
ExecStart=$VIRTUALENV/bin/python $BOTDIR/nxy/bot.py
[Install]
WantedBy=multi-user.target

View File

@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
import os
import json
import sys
import json
from dotenv import load_dotenv
from irc3 import IrcBot

View File

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
from irc3 import IrcBot
from irc3.plugins.command import Commands

View File

@ -1,15 +1,19 @@
# -*- coding: utf-8 -*-
import logging
import irc3
from docopt import Dict as DocoptDict
from docopt import Dict as DocOptDict
from irc3.plugins.command import command
from irc3.utils import IrcString
from . import MODULE
from . import MODULE, Plugin
logger = logging.getLogger(__name__)
@command(permission='admin', show_in_help_list=False)
def reload(bot: irc3.IrcBot, mask: IrcString, target: IrcString,
args: DocoptDict):
args: DocOptDict):
"""Reloads a plugin or the whole bot.
%%reload [<plugin>]
@ -21,3 +25,8 @@ def reload(bot: irc3.IrcBot, mask: IrcString, target: IrcString,
else:
bot.reload()
bot.privmsg(target, 'Reloaded the bot')
@irc3.plugin
class Admin(Plugin):
pass

View File

@ -62,8 +62,3 @@ class Coins(Plugin):
low=result['price']['low'],
change=result['price']['change']['percentage'] * 100,
volume=result['volume'])
@staticmethod
def _etherscan(action: str):
return requests.get('https://api.etherscan.io/api?module=stats&action='
'{action}'.format(action=action)).json()['result']

36
nxy/plugins/isup.py Normal file
View File

@ -0,0 +1,36 @@
# -*- coding: utf-8 -*-
from urllib.parse import urlparse
import irc3
import requests
from docopt import Dict as DocOptDict
from irc3.plugins.command import command
from irc3.utils import IrcString
from . import DatabasePlugin
@irc3.plugin
class Useless(DatabasePlugin):
requires = ['irc3.plugins.command',
'nxy.plugins.storage']
@command
def isup(self, mask: IrcString, target: IrcString, args: DocOptDict):
"""Checks if a address is up.
%%isup <address>
"""
address = args['<address>']
if not address.startswith('http://'):
address = 'https://{}'.format(address)
parsed = urlparse(address)
try:
requests.head(address)
state = 'up'
except requests.ConnectionError:
state = 'down'
return '{scheme}://{address} seems to be {state}'.format(scheme=parsed.scheme,
address=parsed.netloc,
state=state)

View File

@ -1,7 +1,6 @@
# -*- coding: utf-8 -*-
import random
import irc3
import feedparser
from docopt import Dict as DocOptDict
@ -10,6 +9,7 @@ from irc3.utils import IrcString
from . import Plugin
GNU_LINUX = """I'd Just Like To Interject For A Moment. What you're referring
to as Linux, is in fact, GNU/Linux, or as I've recently taken to calling it,
GNU plus Linux. Linux is not an operating system unto itself, but rather
@ -21,14 +21,18 @@ 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+) :.*(debian|apt|dpkg).*')
@irc3.event(r'(?i)^:\S+ PRIVMSG (?P<target>\S+) :'
r'.*(debian|ubuntu|apt|dpkg).*')
def debillian(self, target: str):
if random.randint(0, 12) is 0:
self.bot.privmsg(target, 'REEEEEEEEEEEEEEEEEEEEEEEEEEEEE')
"""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)))))
@irc3.event(r'(?i)^:\S+ PRIVMSG (?P<target>\S+) :'
r'.*(?<!gnu[/+])linux(?! kernel).*')
def linux(self, target: str):
"""Super annoying, useless 'Stallman is mad' trigger."""
if random.randint(0, 12) is 0:
self.bot.privmsg(target, GNU_LINUX)
@ -39,13 +43,24 @@ class Linux(Plugin):
%%kernel
"""
feed = feedparser.parse(self.KERNEL_FEED)
# Cancel if no feed or entries
if not feed or 'entries' in feed:
self.log.error('Error fetching kernel.org releases feed.')
return
# Make list of releases
releases = []
for e in feed['entries']:
version, branch = e['title'].split(': ')
if '(EOL)' in e['description']:
branch = '{branch}, \x1DEOL\x1D'.format(branch=branch)
releases.append('\x02{version}\x02 ({branch})'.format(
branch = '{branch}, \x1DEOL\x0F'.format(branch=branch)
releases.append('\x02{version}\x0F ({branch})'.format(
version=version,
branch=branch,
))
return '[Kernel] {releases}'.format(releases=', '.join(releases))
return '\x02[Kernel]\x0F {releases}'.format(
releases=', '.join(releases))

View File

@ -80,7 +80,7 @@ class Quotes(DatabasePlugin):
self.delete_quote(nick, quote)
self.con.commit()
except Error:
except Error as ex:
# Rollback transaction on error
self.con.rollback()
else:

59
nxy/plugins/regex.py Normal file
View File

@ -0,0 +1,59 @@
# -*- coding: utf-8 -*-
import re
import irc3
from irc3.utils import IrcString
from . import DatabasePlugin
@irc3.plugin
class Useless(DatabasePlugin):
requires = ['irc3.plugins.command',
'nxy.plugins.storage']
@irc3.event(r'^:(?P<mask>\S+) PRIVMSG (?P<target>#\S+) :s/'
r'(?P<search>(?:[^/\\]|\\.)*)/'
r'(?P<replace>(?:.*?))'
r'(?:/ ?(?P<nick>.*))?$')
def regex(self, mask: str, target: str, search: str, replace: str,
nick: str = None):
nick = (nick or IrcString(mask).nick).strip()
if nick == self.bot.nick:
return
self.cur.execute('''
select
item
from
last_messages
where
nick = lower(%s)
and channel = lower(%s)
''', [nick, target])
result = self.cur.fetchone()
if result:
old = result['item']
msg = re.sub(search, '\x02{}\x0F'.format(replace), old)
print(msg)
if old != msg:
self.bot.privmsg(target, '<{nick}> {msg}'.format(nick=nick,
msg=msg))
@irc3.event(r'(?i)^:(?P<mask>\S+) PRIVMSG (?P<target>#\S+) :(?P<msg>.*)$')
def last_message(self, mask: str, target: str, msg: str):
"""Saves the last message of a user for each channel (for regex)."""
mask = IrcString(mask)
self.cur.execute('''
insert into
last_messages (nick, host, channel, item)
values
(lower(%s), %s, lower(%s), %s)
on conflict (nick, channel) do update set
host = excluded.host,
item = excluded.item
''', [mask.nick, mask.host, target, msg])
self.con.commit()

View File

@ -14,5 +14,5 @@ class Storage(Plugin):
super().__init__(bot)
# Create database connection
self.con = psycopg2.connect(os.environ['DATABASE_URI'])
# Create database cursor (with dict favtory to access rows by name)
# Create database cursor (with dict factory to access rows by name)
self.cur = self.con.cursor(cursor_factory=DictCursor)

View File

@ -8,7 +8,7 @@ from irc3.utils import IrcString
from . import DatabasePlugin
RAINBOW = (5, 3, 7, 8, 9, 3, 10, 12, 2, 6, 13)
RAINBOW = (5, 7, 8, 9, 3, 10, 12, 2, 6, 13)
RAINBOW_LEN = len(RAINBOW)
@ -16,6 +16,18 @@ RAINBOW_LEN = len(RAINBOW)
class Useless(DatabasePlugin):
requires = ['irc3.plugins.command',
'nxy.plugins.storage']
WOAH = (
'woah',
'woah indeed',
'woah woah woah!',
'keep your woahs to yourself',
)
@irc3.event(r'(?i)^:\S+ PRIVMSG (?P<target>\S+) :.*(woah|whoa).*$')
def woah(self, target: str):
"""Colorize words in a sentence with rainbow colors."""
if random.randint(0, 4) is 0:
self.bot.privmsg(target, random.choice(self.WOAH))
@irc3.event(r'(?i)^:\S+ PRIVMSG (?P<target>\S+) :(?P<msg>huehuehue)$')
def huehuehue(self, target: str, msg: str):
@ -44,7 +56,6 @@ class Useless(DatabasePlugin):
%%kill [<nick>]
"""
nick = args.get('<nick>') or mask.nick
self.cur.execute('''
select
item
@ -55,7 +66,8 @@ class Useless(DatabasePlugin):
limit
1
''')
return self.cur.fetchone()['item'].format(nick=nick)
self.bot.action(target, self.cur.fetchone()['item']
.format(nick=args.get('<nick>') or mask.nick))
@command
def yiff(self, mask: IrcString, target: IrcString, args: DocOptDict):
@ -63,7 +75,6 @@ class Useless(DatabasePlugin):
%%yiff [<nick>]
"""
nick = args.get('<nick>') or mask.nick
self.cur.execute('''
select
item
@ -74,15 +85,16 @@ class Useless(DatabasePlugin):
limit
1
''')
return self.cur.fetchone()['item'].format(nick=nick)
self.bot.action(target, self.cur.fetchone()['item']
.format(nick=args.get('<nick>') or mask.nick))
@command
def waifu(self, mask: IrcString, target: IrcString, args: DocOptDict):
"""Get waifu for a user.
%%waifu [<nick>]
%%waifu [<nick>...]
"""
nick = args.get('<nick>') or mask.nick
nick = ' '.join(args.get('<nick>')) or mask.nick
if nick.startswith('='):
waifu = nick[1:]
@ -118,12 +130,12 @@ class Useless(DatabasePlugin):
def husbando(self, mask: IrcString, target: IrcString, args: DocOptDict):
"""Get husbando for a user.
%%husbando [<nick>]
%%husbando [<nick>...]
"""
nick = args.get('<nick>') or mask.nick
nick = ' '.join(args.get('<nick>')) or mask.nick
if nick.startswith('='):
husbando = nick[1:]
nick = nick[1:]
self.cur.execute('''
insert into
@ -132,10 +144,10 @@ class Useless(DatabasePlugin):
(%s, %s)
on conflict (nick) do update set
husbando = excluded.husbando
''', [mask.nick, husbando])
''', [mask.nick, nick])
self.bot.notice(mask.nick, 'Husbando set to: {husbando}'
.format(husbando=husbando))
.format(husbando=nick))
else:
self.cur.execute('''
select
@ -206,7 +218,7 @@ class Useless(DatabasePlugin):
%%bier [<nick>]
"""
self.bot.action(target, 'schenkt ein kühles blondes an {nick} aus.'
self.bot.action(target, 'schenkt ein kühles Blondes an {nick} aus.'
.format(nick=args.get('<nick>') or mask.nick))
@command
@ -276,7 +288,6 @@ class Useless(DatabasePlugin):
return ' '.join([self._rainbow(i, word) for i, word
in enumerate(args['<words>'])])
@staticmethod
def _rainbow(i, char):
def _rainbow(self, i, char):
return '\x03{color}{char}'.format(color=RAINBOW[i % RAINBOW_LEN],
char=char)

View File

@ -63,3 +63,20 @@ create table if not exists yiffs (
item text not null,
unique (item)
);
create table if not exists last_messages (
id serial primary key,
nick varchar(30) not null,
host varchar(255) not null,
channel varchar(32) not null,
item text not null,
unique (nick, channel)
);
select
item
from
last_messages
where
nick = lower('m')
and channel = lower('nxy-dev');