mirror of
https://github.com/SpiceBot/SpiceBot.git
synced 2026-11-10 21:50:59 -05:00
Watch For New Channels, JOIN, and +a. Basic Nick_Commands for channel Listing
This commit is contained in:
commit
4d2156be1c
57
.gitignore
vendored
Normal file
57
.gitignore
vendored
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
# Byte-compiled / optimized / DLL files
|
||||||
|
__pycache__/
|
||||||
|
*.py[cod]
|
||||||
|
|
||||||
|
# C extensions
|
||||||
|
*.so
|
||||||
|
|
||||||
|
# Distribution / packaging
|
||||||
|
.Python
|
||||||
|
env/
|
||||||
|
build/
|
||||||
|
develop-eggs/
|
||||||
|
dist/
|
||||||
|
downloads/
|
||||||
|
eggs/
|
||||||
|
.eggs/
|
||||||
|
lib/
|
||||||
|
lib64/
|
||||||
|
parts/
|
||||||
|
sdist/
|
||||||
|
var/
|
||||||
|
*.egg-info/
|
||||||
|
.installed.cfg
|
||||||
|
*.egg
|
||||||
|
|
||||||
|
# PyInstaller
|
||||||
|
# Usually these files are written by a python script from a template
|
||||||
|
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||||
|
*.manifest
|
||||||
|
*.spec
|
||||||
|
|
||||||
|
# Installer logs
|
||||||
|
pip-log.txt
|
||||||
|
pip-delete-this-directory.txt
|
||||||
|
|
||||||
|
# Unit test / coverage reports
|
||||||
|
htmlcov/
|
||||||
|
.tox/
|
||||||
|
.coverage
|
||||||
|
.coverage.*
|
||||||
|
.cache
|
||||||
|
nosetests.xml
|
||||||
|
coverage.xml
|
||||||
|
*,cover
|
||||||
|
|
||||||
|
# Translations
|
||||||
|
*.mo
|
||||||
|
*.pot
|
||||||
|
|
||||||
|
# Django stuff:
|
||||||
|
*.log
|
||||||
|
|
||||||
|
# Sphinx documentation
|
||||||
|
docs/_build/
|
||||||
|
|
||||||
|
# PyBuilder
|
||||||
|
target/
|
||||||
23
COPYING
Normal file
23
COPYING
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
|
||||||
|
Eiffel Forum License, version 2
|
||||||
|
|
||||||
|
1. Permission is hereby granted to use, copy, modify and/or
|
||||||
|
distribute this package, provided that:
|
||||||
|
* copyright notices are retained unchanged,
|
||||||
|
* any distribution of this package, whether modified or not,
|
||||||
|
includes this license text.
|
||||||
|
2. Permission is hereby also granted to distribute binary programs
|
||||||
|
which depend on this package. If the binary program depends on a
|
||||||
|
modified version of this package, you are encouraged to publicly
|
||||||
|
release the modified version of this package.
|
||||||
|
|
||||||
|
***********************
|
||||||
|
|
||||||
|
THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT WARRANTY. ANY EXPRESS OR
|
||||||
|
IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
DISCLAIMED. IN NO EVENT SHALL THE AUTHORS BE LIABLE TO ANY PARTY FOR ANY
|
||||||
|
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
DAMAGES ARISING IN ANY WAY OUT OF THE USE OF THIS PACKAGE.
|
||||||
|
|
||||||
|
***********************
|
||||||
40
Installation Files/requirements-os.sh
Normal file
40
Installation Files/requirements-os.sh
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# This install was run on Proxmox Ubuntu 18.10
|
||||||
|
|
||||||
|
apt update
|
||||||
|
apt upgrade -y
|
||||||
|
|
||||||
|
dpkg-reconfigure locales
|
||||||
|
|
||||||
|
apt install -y git
|
||||||
|
apt install -y python3-dev python3-pip
|
||||||
|
apt install -y python3-enchant libaspell-dev
|
||||||
|
|
||||||
|
wget https://raw.githubusercontent.com/sopel-irc/sopel/master/requirements.txt
|
||||||
|
pip3 install -r requirements.txt
|
||||||
|
rm requirements.txt
|
||||||
|
wget https://raw.githubusercontent.com/sopel-irc/sopel/master/dev-requirements.txt
|
||||||
|
pip3 install -r dev-requirements.txt
|
||||||
|
rm dev-requirements.txt
|
||||||
|
wget https://raw.githubusercontent.com/SpiceBot/SpiceBot/development/Installation%20Files/requirements.txt
|
||||||
|
pip3 install -r requirements.txt
|
||||||
|
rm requirements.txt
|
||||||
|
pip3 install sopel
|
||||||
|
|
||||||
|
mkdir /usr/local/lib/python3.6/dist-packages/sopel/modules/stock
|
||||||
|
mv /usr/local/lib/python3.6/dist-packages/sopel/modules/* /usr/local/lib/python3.6/dist-packages/sopel/modules/stock/
|
||||||
|
|
||||||
|
useradd sopel
|
||||||
|
passwd sopel
|
||||||
|
mkdir /home/sopel
|
||||||
|
chown sopel:sopel /home/sopel
|
||||||
|
usermod -aG sudo sopel
|
||||||
|
|
||||||
|
git clone https://github.com/SpiceBot/SpiceBot.git /home/sopel/SpiceBot
|
||||||
|
cd /home/sopel/SpiceBot
|
||||||
|
git checkout dev
|
||||||
|
|
||||||
|
cp /home/sopel/SpiceBot/System-Files/Config/SpiceBot.cfg /home/sopel/SpiceBot.cfg
|
||||||
|
cp /home/sopel/SpiceBot/System-Files/systemd/SpiceBot.service /lib/systemd/system/SpiceBot.service
|
||||||
|
systemctl enable SpiceBot.service
|
||||||
8
MANIFEST.in
Normal file
8
MANIFEST.in
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
include NEWS
|
||||||
|
include COPYING
|
||||||
|
include README.md
|
||||||
|
include *requirements.txt
|
||||||
|
|
||||||
|
recursive-include tests *
|
||||||
|
recursive-exclude * __pycache__
|
||||||
|
recursive-exclude * *.py[co]
|
||||||
13
README.md
Normal file
13
README.md
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
# SpiceBot
|
||||||
|
|
||||||
|
SpiceBot aims to run SpiceBot as an IRC service
|
||||||
|
|
||||||
|
# This code is bad, and the author doesn't feel bad
|
||||||
|
Use at your own risk. Problems are not my fault™.
|
||||||
|
|
||||||
|
# Installation
|
||||||
|
````
|
||||||
|
git clone https://github.com/SpiceBot/SpiceBot.git
|
||||||
|
cd SpiceBot
|
||||||
|
pip3 install .
|
||||||
|
````
|
||||||
16
System-Files/Config/SpiceBotSERV.cfg
Normal file
16
System-Files/Config/SpiceBotSERV.cfg
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
[core]
|
||||||
|
name = SpiceBot
|
||||||
|
nick = SpiceBot
|
||||||
|
user = SpiceBot/SpiceBot
|
||||||
|
auth_method = server
|
||||||
|
auth_password = **********
|
||||||
|
admins = deathbybandaid,dysonparkes
|
||||||
|
host = 192.168.5.10
|
||||||
|
use_ssl = false
|
||||||
|
port = 5000
|
||||||
|
owner = deathbybandaid
|
||||||
|
channels = #spicebot
|
||||||
|
prefix = \.|!
|
||||||
|
homedir = /home/sopel/.sopel/
|
||||||
|
db_filename = /home/sopel/.sopel/SpiceBot.db
|
||||||
|
extra =
|
||||||
17
System-Files/systemd/SpiceBotSERV.service
Normal file
17
System-Files/systemd/SpiceBotSERV.service
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
[Unit]
|
||||||
|
Description=Sopel IRC bot
|
||||||
|
Documentation=http://sopel.chat/
|
||||||
|
After=network.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
User=sopel
|
||||||
|
PIDFile=/run/sopel/sopel-sopel.pid
|
||||||
|
ExecStart=/usr/local/bin/sopel -c /home/sopel/.sopel/SpiceBot.cfg
|
||||||
|
Restart=on-failure
|
||||||
|
RestartPreventExitStatus=2
|
||||||
|
RestartSec=30
|
||||||
|
Environment=LC_ALL=en_US.UTF-8
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
0
dev-requirements.txt
Normal file
0
dev-requirements.txt
Normal file
4
requirements.txt
Normal file
4
requirements.txt
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
sopel>=6.0,<7
|
||||||
|
spicemanip>=0.1.6
|
||||||
|
gitpython
|
||||||
|
sopel-modules.osd
|
||||||
43
setup.py
Executable file
43
setup.py
Executable file
@ -0,0 +1,43 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
from __future__ import print_function
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
from setuptools import setup, find_packages
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
print('Sopel does not correctly load modules installed with setup.py '
|
||||||
|
'directly. Please use "pip install .", or add {}/sopel_modules to '
|
||||||
|
'core.extra in your config.'.format(
|
||||||
|
os.path.dirname(os.path.abspath(__file__))),
|
||||||
|
file=sys.stderr)
|
||||||
|
|
||||||
|
with open('README.md') as readme_file:
|
||||||
|
readme = readme_file.read()
|
||||||
|
|
||||||
|
with open('NEWS') as history_file:
|
||||||
|
history = history_file.read()
|
||||||
|
|
||||||
|
with open('requirements.txt') as requirements_file:
|
||||||
|
requirements = [req for req in requirements_file.readlines()]
|
||||||
|
|
||||||
|
with open('dev-requirements.txt') as dev_requirements_file:
|
||||||
|
dev_requirements = [req for req in dev_requirements_file.readlines()]
|
||||||
|
|
||||||
|
|
||||||
|
setup(
|
||||||
|
name='sopel_modules.SpiceBot',
|
||||||
|
version='0.1.0',
|
||||||
|
description='SpiceBot aims to run SpiceBot as an IRC service',
|
||||||
|
long_description=readme + '\n\n' + history,
|
||||||
|
author='Sam Zick',
|
||||||
|
author_email='sam@deathbybandaid.net',
|
||||||
|
url='https://github.com/SpiceBot/SpiceBot',
|
||||||
|
packages=find_packages('.'),
|
||||||
|
namespace_packages=['sopel_modules'],
|
||||||
|
include_package_data=True,
|
||||||
|
install_requires=requirements,
|
||||||
|
tests_require=dev_requirements,
|
||||||
|
test_suite='tests',
|
||||||
|
license='Eiffel Forum License, version 2',
|
||||||
|
)
|
||||||
367
sopel_modules/SpiceBot_Channels/Channels.py
Normal file
367
sopel_modules/SpiceBot_Channels/Channels.py
Normal file
@ -0,0 +1,367 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# coding=utf-8
|
||||||
|
from __future__ import unicode_literals, absolute_import, print_function, division
|
||||||
|
|
||||||
|
# sopel imports
|
||||||
|
import sopel.module
|
||||||
|
from sopel.tools import stderr
|
||||||
|
from sopel.config.types import StaticSection, ValidatedAttribute
|
||||||
|
from sopel.module import OP, ADMIN, VOICE, OWNER, HALFOP
|
||||||
|
HOP = HALFOP
|
||||||
|
|
||||||
|
import time
|
||||||
|
import re
|
||||||
|
|
||||||
|
import spicemanip
|
||||||
|
|
||||||
|
import sopel_modules.osd
|
||||||
|
|
||||||
|
from sopel_modules.SpiceBot_SBTools import sopel_triggerargs, inlist
|
||||||
|
|
||||||
|
|
||||||
|
class SpiceBot_Channels_MainSection(StaticSection):
|
||||||
|
announcenew = ValidatedAttribute('announcenew', default=False)
|
||||||
|
joinall = ValidatedAttribute('joinall', default=False)
|
||||||
|
operadmin = ValidatedAttribute('operadmin', default=False)
|
||||||
|
|
||||||
|
|
||||||
|
def configure(config):
|
||||||
|
config.define_section("SpiceBot_Channels", SpiceBot_Channels_MainSection, validate=False)
|
||||||
|
config.SpiceBot_Channels.configure_setting('announcenew', 'SpiceBot_Channels Announce New Channels')
|
||||||
|
config.SpiceBot_Channels.configure_setting('announcenew', 'SpiceBot_Channels JOIN New Channels')
|
||||||
|
config.SpiceBot_Channels.configure_setting('announcenew', 'SpiceBot_Channels OPER ADMIN MODE')
|
||||||
|
|
||||||
|
|
||||||
|
def setup(bot):
|
||||||
|
stderr("[SpiceBot_Channels] Initial Setup processing...")
|
||||||
|
|
||||||
|
bot.config.define_section("SpiceBot_Channels", SpiceBot_Channels_MainSection, validate=False)
|
||||||
|
|
||||||
|
bot.memory['SpiceBot_Channels'] = dict()
|
||||||
|
bot.memory['SpiceBot_Channels']['channels'] = dict()
|
||||||
|
bot.memory['SpiceBot_Channels']['InitialProcess'] = False
|
||||||
|
bot.memory['SpiceBot_Channels']['ProcessLock'] = False
|
||||||
|
|
||||||
|
|
||||||
|
@sopel.module.event('001')
|
||||||
|
@sopel.module.rule('.*')
|
||||||
|
def trigger_channel_list_initial(bot, trigger):
|
||||||
|
|
||||||
|
# Unkickable
|
||||||
|
bot.write(('SAMODE', bot.nick, '+q'))
|
||||||
|
|
||||||
|
bot.write(['LIST'])
|
||||||
|
bot.memory['SpiceBot_Channels']['ProcessLock'] = True
|
||||||
|
|
||||||
|
stderr("[SpiceBot_Channels] Initial Channel list populating...")
|
||||||
|
starttime = time.time()
|
||||||
|
|
||||||
|
while not bot.memory['SpiceBot_Channels']['InitialProcess']:
|
||||||
|
timesince = time.time() - starttime
|
||||||
|
if timesince < 60:
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
stderr("[SpiceBot_Channels] Initial Channel list populating Timed Out.")
|
||||||
|
bot.memory['SpiceBot_Channels']['InitialProcess'] = True
|
||||||
|
|
||||||
|
channel_list_current(bot)
|
||||||
|
foundchannelcount = len(bot.memory['SpiceBot_Channels']['channels'].keys())
|
||||||
|
stderr("[SpiceBot_Channels] Channel listing finished! " + str(foundchannelcount) + " channel(s) found.")
|
||||||
|
|
||||||
|
# JOIN
|
||||||
|
if bot.config.SpiceBot_Channels.joinall:
|
||||||
|
for channel in bot.memory['SpiceBot_Channels']['channels'].keys():
|
||||||
|
if channel not in bot.channels.keys():
|
||||||
|
bot.write(('JOIN', bot.nick, bot.memory['SpiceBot_Channels']['channels'][channel]['name']))
|
||||||
|
if channel not in bot.channels.keys():
|
||||||
|
bot.write(('SAJOIN', bot.nick, bot.memory['SpiceBot_Channels']['channels'][channel]['name']))
|
||||||
|
|
||||||
|
# Chan ADMIN +a
|
||||||
|
for channel in bot.channels.keys():
|
||||||
|
if bot.config.SpiceBot_Channels.operadmin:
|
||||||
|
if not bot.channels[channel].privileges[bot.nick] < ADMIN:
|
||||||
|
bot.write(('SAMODE', channel, "+a", bot.nick))
|
||||||
|
channel_privs(bot, channel)
|
||||||
|
|
||||||
|
if "*" in bot.memory['SpiceBot_Channels']['channels']:
|
||||||
|
del bot.memory['SpiceBot_Channels']['channels']["*"]
|
||||||
|
|
||||||
|
while True:
|
||||||
|
time.sleep(1800)
|
||||||
|
oldlist = list(bot.memory['SpiceBot_Channels']['channels'].keys())
|
||||||
|
bot.write(['LIST'])
|
||||||
|
bot.memory['SpiceBot_Channels']['ProcessLock'] = True
|
||||||
|
|
||||||
|
while bot.memory['SpiceBot_Channels']['ProcessLock']:
|
||||||
|
pass
|
||||||
|
|
||||||
|
newlist = [item.lower() for item in oldlist if item.lower() not in bot.memory['SpiceBot_Channels']['channels']]
|
||||||
|
if "*" in newlist:
|
||||||
|
newlist.remove("*")
|
||||||
|
if len(newlist) and bot.config.SpiceBot_Channels.announcenew:
|
||||||
|
bot.osd(["The Following channel(s) are new:", spicemanip.main(newlist, 'andlist')], bot.channels.keys())
|
||||||
|
|
||||||
|
# JOIN
|
||||||
|
if bot.config.SpiceBot_Channels.joinall:
|
||||||
|
for channel in bot.memory['SpiceBot_Channels']['channels'].keys():
|
||||||
|
if channel not in bot.channels.keys():
|
||||||
|
bot.write(('JOIN', bot.nick, bot.memory['SpiceBot_Channels']['channels'][channel]['name']))
|
||||||
|
if channel not in bot.channels.keys():
|
||||||
|
bot.write(('SAJOIN', bot.nick, bot.memory['SpiceBot_Channels']['channels'][channel]['name']))
|
||||||
|
|
||||||
|
# Chan ADMIN +a
|
||||||
|
for channel in bot.channels.keys():
|
||||||
|
if bot.config.SpiceBot_Channels.operadmin:
|
||||||
|
if not bot.channels[channel].privileges[bot.nick] < ADMIN:
|
||||||
|
bot.write(('SAMODE', channel, "+a", bot.nick))
|
||||||
|
channel_privs(bot, channel)
|
||||||
|
|
||||||
|
if "*" in bot.memory['SpiceBot_Channels']['channels']:
|
||||||
|
del bot.memory['SpiceBot_Channels']['channels']["*"]
|
||||||
|
|
||||||
|
|
||||||
|
@sopel.module.event('321')
|
||||||
|
@sopel.module.rule('.*')
|
||||||
|
def watch_chanlist_start(bot, trigger):
|
||||||
|
bot.memory['SpiceBot_Channels']['ProcessLock'] = True
|
||||||
|
|
||||||
|
|
||||||
|
@sopel.module.event('322')
|
||||||
|
@sopel.module.rule('.*')
|
||||||
|
def watch_chanlist_populate(bot, trigger):
|
||||||
|
channel, _, topic = trigger.args[1:]
|
||||||
|
if channel.lower() not in bot.memory['SpiceBot_Channels']['channels']:
|
||||||
|
bot.memory['SpiceBot_Channels']['channels'][channel.lower()] = dict()
|
||||||
|
bot.memory['SpiceBot_Channels']['channels'][channel.lower()]['name'] = channel
|
||||||
|
bot.memory['SpiceBot_Channels']['channels'][channel.lower()]['topic'] = topic_compile(topic)
|
||||||
|
bot.memory['SpiceBot_Channels']['ProcessLock'] = True
|
||||||
|
|
||||||
|
|
||||||
|
@sopel.module.event('323')
|
||||||
|
@sopel.module.rule('.*')
|
||||||
|
def watch_chanlist_complete(bot, trigger):
|
||||||
|
bot.memory['SpiceBot_Channels']['ProcessLock'] = False
|
||||||
|
if not bot.memory['SpiceBot_Channels']['InitialProcess']:
|
||||||
|
bot.memory['SpiceBot_Channels']['InitialProcess'] = True
|
||||||
|
|
||||||
|
|
||||||
|
@sopel.module.nickname_commands('channels', 'channel')
|
||||||
|
def nickname_comand_chanstats(bot, trigger):
|
||||||
|
triggerargs = sopel_triggerargs(bot, trigger, 'nickname_command')
|
||||||
|
|
||||||
|
if not len(triggerargs):
|
||||||
|
commandused = 'list'
|
||||||
|
else:
|
||||||
|
commandused = spicemanip.main(triggerargs, 1).lower()
|
||||||
|
|
||||||
|
triggerargs = spicemanip.main(triggerargs, '2+', 'list')
|
||||||
|
|
||||||
|
channel_list_current(bot)
|
||||||
|
|
||||||
|
if commandused == 'list':
|
||||||
|
chanlist = spicemanip.main(bot.channels.keys(), 'andlist')
|
||||||
|
bot.osd("You can find me in " + chanlist)
|
||||||
|
return
|
||||||
|
|
||||||
|
elif commandused == 'total':
|
||||||
|
botcount = len(bot.channels.keys())
|
||||||
|
servercount = len(bot.memory['SpiceBot_Channels']['channels'].keys())
|
||||||
|
bot.osd("I am in " + str(botcount) + " of " + str(servercount) + " channel(s) available on this server.")
|
||||||
|
return
|
||||||
|
|
||||||
|
elif commandused == 'random':
|
||||||
|
channel = spicemanip.main(bot.memory['SpiceBot_Channels']['channels'], 'random')
|
||||||
|
topic = bot.memory['SpiceBot_Channels']['channels'][channel]['topic']
|
||||||
|
msg = ["Random channel for you: {}.".format(bot.memory['SpiceBot_Channels']['channels'][channel]['name'])]
|
||||||
|
if topic and not topic.isspace():
|
||||||
|
msg.append("The topic is: {}".format(topic))
|
||||||
|
else:
|
||||||
|
msg.append("Its topic is empty.")
|
||||||
|
bot.osd(msg)
|
||||||
|
return
|
||||||
|
|
||||||
|
elif commandused == 'update':
|
||||||
|
if not trigger.admin:
|
||||||
|
bot.osd("You do not have permission to update the channel listing.")
|
||||||
|
return
|
||||||
|
bot.write(['LIST'])
|
||||||
|
bot.osd(["[SpiceBot_Channels]", "I am now updating the channel listing for this server."])
|
||||||
|
bot.memory['SpiceBot_Channels']['ProcessLock'] = True
|
||||||
|
while bot.memory['SpiceBot_Channels']['ProcessLock']:
|
||||||
|
pass
|
||||||
|
foundchannelcount = len(bot.memory['SpiceBot_Channels']['channels'].keys())
|
||||||
|
bot.osd("[SpiceBot_Channels]", "Channel listing finished!", str(foundchannelcount) + " channel(s) found.")
|
||||||
|
return
|
||||||
|
|
||||||
|
elif commandused == 'topic':
|
||||||
|
if not len(triggerargs):
|
||||||
|
bot.osd("Channel name input missing.")
|
||||||
|
return
|
||||||
|
channel = spicemanip.main(triggerargs, 1)
|
||||||
|
if not inlist(bot, channel.lower(), bot.memory['SpiceBot_Channels']['channels'].keys()):
|
||||||
|
bot.osd("Channel name {} not valid.".format(channel))
|
||||||
|
return
|
||||||
|
topic = bot.memory['SpiceBot_Channels']['channels'][channel.lower()]['topic']
|
||||||
|
channel = bot.memory['SpiceBot_Channels']['channels'][channel.lower()]['name']
|
||||||
|
bot.osd("Topic for {}: {}".format(channel, topic))
|
||||||
|
return
|
||||||
|
|
||||||
|
# OP list
|
||||||
|
if commandused == 'op':
|
||||||
|
channel = spicemanip.main(triggerargs, 1)
|
||||||
|
if not inlist(bot, channel.lower(), bot.memory['SpiceBot_Channels']['channels'].keys()):
|
||||||
|
bot.osd("Channel name {} not valid.".format(channel))
|
||||||
|
return
|
||||||
|
if not inlist(bot, channel.lower(), bot.channels.keys()):
|
||||||
|
bot.osd("I need to be in {} to see nick privileges.".format(channel))
|
||||||
|
return
|
||||||
|
channel_privs(bot, channel)
|
||||||
|
dispmsg = []
|
||||||
|
if not len(bot.memory['SpiceBot_Channels']['channels'][str(channel).lower()][commandused.upper()]):
|
||||||
|
dispmsg.append("There are no Channel " + commandused.upper() + "s for " + str(channel))
|
||||||
|
else:
|
||||||
|
oplist = spicemanip.main(bot.memory['SpiceBot_Channels']['channels'][str(channel).lower()][commandused.upper()], 'andlist')
|
||||||
|
dispmsg.append("Channel " + commandused.upper() + "s for " + str(channel) + " are: " + oplist)
|
||||||
|
bot.osd(dispmsg, trigger.nick, 'notice')
|
||||||
|
return
|
||||||
|
|
||||||
|
# HOP list
|
||||||
|
if commandused == 'hop':
|
||||||
|
channel = spicemanip.main(triggerargs, 1)
|
||||||
|
if not inlist(bot, channel.lower(), bot.memory['SpiceBot_Channels']['channels'].keys()):
|
||||||
|
bot.osd("Channel name {} not valid.".format(channel))
|
||||||
|
return
|
||||||
|
if not inlist(bot, channel.lower(), bot.channels.keys()):
|
||||||
|
bot.osd("I need to be in {} to see nick privileges.".format(channel))
|
||||||
|
return
|
||||||
|
channel_privs(bot, channel)
|
||||||
|
dispmsg = []
|
||||||
|
if not len(bot.memory['SpiceBot_Channels']['channels'][str(channel).lower()][commandused.upper()]):
|
||||||
|
dispmsg.append("There are no Channel " + commandused.upper() + "s for " + str(channel))
|
||||||
|
else:
|
||||||
|
oplist = spicemanip.main(bot.memory['SpiceBot_Channels']['channels'][str(channel).lower()][commandused.upper()], 'andlist')
|
||||||
|
dispmsg.append("Channel " + commandused.upper() + "s for " + str(channel) + " are: " + oplist)
|
||||||
|
bot.osd(dispmsg, trigger.nick, 'notice')
|
||||||
|
return
|
||||||
|
|
||||||
|
# Voice List
|
||||||
|
if commandused == 'voice':
|
||||||
|
channel = spicemanip.main(triggerargs, 1)
|
||||||
|
if not inlist(bot, channel.lower(), bot.memory['SpiceBot_Channels']['channels'].keys()):
|
||||||
|
bot.osd("Channel name {} not valid.".format(channel))
|
||||||
|
return
|
||||||
|
if not inlist(bot, channel.lower(), bot.channels.keys()):
|
||||||
|
bot.osd("I need to be in {} to see nick privileges.".format(channel))
|
||||||
|
return
|
||||||
|
channel_privs(bot, channel)
|
||||||
|
dispmsg = []
|
||||||
|
if not len(bot.memory['SpiceBot_Channels']['channels'][str(channel).lower()][commandused.upper()]):
|
||||||
|
dispmsg.append("There are no Channel " + commandused.upper() + "s for " + str(channel))
|
||||||
|
else:
|
||||||
|
oplist = spicemanip.main(bot.memory['SpiceBot_Channels']['channels'][str(channel).lower()][commandused.upper()], 'andlist')
|
||||||
|
dispmsg.append("Channel " + commandused.upper() + "s for " + str(channel) + " are: " + oplist)
|
||||||
|
bot.osd(dispmsg, trigger.nick, 'notice')
|
||||||
|
return
|
||||||
|
|
||||||
|
# owner List
|
||||||
|
if commandused == 'owner':
|
||||||
|
channel = spicemanip.main(triggerargs, 1)
|
||||||
|
if not inlist(bot, channel.lower(), bot.memory['SpiceBot_Channels']['channels'].keys()):
|
||||||
|
bot.osd("Channel name {} not valid.".format(channel))
|
||||||
|
return
|
||||||
|
if not inlist(bot, channel.lower(), bot.channels.keys()):
|
||||||
|
bot.osd("I need to be in {} to see nick privileges.".format(channel))
|
||||||
|
return
|
||||||
|
channel_privs(bot, channel)
|
||||||
|
dispmsg = []
|
||||||
|
if not len(bot.memory['SpiceBot_Channels']['channels'][str(channel).lower()][commandused.upper()]):
|
||||||
|
dispmsg.append("There are no Channel " + commandused.upper() + "s for " + str(channel))
|
||||||
|
else:
|
||||||
|
oplist = spicemanip.main(bot.memory['SpiceBot_Channels']['channels'][str(channel).lower()][commandused.upper()], 'andlist')
|
||||||
|
dispmsg.append("Channel " + commandused.upper() + "s for " + str(channel) + " are: " + oplist)
|
||||||
|
bot.osd(dispmsg, trigger.nick, 'notice')
|
||||||
|
return
|
||||||
|
|
||||||
|
# admin List
|
||||||
|
if commandused == 'admin':
|
||||||
|
channel = spicemanip.main(triggerargs, 1)
|
||||||
|
if not inlist(bot, channel.lower(), bot.memory['SpiceBot_Channels']['channels'].keys()):
|
||||||
|
bot.osd("Channel name {} not valid.".format(channel))
|
||||||
|
return
|
||||||
|
if not inlist(bot, channel.lower(), bot.channels.keys()):
|
||||||
|
bot.osd("I need to be in {} to see nick privileges.".format(channel))
|
||||||
|
return
|
||||||
|
channel_privs(bot, channel)
|
||||||
|
dispmsg = []
|
||||||
|
if not len(bot.memory['SpiceBot_Channels']['channels'][str(channel).lower()][commandused.upper()]):
|
||||||
|
dispmsg.append("There are no Channel " + commandused.upper() + "s for " + str(channel))
|
||||||
|
else:
|
||||||
|
oplist = spicemanip.main(bot.memory['SpiceBot_Channels']['channels'][str(channel).lower()][commandused.upper()], 'andlist')
|
||||||
|
dispmsg.append("Channel " + commandused.upper() + "s for " + str(channel) + " are: " + oplist)
|
||||||
|
bot.osd(dispmsg, trigger.nick, 'notice')
|
||||||
|
return
|
||||||
|
|
||||||
|
# Users List
|
||||||
|
if commandused == 'users':
|
||||||
|
channel = spicemanip.main(triggerargs, 1)
|
||||||
|
if not inlist(bot, channel.lower(), bot.memory['SpiceBot_Channels']['channels'].keys()):
|
||||||
|
bot.osd("Channel name {} not valid.".format(channel))
|
||||||
|
return
|
||||||
|
if not inlist(bot, channel.lower(), bot.channels.keys()):
|
||||||
|
bot.osd("I need to be in {} to see user list.".format(channel))
|
||||||
|
return
|
||||||
|
dispmsg = []
|
||||||
|
if not len(bot.channels[channel].privileges.keys()):
|
||||||
|
dispmsg.append("There are no Channel users for " + str(channel))
|
||||||
|
else:
|
||||||
|
userslist = spicemanip.main(bot.channels[channel].privileges.keys(), 'andlist')
|
||||||
|
dispmsg.append("Channel users for " + str(channel) + " are: " + userslist)
|
||||||
|
bot.osd(dispmsg, trigger.nick, 'notice')
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
def channel_list_current(bot):
|
||||||
|
newlist = [item for item in bot.channels.keys() if item.lower() not in bot.memory['SpiceBot_Channels']['channels']]
|
||||||
|
for channel in newlist:
|
||||||
|
topic = bot.channels[channel].topic
|
||||||
|
bot.memory['SpiceBot_Channels']['channels'][str(channel).lower()] = dict()
|
||||||
|
bot.memory['SpiceBot_Channels']['channels'][str(channel).lower()]['name'] = str(channel)
|
||||||
|
bot.memory['SpiceBot_Channels']['channels'][str(channel).lower()]['topic'] = topic_compile(topic)
|
||||||
|
channel_privs(bot, channel)
|
||||||
|
|
||||||
|
if "*" in bot.memory['SpiceBot_Channels']:
|
||||||
|
bot.memory['SpiceBot_Channels'].remove("*")
|
||||||
|
|
||||||
|
|
||||||
|
def topic_compile(topic):
|
||||||
|
actual_topic = re.compile(r'^\[\+[a-zA-Z]+\] (.*)')
|
||||||
|
topic = re.sub(actual_topic, r'\1', topic)
|
||||||
|
return topic
|
||||||
|
|
||||||
|
|
||||||
|
def channel_privs(bot, channel):
|
||||||
|
|
||||||
|
if channel not in bot.memory['SpiceBot_Channels']['channels'].keys():
|
||||||
|
topic = bot.channels[channel].topic
|
||||||
|
bot.memory['SpiceBot_Channels']['channels'][str(channel).lower()] = dict()
|
||||||
|
bot.memory['SpiceBot_Channels']['channels'][str(channel).lower()]['name'] = str(channel)
|
||||||
|
bot.memory['SpiceBot_Channels']['channels'][str(channel).lower()]['topic'] = topic_compile(topic)
|
||||||
|
|
||||||
|
for chan in bot.memory['SpiceBot_Channels']['channels'].keys():
|
||||||
|
for privtype in ['VOICE', 'HOP', 'OP', 'ADMIN', 'OWNER']:
|
||||||
|
if privtype not in bot.memory['SpiceBot_Channels']['channels'][str(chan).lower()].keys():
|
||||||
|
bot.memory['SpiceBot_Channels']['channels'][str(chan).lower()][privtype] = []
|
||||||
|
|
||||||
|
for user in bot.channels[channel].privileges.keys():
|
||||||
|
try:
|
||||||
|
privnum = bot.channels[channel].privileges[user] or 0
|
||||||
|
except KeyError:
|
||||||
|
privnum = 0
|
||||||
|
|
||||||
|
for privtype in ['VOICE', 'HOP', 'OP', 'ADMIN', 'OWNER']:
|
||||||
|
if privnum == eval(privtype) or (privnum >= eval(privtype) and privtype == 'OWNER'):
|
||||||
|
if user not in bot.memory['SpiceBot_Channels']['channels'][str(channel).lower()][privtype]:
|
||||||
|
bot.memory['SpiceBot_Channels']['channels'][str(channel).lower()][privtype].append(user)
|
||||||
|
else:
|
||||||
|
if user in bot.memory['SpiceBot_Channels']['channels'][str(channel).lower()][privtype]:
|
||||||
|
bot.memory['SpiceBot_Channels']['channels'][str(channel).lower()][privtype].remove(user)
|
||||||
6
sopel_modules/SpiceBot_Channels/__init__.py
Normal file
6
sopel_modules/SpiceBot_Channels/__init__.py
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
# coding=utf-8
|
||||||
|
"""Event Parsing from IRC
|
||||||
|
"""
|
||||||
|
from __future__ import unicode_literals, absolute_import, print_function, division
|
||||||
|
|
||||||
|
from .Channels import *
|
||||||
76
sopel_modules/SpiceBot_Database_Addons/Databaseaddons.py
Normal file
76
sopel_modules/SpiceBot_Database_Addons/Databaseaddons.py
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# coding=utf-8
|
||||||
|
from __future__ import unicode_literals, absolute_import, print_function, division
|
||||||
|
|
||||||
|
# sopel imports
|
||||||
|
import sopel.module
|
||||||
|
from sopel.tools import stderr, Identifier
|
||||||
|
from sopel.db import _deserialize, SopelDB
|
||||||
|
|
||||||
|
import json
|
||||||
|
|
||||||
|
|
||||||
|
def setup(bot):
|
||||||
|
# Inject Database Functions
|
||||||
|
stderr("[SpiceBot_Databaseaddons] Implanting Database functions into bot.")
|
||||||
|
SopelDB.reset_nick_value = SopelDBCache.reset_nick_value
|
||||||
|
SopelDB.adjust_nick_value = SopelDBCache.adjust_nick_value
|
||||||
|
SopelDB.reset_channel_value = SopelDBCache.reset_channel_value
|
||||||
|
SopelDB.adjust_channel_value = SopelDBCache.adjust_channel_value
|
||||||
|
SopelDB._create_table = SopelDBCache._create_table
|
||||||
|
|
||||||
|
|
||||||
|
class SopelDBCache:
|
||||||
|
|
||||||
|
"""Dynamic Table Creation"""
|
||||||
|
|
||||||
|
def _create_table(self, tablename):
|
||||||
|
self.execute('CREATE TABLE IF NOT EXISTS ? (mainid STRING, key STRING, value STRING, PRIMARY KEY (mainid, key))', tablename)
|
||||||
|
|
||||||
|
"""Nicks"""
|
||||||
|
|
||||||
|
def reset_nick_value(self, nick, key):
|
||||||
|
"""Resets the value for a given key to be associated with the nick."""
|
||||||
|
nick = Identifier(nick)
|
||||||
|
nick_id = self.get_nick_id(nick)
|
||||||
|
self.execute('DELETE FROM nick_values WHERE nick_id = ? AND key = ?', [nick_id, key])
|
||||||
|
|
||||||
|
def adjust_nick_value(self, nick, key, value):
|
||||||
|
"""Adjusts the value for a given key to be associated with the nick."""
|
||||||
|
nick = Identifier(nick)
|
||||||
|
result = self.execute(
|
||||||
|
'SELECT value FROM nicknames JOIN nick_values '
|
||||||
|
'ON nicknames.nick_id = nick_values.nick_id '
|
||||||
|
'WHERE slug = ? AND key = ?',
|
||||||
|
[nick.lower(), key]
|
||||||
|
).fetchone()
|
||||||
|
if result is not None:
|
||||||
|
result = result[0]
|
||||||
|
current_value = _deserialize(result)
|
||||||
|
value = current_value + value
|
||||||
|
value = json.dumps(value, ensure_ascii=False)
|
||||||
|
nick_id = self.get_nick_id(nick)
|
||||||
|
self.execute('INSERT OR REPLACE INTO nick_values VALUES (?, ?, ?)',
|
||||||
|
[nick_id, key, value])
|
||||||
|
|
||||||
|
"""Channels"""
|
||||||
|
|
||||||
|
def reset_channel_value(self, channel, key):
|
||||||
|
"""Resets the value for a given key to be associated with a channel."""
|
||||||
|
channel = Identifier(channel).lower()
|
||||||
|
self.execute('DELETE FROM channel_values WHERE channel = ? AND key = ?', [channel, key])
|
||||||
|
|
||||||
|
def adjust_channel_value(self, channel, key, value):
|
||||||
|
"""Adjusts the value for a given key to be associated with the channel."""
|
||||||
|
channel = Identifier(channel).lower()
|
||||||
|
result = self.execute(
|
||||||
|
'SELECT value FROM channel_values WHERE channel = ? AND key = ?',
|
||||||
|
[channel, key]
|
||||||
|
).fetchone()
|
||||||
|
if result is not None:
|
||||||
|
result = result[0]
|
||||||
|
current_value = _deserialize(result)
|
||||||
|
value = current_value + value
|
||||||
|
value = json.dumps(value, ensure_ascii=False)
|
||||||
|
self.execute('INSERT OR REPLACE INTO channel_values VALUES (?, ?, ?)',
|
||||||
|
[channel, key, value])
|
||||||
6
sopel_modules/SpiceBot_Database_Addons/__init__.py
Normal file
6
sopel_modules/SpiceBot_Database_Addons/__init__.py
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
# coding=utf-8
|
||||||
|
"""Useful miscellaneous tools and shortcuts for SpiceBot Sopel modules
|
||||||
|
"""
|
||||||
|
from __future__ import unicode_literals, absolute_import, print_function, division
|
||||||
|
|
||||||
|
from .Databaseaddons import *
|
||||||
12
sopel_modules/SpiceBot_Database_Cache/DatabaseCache.py
Normal file
12
sopel_modules/SpiceBot_Database_Cache/DatabaseCache.py
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# coding=utf-8
|
||||||
|
from __future__ import unicode_literals, absolute_import, print_function, division
|
||||||
|
|
||||||
|
# sopel imports
|
||||||
|
import sopel.module
|
||||||
|
from sopel.tools import stderr
|
||||||
|
|
||||||
|
|
||||||
|
def setup(bot):
|
||||||
|
stderr("[SpiceBot_DatabaseCache] Setting up Database Cache.")
|
||||||
|
bot.memory['SpiceBot_DatabaseCache'] = dict()
|
||||||
6
sopel_modules/SpiceBot_Database_Cache/__init__.py
Normal file
6
sopel_modules/SpiceBot_Database_Cache/__init__.py
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
# coding=utf-8
|
||||||
|
"""Useful miscellaneous tools and shortcuts for SpiceBot Sopel modules
|
||||||
|
"""
|
||||||
|
from __future__ import unicode_literals, absolute_import, print_function, division
|
||||||
|
|
||||||
|
from .DatabaseCache import *
|
||||||
64
sopel_modules/SpiceBot_Database_Tools/DatabaseTools.py
Normal file
64
sopel_modules/SpiceBot_Database_Tools/DatabaseTools.py
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# coding=utf-8
|
||||||
|
from __future__ import unicode_literals, absolute_import, print_function, division
|
||||||
|
|
||||||
|
# sopel imports
|
||||||
|
import sopel.module
|
||||||
|
|
||||||
|
|
||||||
|
"""Dyanmic Table Creation"""
|
||||||
|
|
||||||
|
|
||||||
|
def db_create_table(bot, tablename):
|
||||||
|
bot.db._create_table(tablename)
|
||||||
|
|
||||||
|
|
||||||
|
"""Database Direct"""
|
||||||
|
|
||||||
|
|
||||||
|
# Get a value
|
||||||
|
def db_get_nick_value(bot, nick, key):
|
||||||
|
database_value = bot.db.get_nick_value(nick, key) or None
|
||||||
|
return database_value
|
||||||
|
|
||||||
|
|
||||||
|
# set a value
|
||||||
|
def db_set_nick_value(bot, nick, key, value):
|
||||||
|
bot.db.set_nick_value(nick, key, value)
|
||||||
|
|
||||||
|
|
||||||
|
# DELETE a value
|
||||||
|
def db_reset_value(bot, nick, key):
|
||||||
|
bot.db.reset_nick_value(nick, key)
|
||||||
|
|
||||||
|
|
||||||
|
# add or subtract from current value
|
||||||
|
def db_adjust_value(bot, nick, key, value):
|
||||||
|
bot.db.adjust_nick_value(nick, key, value)
|
||||||
|
|
||||||
|
|
||||||
|
# list stored in database, add or remove elements
|
||||||
|
def db_adjust_list(bot, nick, entries, key, adjustmentdirection):
|
||||||
|
if not isinstance(entries, list):
|
||||||
|
entries = [entries]
|
||||||
|
adjustlist = db_get_nick_value(bot, nick, key) or []
|
||||||
|
adjustlistnew = []
|
||||||
|
for x in adjustlist:
|
||||||
|
adjustlistnew.append(x)
|
||||||
|
db_reset_value(bot, nick, key)
|
||||||
|
adjustlist = []
|
||||||
|
if adjustmentdirection == 'add':
|
||||||
|
for y in entries:
|
||||||
|
if y not in adjustlistnew:
|
||||||
|
adjustlistnew.append(y)
|
||||||
|
elif adjustmentdirection == 'del':
|
||||||
|
for y in entries:
|
||||||
|
if y in adjustlistnew:
|
||||||
|
adjustlistnew.remove(y)
|
||||||
|
for x in adjustlistnew:
|
||||||
|
if x not in adjustlist:
|
||||||
|
adjustlist.append(x)
|
||||||
|
if adjustlist == []:
|
||||||
|
db_reset_value(bot, nick, key)
|
||||||
|
else:
|
||||||
|
db_set_nick_value(bot, nick, key, adjustlist)
|
||||||
6
sopel_modules/SpiceBot_Database_Tools/__init__.py
Normal file
6
sopel_modules/SpiceBot_Database_Tools/__init__.py
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
# coding=utf-8
|
||||||
|
"""Useful miscellaneous tools and shortcuts for SpiceBot Sopel modules
|
||||||
|
"""
|
||||||
|
from __future__ import unicode_literals, absolute_import, print_function, division
|
||||||
|
|
||||||
|
from .DatabaseTools import *
|
||||||
44
sopel_modules/SpiceBot_SBTools/__init__.py
Normal file
44
sopel_modules/SpiceBot_SBTools/__init__.py
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
# coding=utf-8
|
||||||
|
"""Useful miscellaneous tools and shortcuts for SpiceBot Sopel modules
|
||||||
|
"""
|
||||||
|
from __future__ import unicode_literals, absolute_import, print_function, division
|
||||||
|
|
||||||
|
import collections
|
||||||
|
|
||||||
|
import spicemanip
|
||||||
|
|
||||||
|
|
||||||
|
def sopel_triggerargs(bot, trigger, command_type):
|
||||||
|
triggerargs = []
|
||||||
|
|
||||||
|
if len(trigger.args) > 1:
|
||||||
|
triggerargs = spicemanip.main(trigger.args[1], 'create')
|
||||||
|
triggerargs = spicemanip.main(triggerargs, 'create')
|
||||||
|
|
||||||
|
if command_type in ['module_command']:
|
||||||
|
triggerargs = spicemanip.main(triggerargs, '2+', 'list')
|
||||||
|
elif command_type in ['nickname_command']:
|
||||||
|
triggerargs = spicemanip.main(triggerargs, '3+', 'list')
|
||||||
|
|
||||||
|
return triggerargs
|
||||||
|
|
||||||
|
|
||||||
|
def inlist(bot, searchterm, searchlist):
|
||||||
|
|
||||||
|
# verify we are searching a list
|
||||||
|
if isinstance(searchlist, collections.abc.KeysView) or isinstance(searchlist, dict):
|
||||||
|
searchlist = [x for x in searchlist]
|
||||||
|
if not isinstance(searchlist, list):
|
||||||
|
searchlist = [searchlist]
|
||||||
|
rebuildlist = []
|
||||||
|
for searchitem in searchlist:
|
||||||
|
rebuildlist.append(str(searchitem))
|
||||||
|
|
||||||
|
searchterm = str(searchterm)
|
||||||
|
|
||||||
|
if searchterm in rebuildlist:
|
||||||
|
return True
|
||||||
|
elif searchterm.lower() in [searching.lower() for searching in rebuildlist]:
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
return False
|
||||||
1
sopel_modules/__init__.py
Normal file
1
sopel_modules/__init__.py
Normal file
@ -0,0 +1 @@
|
|||||||
|
__import__('pkg_resources').declare_namespace(__name__)
|
||||||
1
tests/__init__.py
Normal file
1
tests/__init__.py
Normal file
@ -0,0 +1 @@
|
|||||||
|
# coding=utf-8
|
||||||
14
tests/test_cookiecutter.py
Normal file
14
tests/test_cookiecutter.py
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# coding=utf-8
|
||||||
|
from __future__ import unicode_literals, absolute_import, division, print_function
|
||||||
|
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
from sopel_modules.SpiceBot import *
|
||||||
|
|
||||||
|
class TestSpiceBot(unittest.TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def testSomething(self):
|
||||||
|
pass
|
||||||
Loading…
Reference in New Issue
Block a user