Compare commits

..

No commits in common. "master" and "v1.9.2" have entirely different histories.

9 changed files with 55 additions and 95 deletions

4
.github/FUNDING.yml vendored
View File

@ -1,4 +0,0 @@
github: archangelic
ko_fi: archangelic
liberapay: archangelic
custom: ["https://paypal.me/archangelic", "https://cash.app/$archangelic"]

View File

@ -1,30 +0,0 @@
# This workflows will upload a Python Package using Twine when a release is created
# For more information see: https://help.github.com/en/actions/language-and-framework-guides/using-python-with-github-actions#publishing-to-package-registries
name: Upload Python Package
on:
release:
types: [created]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: '3.x'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install setuptools wheel twine
- name: Build and publish
env:
TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }}
TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }}
run: |
python setup.py upload

View File

@ -127,14 +127,14 @@ These options are the same for both IRC and Twitch
There are two types of plugins, commands and listeners. Commands only activate if a message starts with the command word, while listeners receive all messages and are parsed by the plugin for maximum flexibility. There are two types of plugins, commands and listeners. Commands only activate if a message starts with the command word, while listeners receive all messages and are parsed by the plugin for maximum flexibility.
In your chosen plugins directory ("plugins" by default) make a python file with a function. You use the `@pinhook.plugin.command` decorator to create command plugins, or `@pinhook.plugin.listener` to create listeners. In your chosen plugins directory ("plugins" by default) make a python file with a function. You use the `@pinhook.plugin.register` decorator to create command plugins, or `@pinhook.plugin.listener` to create listeners.
The function will need to be structured as such: The function will need to be structured as such:
```python ```python
import pinhook.plugin import pinhook.plugin
@pinhook.plugin.command('!test') @pinhook.plugin.register('!test')
def test_plugin(msg): def test_plugin(msg):
message = '{}: this is a test!'.format(msg.nick) message = '{}: this is a test!'.format(msg.nick)
return pinhook.plugin.message(message) return pinhook.plugin.message(message)
@ -162,12 +162,15 @@ It also contains the following IRC functions:
* `action`: same as privmsg, but does a CTCP action. (i.e., `/me does a thing`) * `action`: same as privmsg, but does a CTCP action. (i.e., `/me does a thing`)
* `notice`: send a notice * `notice`: send a notice
You can optionally set a command to be used only by ops You can optionally use the `@pinhook.plugin.ops` decorator to denote that a command should only be executable by a bot op.
* If you specify the optional second argument, it will be displayed when a non-op attempts to execute the command
The function will need to be structured as such: The function will need to be structured as such:
```python ```python
@pinhook.plugin.command('!test', ops=True, ops_msg='This command can only be run by an op') @pinhook.plugin.register('!test')
@pinhook.plugin.ops('!test', 'Only ops can run this command!')
def test_plugin(msg): def test_plugin(msg):
return pinhook.plugin.message('This was run by an op!') return pinhook.plugin.message('This was run by an op!')
``` ```

View File

@ -1 +1 @@
theme: jekyll-theme-minimal theme: jekyll-theme-midnight

View File

@ -17,7 +17,7 @@ def build_output(rolls, modifier):
output = start output = start
return output return output
@pinhook.plugin.command('!roll') @pinhook.plugin.register('!roll')
def roll(msg): def roll(msg):
matches = dicepattern.match(msg.arg) matches = dicepattern.match(msg.arg)
if matches: if matches:

View File

@ -17,7 +17,7 @@ def build_output(rolls, modifier):
output = start output = start
return output return output
@pinhook.plugin.command('!roll') @pinhook.plugin.register('!roll')
def roll(msg): def roll(msg):
matches = dicepattern.match(msg.arg) matches = dicepattern.match(msg.arg)
if matches: if matches:

View File

@ -1 +1 @@
__version__ = '1.9.7' __version__ = '1.9.2'

View File

@ -14,20 +14,6 @@ irc.client.ServerConnection.buffer_class.errors = 'replace'
class Bot(irc.bot.SingleServerIRCBot): class Bot(irc.bot.SingleServerIRCBot):
internal_commands = {
'join': 'join a channel',
'quit': 'force the bot to quit',
'reload': 'force bot to reload all plugins',
'enable': 'enable a plugin',
'disable': 'disable a plugin',
'op': 'add a user as bot operator',
'deop': 'remove a user as bot operator',
'ops': 'list all ops',
'ban': 'ban a user from using the bot',
'unban': 'remove bot ban for user',
'banlist': 'currently banned nicks'
}
def __init__(self, channels, nickname, server, **kwargs): def __init__(self, channels, nickname, server, **kwargs):
self.port = kwargs.get('port', 6667) self.port = kwargs.get('port', 6667)
self.ops = kwargs.get('ops', []) self.ops = kwargs.get('ops', [])
@ -50,6 +36,21 @@ class Bot(irc.bot.SingleServerIRCBot):
self.chanlist = channels self.chanlist = channels
self.bot_nick = nickname self.bot_nick = nickname
self.start_logging() self.start_logging()
self.output_message = plugin.message
self.output_action = plugin.action
self.internal_commands = {
'join': 'join a channel',
'quit': 'force the bot to quit',
'reload': 'force bot to reload all plugins',
'enable': 'enable a plugin',
'disable': 'disable a plugin',
'op': 'add a user as bot operator',
'deop': 'remove a user as bot operator',
'ops': 'list all ops',
'ban': 'ban a user from using the bot',
'unban': 'remove bot ban for user',
'banlist': 'currently banned nicks'
}
self.internal_commands = {self.cmd_prefix + k: v for k,v in self.internal_commands.items()} self.internal_commands = {self.cmd_prefix + k: v for k,v in self.internal_commands.items()}
plugin.load_plugins(self.plugin_dir, use_prefix=self.use_prefix_for_plugins, cmd_prefix=self.cmd_prefix) plugin.load_plugins(self.plugin_dir, use_prefix=self.use_prefix_for_plugins, cmd_prefix=self.cmd_prefix)
@ -71,9 +72,9 @@ class Bot(irc.bot.SingleServerIRCBot):
if cmd: if cmd:
self.cmd = cmd self.cmd = cmd
self.arg = arg self.arg = arg
if text != None: if text:
self.text = text self.text = text
if not (cmd==None or text==None): if not (cmd or text):
raise TypeError('missing cmd or text parameter') raise TypeError('missing cmd or text parameter')
def start_logging(self): def start_logging(self):
@ -139,7 +140,7 @@ class Bot(irc.bot.SingleServerIRCBot):
try: try:
c.join(*arg.split()) c.join(*arg.split())
self.logger.info('joining {} per request of {}'.format(arg, nick)) self.logger.info('joining {} per request of {}'.format(arg, nick))
output = plugin.message('{}: joined {}'.format(nick, arg.split()[0])) output = self.output_message('{}: joined {}'.format(nick, arg.split()[0]))
except: except:
self.logger.exception('issue with join command: {}join #channel <channel key>'.format(self.cmd_prefix)) self.logger.exception('issue with join command: {}join #channel <channel key>'.format(self.cmd_prefix))
elif cmd == 'quit' and op: elif cmd == 'quit' and op:
@ -153,43 +154,43 @@ class Bot(irc.bot.SingleServerIRCBot):
elif cmd == 'reload' and op: elif cmd == 'reload' and op:
self.logger.info('reloading plugins per request of {}'.format(nick)) self.logger.info('reloading plugins per request of {}'.format(nick))
plugin.load_plugins(self.plugin_dir, use_prefix=self.use_prefix_for_plugins, cmd_prefix=self.cmd_prefix) plugin.load_plugins(self.plugin_dir, use_prefix=self.use_prefix_for_plugins, cmd_prefix=self.cmd_prefix)
output = plugin.message('Plugins reloaded') output = self.output_message('Plugins reloaded')
elif cmd == 'enable' and op: elif cmd == 'enable' and op:
if arg in plugin.plugins: if arg in plugin.plugins:
if plugin.plugins[arg].enabled: if plugin.plugins[arg].enabled:
output = plugin.message("{}: '{}' already enabled".format(nick, arg)) output = self.output_message("{}: '{}' already enabled".format(nick, arg))
else: else:
plugin.plugins[arg].enable() plugin.plugins[arg].enable()
output = plugin.message("{}: '{}' enabled!".format(nick, arg)) output = self.output_message("{}: '{}' enabled!".format(nick, arg))
else: else:
output = plugin.message("{}: '{}' not found".format(nick, arg)) output = self.output_message("{}: '{}' not found".format(nick, arg))
elif cmd == 'disable' and op: elif cmd == 'disable' and op:
if arg in plugin.plugins: if arg in plugin.plugins:
if not plugin.plugins[arg].enabled: if not plugin.plugins[arg].enabled:
output = plugin.message("{}: '{}' already disabled".format(nick, arg)) output = self.output_message("{}: '{}' already disabled".format(nick, arg))
else: else:
plugin.plugins[arg].disable() plugin.plugins[arg].disable()
output = plugin.message("{}: '{}' disabled!".format(nick, arg)) output = self.output_message("{}: '{}' disabled!".format(nick, arg))
elif cmd == 'op' and op: elif cmd == 'op' and op:
for o in arg.split(' '): for o in arg.split(' '):
self.ops.append(o) self.ops.append(o)
output = plugin.message('{}: {} added as op'.format(nick, arg)) output = self.output_message('{}: {} added as op'.format(nick, arg))
elif cmd == 'deop' and op: elif cmd == 'deop' and op:
for o in arg.split(' '): for o in arg.split(' '):
self.ops = [i for i in self.ops if i != o] self.ops = [i for i in self.ops if i != o]
output = plugin.message('{}: {} removed as op'.format(nick, arg)) output = self.output_message('{}: {} removed as op'.format(nick, arg))
elif cmd == 'ops' and op: elif cmd == 'ops' and op:
output = plugin.message('current ops: {}'.format(', '.join(self.ops))) output = self.output_message('current ops: {}'.format(', '.join(self.ops)))
elif cmd == 'ban' and op: elif cmd == 'ban' and op:
for o in arg.split(' '): for o in arg.split(' '):
self.banned_users.append(o) self.banned_users.append(o)
output = plugin.message('{}: banned {}'.format(nick, arg)) output = self.output_message('{}: banned {}'.format(nick, arg))
elif cmd == 'unban' and op: elif cmd == 'unban' and op:
for o in arg.split(' '): for o in arg.split(' '):
self.banned_users = [i for i in self.banned_users if i != o] self.banned_users = [i for i in self.banned_users if i != o]
output = plugin.message('{}: removed ban for {}'.format(nick, arg)) output = self.output_message('{}: removed ban for {}'.format(nick, arg))
elif cmd == 'banlist': elif cmd == 'banlist':
output = plugin.message('currently banned: {}'.format(', '.join(self.banned_users))) output = self.output_message('currently banned: {}'.format(', '.join(self.banned_users)))
return output return output
def call_plugins(self, privmsg, action, notice, chan, cmd, text, nick_list, nick, arg, msg_type): def call_plugins(self, privmsg, action, notice, chan, cmd, text, nick_list, nick, arg, msg_type):
@ -198,7 +199,7 @@ class Bot(irc.bot.SingleServerIRCBot):
try: try:
if plugin.cmds[cmd].ops and nick not in self.ops: if plugin.cmds[cmd].ops and nick not in self.ops:
if plugin.cmds[cmd].ops_msg: if plugin.cmds[cmd].ops_msg:
output = plugin.message(plugin.cmds[cmd].ops_msg) output = self.output_message(plugin.cmds[cmd].ops_msg)
elif plugin.cmds[cmd].enabled: elif plugin.cmds[cmd].enabled:
self.logger.debug('executing {}'.format(cmd)) self.logger.debug('executing {}'.format(cmd))
output = plugin.cmds[cmd].run(self.Message( output = plugin.cmds[cmd].run(self.Message(
@ -247,12 +248,7 @@ class Bot(irc.bot.SingleServerIRCBot):
def process_event(self, c, e): def process_event(self, c, e):
nick = e.source.nick nick = e.source.nick
if nick == self.bot_nick: text = e.arguments[0]
pass
if e.arguments:
text = e.arguments[0]
else:
text = ''
if e.type == 'privmsg' or e.type == 'pubmsg': if e.type == 'privmsg' or e.type == 'pubmsg':
msg_type = 'message' msg_type = 'message'
else: else:
@ -317,24 +313,18 @@ class Bot(irc.bot.SingleServerIRCBot):
class TwitchBot(Bot): class TwitchBot(Bot):
def __init__(self, nickname, channel, token, **kwargs): def __init__(self, nickname, channel, token, plugin_dir='plugins', log_level='info', ops=[]):
self.port = kwargs.get('port', 6667)
self.ops = kwargs.get('ops', [])
self.plugin_dir = kwargs.get('plugin_dir', 'plugins')
self.log_level = kwargs.get('log_level', 'info')
self.log_file = kwargs.get('log_file', None)
self.server_pass = kwargs.get('server_pass', None)
self.cmd_prefix = kwargs.get('cmd_prefix', '!')
self.use_prefix_for_plugins = kwargs.get('use_prefix_for_plugins', False)
self.disable_help = kwargs.get('disable_help', False)
self.banned_users = kwargs.get('banned_users', [])
self.bot_nick = nickname self.bot_nick = nickname
self.log_level = log_level
self.start_logging() self.start_logging()
self.channel = channel self.channel = channel
self.plugin_dir = plugin_dir
self.ops = ops
server = 'irc.twitch.tv'
port = 6667
self.logger.info('Joining Twitch Server') self.logger.info('Joining Twitch Server')
irc.bot.SingleServerIRCBot.__init__(self, [('irc.twitch.tv', 6667, 'oauth:'+token)], nickname, nickname) irc.bot.SingleServerIRCBot.__init__(self, [(server, port, 'oauth:'+token)], nickname, nickname)
self.internal_commands = {self.cmd_prefix + k: v for k,v in self.internal_commands.items()} plugin.load_plugins(self.plugin_dir)
plugin.load_plugins(self.plugin_dir, use_prefix=self.use_prefix_for_plugins, cmd_prefix=self.cmd_prefix)
def on_welcome(self, c, e): def on_welcome(self, c, e):
self.logger.info('requesting permissions') self.logger.info('requesting permissions')
@ -343,3 +333,4 @@ class TwitchBot(Bot):
c.cap('REQ', ':twitch.tv/commands') c.cap('REQ', ':twitch.tv/commands')
self.logger.info('Joining channel ' + self.channel) self.logger.info('Joining channel ' + self.channel)
c.join(self.channel) c.join(self.channel)

View File

@ -27,7 +27,7 @@ def read_conf(config, conf_format):
elif config.name.endswith(('.toml', '.tml')): elif config.name.endswith(('.toml', '.tml')):
conf_format = 'toml' conf_format = 'toml'
else: else:
raise click.ClickException('Could not detect file format, please supply using --format option') click.echo('Could not detect file format, please supply using --format option', err=True)
if conf_format == 'json': if conf_format == 'json':
import json import json
to_json = json.loads(config.read()) to_json = json.loads(config.read())
@ -36,7 +36,7 @@ def read_conf(config, conf_format):
try: try:
import yaml import yaml
except ImportError: except ImportError:
raise click.ClickException('yaml not installed, please use `pip3 install pinhook[yaml]` to install') click.echo('yaml not installed, please use `pip3 install pinhook[yaml]` to install', err=True)
else: else:
to_yaml = yaml.load(config.read(), Loader=yaml.FullLoader) to_yaml = yaml.load(config.read(), Loader=yaml.FullLoader)
output = schema.load(to_yaml) output = schema.load(to_yaml)
@ -44,7 +44,7 @@ def read_conf(config, conf_format):
try: try:
import toml import toml
except ImportError: except ImportError:
raise click.ClicKException('toml not installed, please use `pip3 install pinhook[toml]` to install') click.echo('toml not installed, please use `pip3 install pinhook[toml]` to install', err=True)
else: else:
to_toml = toml.load(config.name) to_toml = toml.load(config.name)
output = schema.load(to_toml) output = schema.load(to_toml)