Bla, added install instructions
This commit is contained in:
parent
57df82943b
commit
928ad44db4
|
@ -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
1
.gitignore
vendored
|
@ -1,4 +1,3 @@
|
|||
*.sqlite
|
||||
.env
|
||||
.idea/
|
||||
__pycache__/
|
||||
|
|
84
README.md
84
README.md
|
@ -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```
|
||||
|
|
|
@ -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
12
nxy-bot.service
Normal 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
|
|
@ -1,7 +1,7 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
import os
|
||||
import json
|
||||
import sys
|
||||
import json
|
||||
|
||||
from dotenv import load_dotenv
|
||||
from irc3 import IrcBot
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
from irc3 import IrcBot
|
||||
from irc3.plugins.command import Commands
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
36
nxy/plugins/isup.py
Normal 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)
|
|
@ -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))
|
||||
|
|
|
@ -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
59
nxy/plugins/regex.py
Normal 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()
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
17
schema.sql
17
schema.sql
|
@ -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');
|
||||
|
|
Loading…
Reference in New Issue
Block a user