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 .env
.idea/ .idea/
__pycache__/ __pycache__/

View File

@ -1,68 +1,16 @@
# Todo # Installation
* [ ] joke Trigger Erzählt einen schlechten Witz * Open shell as user nxy will run
* [ ] .seen trigger returns the last message and date the user was seen in the channel * Install virtualenvwrapper and source it
- ```source $(which virtualenvwrapper.sh)```
# Done * Clone repo
* [x] .help - lists all available commands (builtin) - ```git clone https://gitfap.de/mrhanky/nxy.git```
* [x] .uptime - prints bot uptime (builtin) * Create virtualenv and install dependencies
- ```mkvirtualenv -a $PWD/nxy -r $PWD/nxy/requirements.txt nxy```
## plugins/admin * Copy ```.env-example``` and insert values in ```.env``` (replace everything wrapped in < and >)
* [x] .reload - reloads a plugin or the whole bot - ```cp .env-example .env```
- ```vim .env```
## plugins/coins * Leave (auto) activated virtualenv and
* [x] .btc - prints current btc values - ```deactivate```
* [x] .eth - prints current eth values * Copy systemd unit (would recommend the ```/usr/local``` prefix)
- ```sudo mkdir -p /usr/local/lib/systemd/system```
## plugins/ctcp - ```sudo cp $PWD/nxy/nxy-bot.service /usr/local/lib/systemd/system```
* [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

View File

@ -13,10 +13,12 @@
"nxy.plugins.admin", "nxy.plugins.admin",
"nxy.plugins.coins", "nxy.plugins.coins",
"nxy.plugins.ctcp", "nxy.plugins.ctcp",
"nxy.plugins.isup",
"nxy.plugins.linux", "nxy.plugins.linux",
"nxy.plugins.mcmaniac", "nxy.plugins.mcmaniac",
"nxy.plugins.quotes", "nxy.plugins.quotes",
"nxy.plugins.rape", "nxy.plugins.rape",
"nxy.plugins.regex",
"nxy.plugins.seen", "nxy.plugins.seen",
"nxy.plugins.tell", "nxy.plugins.tell",
"nxy.plugins.timer", "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 -*- # -*- coding: utf-8 -*-
import os import os
import json
import sys import sys
import json
from dotenv import load_dotenv from dotenv import load_dotenv
from irc3 import IrcBot from irc3 import IrcBot

View File

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

View File

@ -1,15 +1,19 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import logging
import irc3 import irc3
from docopt import Dict as DocoptDict from docopt import Dict as DocOptDict
from irc3.plugins.command import command from irc3.plugins.command import command
from irc3.utils import IrcString from irc3.utils import IrcString
from . import MODULE from . import MODULE, Plugin
logger = logging.getLogger(__name__)
@command(permission='admin', show_in_help_list=False) @command(permission='admin', show_in_help_list=False)
def reload(bot: irc3.IrcBot, mask: IrcString, target: IrcString, def reload(bot: irc3.IrcBot, mask: IrcString, target: IrcString,
args: DocoptDict): args: DocOptDict):
"""Reloads a plugin or the whole bot. """Reloads a plugin or the whole bot.
%%reload [<plugin>] %%reload [<plugin>]
@ -21,3 +25,8 @@ def reload(bot: irc3.IrcBot, mask: IrcString, target: IrcString,
else: else:
bot.reload() bot.reload()
bot.privmsg(target, 'Reloaded the bot') 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'], low=result['price']['low'],
change=result['price']['change']['percentage'] * 100, change=result['price']['change']['percentage'] * 100,
volume=result['volume']) 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 -*- # -*- coding: utf-8 -*-
import random import random
import irc3 import irc3
import feedparser import feedparser
from docopt import Dict as DocOptDict from docopt import Dict as DocOptDict
@ -10,6 +9,7 @@ from irc3.utils import IrcString
from . import Plugin from . import Plugin
GNU_LINUX = """I'd Just Like To Interject For A Moment. What you're referring 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, 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 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): class Linux(Plugin):
KERNEL_FEED = 'https://www.kernel.org/feeds/kdist.xml' 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): def debillian(self, target: str):
if random.randint(0, 12) is 0: """Annoying RE trigger for debian with variable count of E."""
self.bot.privmsg(target, 'REEEEEEEEEEEEEEEEEEEEEEEEEEEEE') 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+) :' @irc3.event(r'(?i)^:\S+ PRIVMSG (?P<target>\S+) :'
r'.*(?<!gnu[/+])linux(?! kernel).*') r'.*(?<!gnu[/+])linux(?! kernel).*')
def linux(self, target: str): def linux(self, target: str):
"""Super annoying, useless 'Stallman is mad' trigger."""
if random.randint(0, 12) is 0: if random.randint(0, 12) is 0:
self.bot.privmsg(target, GNU_LINUX) self.bot.privmsg(target, GNU_LINUX)
@ -39,13 +43,24 @@ class Linux(Plugin):
%%kernel %%kernel
""" """
feed = feedparser.parse(self.KERNEL_FEED) 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 = [] releases = []
for e in feed['entries']: for e in feed['entries']:
version, branch = e['title'].split(': ') version, branch = e['title'].split(': ')
if '(EOL)' in e['description']: if '(EOL)' in e['description']:
branch = '{branch}, \x1DEOL\x1D'.format(branch=branch) branch = '{branch}, \x1DEOL\x0F'.format(branch=branch)
releases.append('\x02{version}\x02 ({branch})'.format(
releases.append('\x02{version}\x0F ({branch})'.format(
version=version, version=version,
branch=branch, 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.delete_quote(nick, quote)
self.con.commit() self.con.commit()
except Error: except Error as ex:
# Rollback transaction on error # Rollback transaction on error
self.con.rollback() self.con.rollback()
else: 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) super().__init__(bot)
# Create database connection # Create database connection
self.con = psycopg2.connect(os.environ['DATABASE_URI']) 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) self.cur = self.con.cursor(cursor_factory=DictCursor)

View File

@ -8,7 +8,7 @@ from irc3.utils import IrcString
from . import DatabasePlugin 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) RAINBOW_LEN = len(RAINBOW)
@ -16,6 +16,18 @@ RAINBOW_LEN = len(RAINBOW)
class Useless(DatabasePlugin): class Useless(DatabasePlugin):
requires = ['irc3.plugins.command', requires = ['irc3.plugins.command',
'nxy.plugins.storage'] '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)$') @irc3.event(r'(?i)^:\S+ PRIVMSG (?P<target>\S+) :(?P<msg>huehuehue)$')
def huehuehue(self, target: str, msg: str): def huehuehue(self, target: str, msg: str):
@ -44,7 +56,6 @@ class Useless(DatabasePlugin):
%%kill [<nick>] %%kill [<nick>]
""" """
nick = args.get('<nick>') or mask.nick
self.cur.execute(''' self.cur.execute('''
select select
item item
@ -55,7 +66,8 @@ class Useless(DatabasePlugin):
limit limit
1 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 @command
def yiff(self, mask: IrcString, target: IrcString, args: DocOptDict): def yiff(self, mask: IrcString, target: IrcString, args: DocOptDict):
@ -63,7 +75,6 @@ class Useless(DatabasePlugin):
%%yiff [<nick>] %%yiff [<nick>]
""" """
nick = args.get('<nick>') or mask.nick
self.cur.execute(''' self.cur.execute('''
select select
item item
@ -74,15 +85,16 @@ class Useless(DatabasePlugin):
limit limit
1 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 @command
def waifu(self, mask: IrcString, target: IrcString, args: DocOptDict): def waifu(self, mask: IrcString, target: IrcString, args: DocOptDict):
"""Get waifu for a user. """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('='): if nick.startswith('='):
waifu = nick[1:] waifu = nick[1:]
@ -118,12 +130,12 @@ class Useless(DatabasePlugin):
def husbando(self, mask: IrcString, target: IrcString, args: DocOptDict): def husbando(self, mask: IrcString, target: IrcString, args: DocOptDict):
"""Get husbando for a user. """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('='): if nick.startswith('='):
husbando = nick[1:] nick = nick[1:]
self.cur.execute(''' self.cur.execute('''
insert into insert into
@ -132,10 +144,10 @@ class Useless(DatabasePlugin):
(%s, %s) (%s, %s)
on conflict (nick) do update set on conflict (nick) do update set
husbando = excluded.husbando husbando = excluded.husbando
''', [mask.nick, husbando]) ''', [mask.nick, nick])
self.bot.notice(mask.nick, 'Husbando set to: {husbando}' self.bot.notice(mask.nick, 'Husbando set to: {husbando}'
.format(husbando=husbando)) .format(husbando=nick))
else: else:
self.cur.execute(''' self.cur.execute('''
select select
@ -206,7 +218,7 @@ class Useless(DatabasePlugin):
%%bier [<nick>] %%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)) .format(nick=args.get('<nick>') or mask.nick))
@command @command
@ -276,7 +288,6 @@ class Useless(DatabasePlugin):
return ' '.join([self._rainbow(i, word) for i, word return ' '.join([self._rainbow(i, word) for i, word
in enumerate(args['<words>'])]) in enumerate(args['<words>'])])
@staticmethod def _rainbow(self, i, char):
def _rainbow(i, char):
return '\x03{color}{char}'.format(color=RAINBOW[i % RAINBOW_LEN], return '\x03{color}{char}'.format(color=RAINBOW[i % RAINBOW_LEN],
char=char) char=char)

View File

@ -63,3 +63,20 @@ create table if not exists yiffs (
item text not null, item text not null,
unique (item) 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');