last commit
This commit is contained in:
parent
e013a50711
commit
7dca597a2a
|
@ -2,3 +2,5 @@ NIGGER DICKS
|
||||||
NIGGER DICKS
|
NIGGER DICKS
|
||||||
NIGGER DICKS
|
NIGGER DICKS
|
||||||
NIGGER DICKS
|
NIGGER DICKS
|
||||||
|
|
||||||
|
Now deprecated in favor of https://git.steelbea.me/iou1name/fulvia
|
||||||
|
|
3
bot.py
3
bot.py
|
@ -1,5 +1,4 @@
|
||||||
#! /usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
"""
|
"""
|
||||||
The core bot class. Say good bye to PYthon 2.
|
The core bot class. Say good bye to PYthon 2.
|
||||||
"""
|
"""
|
||||||
|
|
341
loader.py
341
loader.py
|
@ -9,220 +9,217 @@ import sys
|
||||||
|
|
||||||
from tools import itervalues, get_command_regexp
|
from tools import itervalues, get_command_regexp
|
||||||
|
|
||||||
if sys.version_info.major >= 3:
|
|
||||||
basestring = (str, bytes)
|
|
||||||
|
|
||||||
# Can be implementation-dependent
|
# Can be implementation-dependent
|
||||||
_regex_type = type(re.compile(''))
|
_regex_type = type(re.compile(''))
|
||||||
|
|
||||||
|
|
||||||
def get_module_description(path):
|
def get_module_description(path):
|
||||||
good_file = (os.path.isfile(path) and path.endswith('.py')
|
good_file = (os.path.isfile(path) and path.endswith('.py')
|
||||||
and not path.startswith('_'))
|
and not path.startswith('_'))
|
||||||
good_dir = (os.path.isdir(path) and
|
good_dir = (os.path.isdir(path) and
|
||||||
os.path.isfile(os.path.join(path, '__init__.py')))
|
os.path.isfile(os.path.join(path, '__init__.py')))
|
||||||
if good_file:
|
if good_file:
|
||||||
name = os.path.basename(path)[:-3]
|
name = os.path.basename(path)[:-3]
|
||||||
return (name, path, imp.PY_SOURCE)
|
return (name, path, imp.PY_SOURCE)
|
||||||
elif good_dir:
|
elif good_dir:
|
||||||
name = os.path.basename(path)
|
name = os.path.basename(path)
|
||||||
return (name, path, imp.PKG_DIRECTORY)
|
return (name, path, imp.PKG_DIRECTORY)
|
||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
def _update_modules_from_dir(modules, directory):
|
def _update_modules_from_dir(modules, directory):
|
||||||
# Note that this modifies modules in place
|
# Note that this modifies modules in place
|
||||||
for path in os.listdir(directory):
|
for path in os.listdir(directory):
|
||||||
path = os.path.join(directory, path)
|
path = os.path.join(directory, path)
|
||||||
result = get_module_description(path)
|
result = get_module_description(path)
|
||||||
if result:
|
if result:
|
||||||
modules[result[0]] = result[1:]
|
modules[result[0]] = result[1:]
|
||||||
|
|
||||||
|
|
||||||
def enumerate_modules(config, show_all=False):
|
def enumerate_modules(config, show_all=False):
|
||||||
"""Map the names of modules to the location of their file.
|
"""Map the names of modules to the location of their file.
|
||||||
|
|
||||||
Return a dict mapping the names of modules to a tuple of the module name,
|
Return a dict mapping the names of modules to a tuple of the module name,
|
||||||
the pathname and either `imp.PY_SOURCE` or `imp.PKG_DIRECTORY`. This
|
the pathname and either `imp.PY_SOURCE` or `imp.PKG_DIRECTORY`. This
|
||||||
searches the regular modules directory and all directories specified in the
|
searches the regular modules directory and all directories specified in the
|
||||||
`core.extra` attribute of the `config` object. If two modules have the same
|
`core.extra` attribute of the `config` object. If two modules have the same
|
||||||
name, the last one to be found will be returned and the rest will be
|
name, the last one to be found will be returned and the rest will be
|
||||||
ignored. Modules are found starting in the regular directory, followed by
|
ignored. Modules are found starting in the regular directory, followed by
|
||||||
`~/.sopel/modules`, and then through the extra directories in the order
|
`~/.sopel/modules`, and then through the extra directories in the order
|
||||||
that the are specified.
|
that the are specified.
|
||||||
|
|
||||||
If `show_all` is given as `True`, the `enable` and `exclude`
|
If `show_all` is given as `True`, the `enable` and `exclude`
|
||||||
configuration options will be ignored, and all modules will be shown
|
configuration options will be ignored, and all modules will be shown
|
||||||
(though duplicates will still be ignored as above).
|
(though duplicates will still be ignored as above).
|
||||||
"""
|
"""
|
||||||
modules = {}
|
modules = {}
|
||||||
|
|
||||||
# First, add modules from the regular modules directory
|
# First, add modules from the regular modules directory
|
||||||
main_dir = os.path.dirname(os.path.abspath(__file__))
|
main_dir = os.path.dirname(os.path.abspath(__file__))
|
||||||
modules_dir = os.path.join(main_dir, 'modules')
|
modules_dir = os.path.join(main_dir, 'modules')
|
||||||
_update_modules_from_dir(modules, modules_dir)
|
_update_modules_from_dir(modules, modules_dir)
|
||||||
for path in os.listdir(modules_dir):
|
for path in os.listdir(modules_dir):
|
||||||
break
|
break
|
||||||
|
|
||||||
# Then, find PyPI installed modules
|
# Then, find PyPI installed modules
|
||||||
# TODO does this work with all possible install mechanisms?
|
# TODO does this work with all possible install mechanisms?
|
||||||
try:
|
try:
|
||||||
import sopel_modules
|
import sopel_modules
|
||||||
except:
|
except:
|
||||||
pass
|
pass
|
||||||
else:
|
else:
|
||||||
for directory in sopel_modules.__path__:
|
for directory in sopel_modules.__path__:
|
||||||
_update_modules_from_dir(modules, directory)
|
_update_modules_from_dir(modules, directory)
|
||||||
|
|
||||||
# Next, look in ~/.sopel/modules
|
# Next, look in ~/.sopel/modules
|
||||||
home_modules_dir = os.path.join(config.homedir, 'modules')
|
home_modules_dir = os.path.join(config.homedir, 'modules')
|
||||||
if not os.path.isdir(home_modules_dir):
|
if not os.path.isdir(home_modules_dir):
|
||||||
os.makedirs(home_modules_dir)
|
os.makedirs(home_modules_dir)
|
||||||
_update_modules_from_dir(modules, home_modules_dir)
|
_update_modules_from_dir(modules, home_modules_dir)
|
||||||
|
|
||||||
# Last, look at all the extra directories.
|
# Last, look at all the extra directories.
|
||||||
for directory in config.core.extra:
|
for directory in config.core.extra:
|
||||||
_update_modules_from_dir(modules, directory)
|
_update_modules_from_dir(modules, directory)
|
||||||
|
|
||||||
# Coretasks is special. No custom user coretasks.
|
# Coretasks is special. No custom user coretasks.
|
||||||
ct_path = os.path.join(main_dir, 'coretasks.py')
|
ct_path = os.path.join(main_dir, 'coretasks.py')
|
||||||
modules['coretasks'] = (ct_path, imp.PY_SOURCE)
|
modules['coretasks'] = (ct_path, imp.PY_SOURCE)
|
||||||
|
|
||||||
# If caller wants all of them, don't apply white and blacklists
|
# If caller wants all of them, don't apply white and blacklists
|
||||||
if show_all:
|
if show_all:
|
||||||
return modules
|
return modules
|
||||||
|
|
||||||
# Apply whitelist, if present
|
# Apply whitelist, if present
|
||||||
enable = config.core.enable
|
enable = config.core.enable
|
||||||
if enable:
|
if enable:
|
||||||
enabled_modules = {'coretasks': modules['coretasks']}
|
enabled_modules = {'coretasks': modules['coretasks']}
|
||||||
for module in enable:
|
for module in enable:
|
||||||
if module in modules:
|
if module in modules:
|
||||||
enabled_modules[module] = modules[module]
|
enabled_modules[module] = modules[module]
|
||||||
modules = enabled_modules
|
modules = enabled_modules
|
||||||
|
|
||||||
# Apply blacklist, if present
|
# Apply blacklist, if present
|
||||||
exclude = config.core.exclude
|
exclude = config.core.exclude
|
||||||
for module in exclude:
|
for module in exclude:
|
||||||
if module in modules:
|
if module in modules:
|
||||||
del modules[module]
|
del modules[module]
|
||||||
|
|
||||||
return modules
|
return modules
|
||||||
|
|
||||||
|
|
||||||
def compile_rule(nick, pattern):
|
def compile_rule(nick, pattern):
|
||||||
# Not sure why this happens on reloads, but it shouldn't cause problems…
|
# Not sure why this happens on reloads, but it shouldn't cause problems…
|
||||||
if isinstance(pattern, _regex_type):
|
if isinstance(pattern, _regex_type):
|
||||||
return pattern
|
return pattern
|
||||||
|
|
||||||
nick = re.escape(nick)
|
nick = re.escape(nick)
|
||||||
pattern = pattern.replace('$nickname', nick)
|
pattern = pattern.replace('$nickname', nick)
|
||||||
pattern = pattern.replace('$nick', r'{}[,:]\s+'.format(nick))
|
pattern = pattern.replace('$nick', r'{}[,:]\s+'.format(nick))
|
||||||
flags = re.IGNORECASE
|
flags = re.IGNORECASE
|
||||||
if '\n' in pattern:
|
if '\n' in pattern:
|
||||||
flags |= re.VERBOSE
|
flags |= re.VERBOSE
|
||||||
return re.compile(pattern, flags)
|
return re.compile(pattern, flags)
|
||||||
|
|
||||||
|
|
||||||
def trim_docstring(doc):
|
def trim_docstring(doc):
|
||||||
"""Get the docstring as a series of lines that can be sent"""
|
"""Get the docstring as a series of lines that can be sent"""
|
||||||
if not doc:
|
if not doc:
|
||||||
return []
|
return []
|
||||||
lines = doc.expandtabs().splitlines()
|
lines = doc.expandtabs().splitlines()
|
||||||
indent = sys.maxsize
|
indent = sys.maxsize
|
||||||
for line in lines[1:]:
|
for line in lines[1:]:
|
||||||
stripped = line.lstrip()
|
stripped = line.lstrip()
|
||||||
if stripped:
|
if stripped:
|
||||||
indent = min(indent, len(line) - len(stripped))
|
indent = min(indent, len(line) - len(stripped))
|
||||||
trimmed = [lines[0].strip()]
|
trimmed = [lines[0].strip()]
|
||||||
if indent < sys.maxsize:
|
if indent < sys.maxsize:
|
||||||
for line in lines[1:]:
|
for line in lines[1:]:
|
||||||
trimmed.append(line[:].rstrip())
|
trimmed.append(line[:].rstrip())
|
||||||
while trimmed and not trimmed[-1]:
|
while trimmed and not trimmed[-1]:
|
||||||
trimmed.pop()
|
trimmed.pop()
|
||||||
while trimmed and not trimmed[0]:
|
while trimmed and not trimmed[0]:
|
||||||
trimmed.pop(0)
|
trimmed.pop(0)
|
||||||
return trimmed
|
return trimmed
|
||||||
|
|
||||||
|
|
||||||
def clean_callable(func, config):
|
def clean_callable(func, config):
|
||||||
"""Compiles the regexes, moves commands into func.rule, fixes up docs and
|
"""Compiles the regexes, moves commands into func.rule, fixes up docs and
|
||||||
puts them in func._docs, and sets defaults"""
|
puts them in func._docs, and sets defaults"""
|
||||||
nick = config.core.nick
|
nick = config.core.nick
|
||||||
prefix = config.core.prefix
|
prefix = config.core.prefix
|
||||||
help_prefix = config.core.help_prefix
|
help_prefix = config.core.help_prefix
|
||||||
func._docs = {}
|
func._docs = {}
|
||||||
doc = trim_docstring(func.__doc__)
|
doc = trim_docstring(func.__doc__)
|
||||||
example = None
|
example = None
|
||||||
|
|
||||||
func.unblockable = getattr(func, 'unblockable', False)
|
func.unblockable = getattr(func, 'unblockable', False)
|
||||||
func.priority = getattr(func, 'priority', 'medium')
|
func.priority = getattr(func, 'priority', 'medium')
|
||||||
func.thread = getattr(func, 'thread', True)
|
func.thread = getattr(func, 'thread', True)
|
||||||
func.rate = getattr(func, 'rate', 0)
|
func.rate = getattr(func, 'rate', 0)
|
||||||
func.channel_rate = getattr(func, 'channel_rate', 0)
|
func.channel_rate = getattr(func, 'channel_rate', 0)
|
||||||
func.global_rate = getattr(func, 'global_rate', 0)
|
func.global_rate = getattr(func, 'global_rate', 0)
|
||||||
|
|
||||||
if not hasattr(func, 'event'):
|
if not hasattr(func, 'event'):
|
||||||
func.event = ['PRIVMSG']
|
func.event = ['PRIVMSG']
|
||||||
else:
|
else:
|
||||||
if isinstance(func.event, basestring):
|
if isinstance(func.event, (str, bytes)):
|
||||||
func.event = [func.event.upper()]
|
func.event = [func.event.upper()]
|
||||||
else:
|
else:
|
||||||
func.event = [event.upper() for event in func.event]
|
func.event = [event.upper() for event in func.event]
|
||||||
|
|
||||||
if hasattr(func, 'rule'):
|
if hasattr(func, 'rule'):
|
||||||
if isinstance(func.rule, basestring):
|
if isinstance(func.rule, (str, bytes)):
|
||||||
func.rule = [func.rule]
|
func.rule = [func.rule]
|
||||||
func.rule = [compile_rule(nick, rule) for rule in func.rule]
|
func.rule = [compile_rule(nick, rule) for rule in func.rule]
|
||||||
|
|
||||||
if hasattr(func, 'commands'):
|
if hasattr(func, 'commands'):
|
||||||
func.rule = getattr(func, 'rule', [])
|
func.rule = getattr(func, 'rule', [])
|
||||||
for command in func.commands:
|
for command in func.commands:
|
||||||
regexp = get_command_regexp(prefix, command)
|
regexp = get_command_regexp(prefix, command)
|
||||||
func.rule.append(regexp)
|
func.rule.append(regexp)
|
||||||
if hasattr(func, 'example'):
|
if hasattr(func, 'example'):
|
||||||
example = func.example[0]["example"]
|
example = func.example[0]["example"]
|
||||||
example = example.replace('$nickname', nick)
|
example = example.replace('$nickname', nick)
|
||||||
if example[0] != help_prefix and not example.startswith(nick):
|
if example[0] != help_prefix and not example.startswith(nick):
|
||||||
example = help_prefix + example[len(help_prefix):]
|
example = help_prefix + example[len(help_prefix):]
|
||||||
if doc or example:
|
if doc or example:
|
||||||
for command in func.commands:
|
for command in func.commands:
|
||||||
func._docs[command] = (doc, example)
|
func._docs[command] = (doc, example)
|
||||||
|
|
||||||
|
|
||||||
def load_module(name, path, type_):
|
def load_module(name, path, type_):
|
||||||
"""Load a module, and sort out the callables and shutdowns"""
|
"""Load a module, and sort out the callables and shutdowns"""
|
||||||
if type_ == imp.PY_SOURCE:
|
if type_ == imp.PY_SOURCE:
|
||||||
with open(path) as mod:
|
with open(path) as mod:
|
||||||
module = imp.load_module(name, mod, path, ('.py', 'U', type_))
|
module = imp.load_module(name, mod, path, ('.py', 'U', type_))
|
||||||
elif type_ == imp.PKG_DIRECTORY:
|
elif type_ == imp.PKG_DIRECTORY:
|
||||||
module = imp.load_module(name, None, path, ('', '', type_))
|
module = imp.load_module(name, None, path, ('', '', type_))
|
||||||
else:
|
else:
|
||||||
raise TypeError('Unsupported module type')
|
raise TypeError('Unsupported module type')
|
||||||
return module, os.path.getmtime(path)
|
return module, os.path.getmtime(path)
|
||||||
|
|
||||||
|
|
||||||
def is_triggerable(obj):
|
def is_triggerable(obj):
|
||||||
return any(hasattr(obj, attr) for attr in ('rule', 'rule', 'intent',
|
return any(hasattr(obj, attr) for attr in ('rule', 'rule', 'intent',
|
||||||
'commands'))
|
'commands'))
|
||||||
|
|
||||||
|
|
||||||
def clean_module(module, config):
|
def clean_module(module, config):
|
||||||
callables = []
|
callables = []
|
||||||
shutdowns = []
|
shutdowns = []
|
||||||
jobs = []
|
jobs = []
|
||||||
urls = []
|
urls = []
|
||||||
for obj in itervalues(vars(module)):
|
for key, obj in dict.items(vars(module)):
|
||||||
if callable(obj):
|
if callable(obj):
|
||||||
if getattr(obj, '__name__', None) == 'shutdown':
|
if getattr(obj, '__name__', None) == 'shutdown':
|
||||||
shutdowns.append(obj)
|
shutdowns.append(obj)
|
||||||
elif is_triggerable(obj):
|
elif is_triggerable(obj):
|
||||||
clean_callable(obj, config)
|
clean_callable(obj, config)
|
||||||
callables.append(obj)
|
callables.append(obj)
|
||||||
elif hasattr(obj, 'interval'):
|
elif hasattr(obj, 'interval'):
|
||||||
clean_callable(obj, config)
|
clean_callable(obj, config)
|
||||||
jobs.append(obj)
|
jobs.append(obj)
|
||||||
elif hasattr(obj, 'url_regex'):
|
elif hasattr(obj, 'url_regex'):
|
||||||
urls.append(obj)
|
urls.append(obj)
|
||||||
return callables, jobs, shutdowns, urls
|
return callables, jobs, shutdowns, urls
|
||||||
|
|
|
@ -1,9 +1,6 @@
|
||||||
# coding=utf-8
|
#!/usr/bin/env python3
|
||||||
"""
|
"""
|
||||||
announce.py - Send a message to all channels
|
Sends a message to all channels the bot is currently in.
|
||||||
Copyright © 2013, Elad Alfassa, <elad@fedoraproject.org>
|
|
||||||
Licensed under the Eiffel Forum License 2.
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
from module import commands, example
|
from module import commands, example
|
||||||
|
|
||||||
|
@ -12,7 +9,7 @@ from module import commands, example
|
||||||
@example('.announce Some important message here')
|
@example('.announce Some important message here')
|
||||||
def announce(bot, trigger):
|
def announce(bot, trigger):
|
||||||
"""
|
"""
|
||||||
Send an announcement to all channels the bot is in
|
Send an announcement to all channels the bot is in.
|
||||||
"""
|
"""
|
||||||
if not trigger.admin:
|
if not trigger.admin:
|
||||||
bot.reply('Sorry, I can\'t let you do that')
|
bot.reply('Sorry, I can\'t let you do that')
|
||||||
|
|
|
@ -9,7 +9,6 @@ import random
|
||||||
from module import commands, example
|
from module import commands, example
|
||||||
|
|
||||||
@commands("grog")
|
@commands("grog")
|
||||||
@example(".grog")
|
|
||||||
def grog(bot, trigger):
|
def grog(bot, trigger):
|
||||||
"""
|
"""
|
||||||
Picks a random status effect from Grog of Substantial Whimsy effect.
|
Picks a random status effect from Grog of Substantial Whimsy effect.
|
||||||
|
|
|
@ -36,7 +36,8 @@ def roomTemp(bot, trigger):
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
res = requests.get("http://192.168.1.25/", timeout=10)
|
res = requests.get("http://192.168.1.25/", timeout=10)
|
||||||
time.sleep(0.5)
|
del res
|
||||||
|
time.sleep(1.5)
|
||||||
res = requests.get("http://192.168.1.25/", timeout=10)
|
res = requests.get("http://192.168.1.25/", timeout=10)
|
||||||
except requests.exceptions.ReadTimeout:
|
except requests.exceptions.ReadTimeout:
|
||||||
return bot.say("Connection error. Timeout reached.")
|
return bot.say("Connection error. Timeout reached.")
|
||||||
|
|
|
@ -15,11 +15,6 @@ import pytz
|
||||||
from module import commands, example, NOLIMIT
|
from module import commands, example, NOLIMIT
|
||||||
from tools.time import get_timezone, format_time
|
from tools.time import get_timezone, format_time
|
||||||
|
|
||||||
def filename(self):
|
|
||||||
name = self.nick + '-' + self.config.core.host + '.reminders.db'
|
|
||||||
return os.path.join(self.config.core.homedir, name)
|
|
||||||
|
|
||||||
|
|
||||||
def init_database(bot):
|
def init_database(bot):
|
||||||
"""
|
"""
|
||||||
Initializes the 'remind' table in the bot's database. Does nothing if
|
Initializes the 'remind' table in the bot's database. Does nothing if
|
||||||
|
|
|
@ -28,8 +28,8 @@ r_bing = re.compile(r'<h3><a href="([^"]+)"')
|
||||||
|
|
||||||
def bing_search(query, lang='en-GB'):
|
def bing_search(query, lang='en-GB'):
|
||||||
base = 'http://www.bing.com/search?mkt=%s&q=' % lang
|
base = 'http://www.bing.com/search?mkt=%s&q=' % lang
|
||||||
bytes = requests.get(base + query)
|
res = requests.get(base + query)
|
||||||
m = r_bing.search(bytes)
|
m = r_bing.search(res.text)
|
||||||
if m:
|
if m:
|
||||||
return m.group(1)
|
return m.group(1)
|
||||||
|
|
||||||
|
@ -39,12 +39,12 @@ r_duck = re.compile(r'nofollow" class="[^"]+" href="(?!https?:\/\/r\.search\.yah
|
||||||
def duck_search(query):
|
def duck_search(query):
|
||||||
query = query.replace('!', '')
|
query = query.replace('!', '')
|
||||||
uri = 'http://duckduckgo.com/html/?q=%s&kl=uk-en' % query
|
uri = 'http://duckduckgo.com/html/?q=%s&kl=uk-en' % query
|
||||||
bytes = requests.get(uri)
|
res = requests.get(uri)
|
||||||
if 'requests-result' in bytes: # filter out the adds on top of the page
|
if 'requests-result' in res.text: # filter out the adds on top of the page
|
||||||
bytes = bytes.split('requests-result')[1]
|
res.text = rex.text.split('requests-result')[1]
|
||||||
m = r_duck.search(bytes)
|
m = r_duck.search(res.text)
|
||||||
if m:
|
if m:
|
||||||
return requests.decode(m.group(1))
|
return res.text
|
||||||
|
|
||||||
# Alias google_search to duck_search
|
# Alias google_search to duck_search
|
||||||
google_search = duck_search
|
google_search = duck_search
|
||||||
|
|
|
@ -22,11 +22,11 @@ def setup(bot):
|
||||||
watching = cur.execute("SELECT * FROM watcher").fetchall()
|
watching = cur.execute("SELECT * FROM watcher").fetchall()
|
||||||
except:
|
except:
|
||||||
cur.execute("CREATE TABLE watcher("
|
cur.execute("CREATE TABLE watcher("
|
||||||
"api_url STRING PRIMARY KEY,"
|
"api_url TEXT PRIMARY KEY,"
|
||||||
"name STRING DEFAULT 'Anonymous',"
|
"name TEXT DEFAULT 'Anonymous',"
|
||||||
"last_post INT,"
|
"last_post INT,"
|
||||||
"time_since STRING,"
|
"time_since TEXT,"
|
||||||
"channel STRING)")
|
"channel TEXT)")
|
||||||
cur.commit()
|
cur.commit()
|
||||||
else:
|
else:
|
||||||
for thread in watching:
|
for thread in watching:
|
||||||
|
|
Loading…
Reference in New Issue
Block a user