#--depends-on commands #--depends-on config import re, traceback from src import ModuleManager, utils REGEX_SPLIT = re.compile("(?<!\\\\)/") REGEX_SED = re.compile("^(?:(\\S+)[:,] )?s/") SED_AMPERSAND = re.compile(r"((?:^|[^\\])(?:\\\\)*)&") @utils.export("channelset", utils.BoolSetting("sed", "Disable/Enable sed in a channel")) @utils.export( "channelset", utils.BoolSetting( "sed-sender-only", "Disable/Enable sed only looking at the messages sent by the user")) class Module(ModuleManager.BaseModule): def _closest_setting(self, event, setting, default): return event["target"].get_setting( setting, event["server"].get_setting(setting, default)) @utils.hook("command.regex") @utils.kwarg("command", "sed") @utils.kwarg("pattern", REGEX_SED) def channel_message(self, event): sed_split = re.split(REGEX_SPLIT, event["message"], 3) if len(sed_split) > 2: if not self._closest_setting(event, "sed", False): return
#--depends-on config from src import ModuleManager, utils DELAY = 5 rejoin_setting = utils.BoolSetting( "kick-rejoin", "Whether or not I should rejoin channels I get kicked from") delay_setting = utils.IntSetting( "kick-rejoin-delay", "Amount of seconds to wait before rejoining a channel") @utils.export("serverset", rejoin_setting) @utils.export("serverset", delay_setting) @utils.export("channelset", rejoin_setting) @utils.export("channelset", delay_setting) class Module(ModuleManager.BaseModule): def _should_rejoin(self, server, channel): return channel.get_setting("kick-rejoin", server.get_setting("kick-rejoin", False)) def _get_delay(self, server, channel): return channel.get_setting( "kick-rejoin-delay", server.get_setting("kick-rejoin-delay", DELAY)) @utils.hook("self.kick") def on_kick(self, event): if self._should_rejoin(event["server"], event["channel"]): delay = self._get_delay(event["server"], event["channel"])
#--depends-on config from src import ModuleManager, utils DELAY = 30 # 30 seconds @utils.export("channelset", utils.BoolSetting( "slowvoice", "Enable/disable giving +v to new users after a delay")) @utils.export("channelset", utils.IntSetting("slowvoice-delay", "Set delay for slowvoice in seconds")) class Module(ModuleManager.BaseModule): @utils.hook("timer.slowvoice") def timer(self, event): event["channel"].send_mode("+v", [event["user"].nickname]) @utils.hook("new.channel") def new_channel(self, event): event["channel"]._slowvoice_timers = {} @utils.hook("received.join") def on_join(self, event): if event["channel"].get_setting("slowvoice", False): delay = event["channel"].get_setting("slowvoice-delay", DELAY) timer = self.timers.add("slowvoice", delay, channel=event["channel"], user=event["user"])
#--depends-on commands #--depends-on format_activity #--depends-on permissions from src import EventManager, ModuleManager, utils @utils.export("channelset", utils.BoolSetting("relay-extras", "Whether or not to relay joins/parts/quits/modes/etc")) class Module(ModuleManager.BaseModule): @utils.hook("new.server") def new_server(self, event): event["server"]._relay_ignore = [] def _get_relays(self, channel): return channel.get_setting("channel-relays", []) def _relay(self, event, channel): if ("parsed_line" in event and event["parsed_line"].id in event["server"]._relay_ignore): event["server"]._relay_ignore.remove(event["parsed_line"].id) return relays = {} for relay_group in channel.get_setting("relay-groups", []): targets = self.bot.get_setting("relay-group-%s" % relay_group, []) for server_id, channel_name in targets: server = self.bot.get_server_by_id(server_id) if server and channel_name in server.channels: relay_channel = server.channels.get(channel_name) if not channel.id == relay_channel.id: if not server in relays:
#--depends-on channel_access #--depends-on check_mode #--depends-on commands #--depends-on shorturl import itertools, json, re, urllib.parse from src import ModuleManager, utils from . import colors, gitea, github FORM_ENCODED = "application/x-www-form-urlencoded" DEFAULT_EVENT_CATEGORIES = [ "ping", "code", "pr", "issue", "repo" ] @utils.export("channelset", utils.BoolSetting("git-prevent-highlight", "Enable/disable preventing highlights")) @utils.export("channelset", utils.BoolSetting("git-hide-organisation", "Hide/show organisation in repository names")) @utils.export("channelset", utils.BoolSetting("git-hide-prefix", "Hide/show command-like prefix on git webhook outputs")) class Module(ModuleManager.BaseModule): _name = "Webhooks" def on_load(self): self._github = github.GitHub(self.log) self._gitea = gitea.Gitea() @utils.hook("api.post.github") def _api_github_webhook(self, event): return self._webhook("github", "GitHub", self._github, event["data"], event["headers"])
#--depends-on config #--depends-on format_activity import datetime, os.path from src import ModuleManager, utils ROOT_DIRECTORY = os.path.dirname(os.path.realpath(__file__)) LOGS_DIRECTORY = os.path.join(ROOT_DIRECTORY, "logs") @utils.export("channelset", utils.BoolSetting("log", "Enable/disable channel logging")) class Module(ModuleManager.BaseModule): def _log_file(self, server_name, channel_name): return open( os.path.join(LOGS_DIRECTORY, "%s%s.log" % (server_name, channel_name)), "a") def _log(self, event, channel): if channel.get_setting("log", False): with self._log_file(str(event["server"]), str(channel)) as log: timestamp = datetime.datetime.now().strftime("%x %X") log.write("%s %s\n" % (timestamp, event["line"])) @utils.hook("formatted.message.channel") @utils.hook("formatted.notice.channel") @utils.hook("formatted.join") @utils.hook("formatted.part") @utils.hook("formatted.nick") @utils.hook("formatted.invite") @utils.hook("formatted.mode.channel")
#--depends-on config #--depends-on format_activity import datetime from src import EventManager, ModuleManager, utils @utils.export("botset", utils.BoolSetting("print-motd", "Set whether I print /motd")) class Module(ModuleManager.BaseModule): def _print(self, event): self.bot.log.info("%s%s | %s", [ str(event["server"]), event["context"] or "", utils.irc.parse_format(event["line"])]) @utils.hook("formatted.message.channel") @utils.hook("formatted.notice.channel") @utils.hook("formatted.notice.private") @utils.hook("formatted.join") @utils.hook("formatted.part") @utils.hook("formatted.nick") @utils.hook("formatted.server-notice") @utils.hook("formatted.invite") @utils.hook("formatted.mode.channel") @utils.hook("formatted.topic") @utils.hook("formatted.topic-timestamp") @utils.hook("formatted.kick") @utils.hook("formatted.quit") @utils.hook("formatted.rename") @utils.hook("formatted.chghost") def formatted(self, event): self._print(event)
f"There were {len(relays)} relays found for " f"this query. {URL_RELAY_SEARCH_SEARCH}{search}") if not relays: raise utils.EventError("There were no relays found for this query.") details = relays[0] nickname = details["nickname"] consensus_weight = details["consensus_weight"] flags = " ".join(details["flags"]) url = URL_RELAY_SEARCH_DETAILS + details["fingerprint"] return f"{nickname} - CW: {consensus_weight} [{flags}] {url}" @utils.export( "channelset", utils.BoolSetting( "auto-torrelay", "Disable/Enable automatically getting Tor relay info from fingerprints" )) class Module(ModuleManager.BaseModule): _name = "Onionoo" @utils.hook("command.regex") @utils.kwarg("ignore_action", False) @utils.kwarg("priority", EventManager.PRIORITY_MONITOR) @utils.kwarg("command", "torrelay") @utils.kwarg("pattern", REGEX_SHA1_HEX) def channel_message(self, event): if event["target"].get_setting("auto-torrelay", False): event.eat() search = event["match"].group(0) try: relays = _get_relays_details(search)
import binascii, enum, os, uuid from src import ModuleManager, utils STR_NOVOTE = "Unknown vote '%s'" class VoteCastResult(enum.Enum): Cast = 1 Changed = 2 Unchanged = 3 @utils.export("channelset", utils.BoolSetting( "votes-start-restricted", "Whether starting a vote should be restricted to ops")) @utils.export( "channelset", utils.BoolSetting( "votes-cast-restricted", "Whether casting a vote should be restricted to voiced-and-above users" )) class Module(ModuleManager.BaseModule): def _get_vote(self, channel, vote_id): return channel.get_setting("vote-%s" % vote_id, None) def _set_vote(self, channel, vote_id, vote): channel.set_setting("vote-%s" % vote_id, vote) def _random_id(self, channel):
REGEX_YOUTUBE = re.compile("https?://(?:www.)?(?:youtu.be/|youtube.com/)\\S+", re.I) REGEX_ISO8601 = re.compile("PT(\d+H)?(\d+M)?(\d+S)?", re.I) URL_YOUTUBESEARCH = "https://www.googleapis.com/youtube/v3/search" URL_YOUTUBEVIDEO = "https://www.googleapis.com/youtube/v3/videos" URL_YOUTUBEPLAYLIST = "https://www.googleapis.com/youtube/v3/playlists" URL_YOUTUBESHORT = "https://youtu.be/%s" URL_VIDEO = "https://www.youtube.com/watch?v=%s" URL_PLAYLIST = "https://www.youtube.com/playlist?list=%s" ARROW_UP = "↑" ARROW_DOWN = "↓" @utils.export("channelset", utils.BoolSetting("auto-youtube", "Disable/Enable automatically getting info from youtube URLs")) @utils.export("channelset", utils.BoolSetting("youtube-safesearch", "Turn safe search off/on")) class Module(ModuleManager.BaseModule): def on_load(self): self.exports.add("search-youtube", self._search_youtube) def get_video_page(self, video_id, part): return utils.http.request(URL_YOUTUBEVIDEO, get_params={"part": part, "id": video_id, "key": self.bot.config["google-api-key"]}, json=True) def video_details(self, video_id): snippet = self.get_video_page(video_id, "snippet") if snippet.data["items"]: snippet = snippet.data["items"][0]["snippet"] statistics = self.get_video_page(video_id, "statistics").data[
#--depends-on commands import random, time from src import ModuleManager, utils @utils.export("channelset", utils.BoolSetting("channel-quotes", "Whether or not quotes added from this channel are kept in this channel")) class Module(ModuleManager.BaseModule): def category_and_quote(self, s): category, sep, quote = s.partition("=") category = category.strip() if not sep: return category, None return category, quote.strip() def _get_quotes(self, server, category): return server.get_setting("quotes-%s" % category, []) def _set_quotes(self, server, category, quotes): server.set_setting("quotes-%s" % category, quotes) @utils.hook("received.command.qadd", alias_of="quoteadd") @utils.hook("received.command.quoteadd", min_args=1) def quote_add(self, event): """ :help: Add a quote to a category :usage: <category> = <quote> """ category, quote = self.category_and_quote(event["args"]) if category and quote: target = event["server"]
#--depends-on commands #--depends-on config import random, re, time from src import EventManager, ModuleManager, utils DUCK = "・゜゜・。。・゜゜\_o< QUACK!" NO_DUCK = "There was no duck!" DEFAULT_MIN_MESSAGES = 100 @utils.export("channelset", utils.BoolSetting("ducks-enabled", "Whether or not to spawn ducks")) @utils.export("channelset", utils.IntRangeSetting(50, 200, "ducks-min-messages", "Minimum messages between ducks spawning")) @utils.export( "channelset", utils.BoolSetting( "ducks-kick", "Whether or not to kick someone talking to non-existent ducks")) class Module(ModuleManager.BaseModule): @utils.hook("new.channel") def new_channel(self, event): self.bootstrap_channel(event["channel"]) def bootstrap_channel(self, channel): if not hasattr(channel, "duck_active"): channel.duck_active = None
server = _bot.get_server_by_id(server_id) if server and channel_name in server.channels: follows.append( [server, server.channels.get(channel_name)]) for server, channel in follows: tweet = format._tweet(_exports, server, status) _events.on("send.stdout").call(target=channel, module_name="Tweets", server=server, message=tweet) @utils.export("channelset", utils.BoolSetting( "auto-tweet", "Enable/disable automatically getting tweet info")) class Module(ModuleManager.BaseModule): _stream = None def on_load(self): self._thread = None global _bot global _events global _exports global _log _bot = self.bot _events = self.events _exports = self.exports _log = self.log
def _parse(value): mechanism, _, arguments = value.partition(" ") mechanism = mechanism.upper() if mechanism in ALL_MECHANISMS: return {"mechanism": mechanism.upper(), "args": arguments} else: raise utils.SettingParseException("Unknown SASL mechanism '%s'" % mechanism) SASL_TIMEOUT = 15 # 15 seconds HARDFAIL = utils.BoolSetting( "sasl-hard-fail", "Set whether a SASL failure should cause a disconnect") @utils.export("serverset", utils.FunctionSetting( _parse, "sasl", "Set the sasl username/password for this server", example="PLAIN BitBot:hunter2", format=utils.sensitive_format)) @utils.export("serverset", HARDFAIL) @utils.export("botset", HARDFAIL) class Module(ModuleManager.BaseModule): @utils.hook("new.server") def new_server(self, event): event["server"]._sasl_timeout = None
URL_GEOIP = "http://ip-api.com/json/%s" REGEX_IPv6 = r"(?:(?:[a-f0-9]{1,4}:){2,}|[a-f0-9:]*::)[a-f0-9:]*" REGEX_IPv4 = r"(?:\d{1,3}\.){3}\d{1,3}" REGEX_IP = re.compile("%s|%s" % (REGEX_IPv4, REGEX_IPv6), re.I) def _parse(value): if utils.is_ip(value): return value return None @utils.export("botset", utils.BoolSetting( "configurable-nameservers", "Whether or not users can configure their own nameservers")) @utils.export("serverset", utils.FunctionSetting(_parse, "dns-nameserver", "Set DNS nameserver", example="8.8.8.8")) @utils.export("channelset", utils.FunctionSetting(_parse, "dns-nameserver", "Set DNS nameserver", example="8.8.8.8")) class Module(ModuleManager.BaseModule): @utils.hook("received.command.dns", min_args=1) def dns(self, event): """
import binascii, enum, os, uuid from src import ModuleManager, utils STR_NOVOTE = "Unknown vote '%s'" class VoteCastResult(enum.Enum): Cast = 1 Changed = 2 Unchanged = 3 @utils.export("channelset", utils.BoolSetting( "votes-start-restricted", "Whether starting a vote should be restricted to ops")) class Module(ModuleManager.BaseModule): def _get_vote(self, channel, vote_id): return channel.get_setting("vote-%s" % vote_id, None) def _set_vote(self, channel, vote_id, vote): channel.set_setting("vote-%s" % vote_id, vote) def _random_id(self, channel): while True: vote_id = binascii.hexlify(os.urandom(3)).decode("ascii") if self._get_vote(channel, vote_id) == None: return vote_id def _close_vote(self, channel, vote_id):
upper = value.upper() if upper in COMMAND_METHODS: return upper return None @utils.export("channelset", utils.Setting("command-prefix", "Set the command prefix used in this channel", example="!")) @utils.export("serverset", utils.Setting("command-prefix", "Set the command prefix used on this server", example="!")) @utils.export("serverset", CommandMethodSetting("command-method", "Set the method used to respond to commands")) @utils.export("channelset", CommandMethodSetting("command-method", "Set the method used to respond to commands")) @utils.export("botset", CommandMethodSetting("command-method", "Set the method used to respond to commands")) @utils.export("channelset", utils.BoolSetting("hide-prefix", "Disable/enable hiding prefix in command reponses")) @utils.export("channelset", utils.BoolSetting("commands", "Disable/enable responding to commands in-channel")) @utils.export("channelset", utils.BoolSetting("prefixed-commands", "Disable/enable responding to prefixed commands in-channel")) class Module(ModuleManager.BaseModule): @utils.hook("new.user") @utils.hook("new.channel") def new(self, event): if "user" in event: target = event["user"] else: target = event["channel"] target.last_stdout = None target.last_stderr = None
REGEX_PR_OR_ISSUE = re.compile( r"https?://github.com/([^/]+)/([^/]+)/(pull|issues)/(\d+)", re.I) REGEX_REF = re.compile(r"(?:\S+(?:\/\S+)?)?#\d+") API_ISSUE_URL = "https://api.github.com/repos/%s/%s/issues/%s" API_PULL_URL = "https://api.github.com/repos/%s/%s/pulls/%s" @utils.export("channelset", utils.Setting( "github-default-repo", "Set the default github repo for the current channel", example="jesopo/bitbot")) @utils.export("channelset", utils.BoolSetting( "auto-github", "Enable/disable automatically getting github issue/PR info")) @utils.export("channelset", utils.IntSetting( "auto-github-cooldown", "Set amount of seconds between auto-github duplicates", example="300")) class Module(ModuleManager.BaseModule): def _parse_ref(self, channel, ref): repo, _, number = ref.rpartition("#") org, _, repo = repo.partition("/") default_repo = channel.get_setting("github-default-repo", "") default_org, _, default_repo = default_repo.partition("/") if org and not repo:
#--depends-on check_mode #--depends-on commands #--depends-on shorturl import itertools, json, re, urllib.parse from src import ModuleManager, utils from . import colors, gitea, gogs, github, gitlab FORM_ENCODED = "application/x-www-form-urlencoded" DEFAULT_EVENT_CATEGORIES = [ "ping", "code", "pr", "issue", "repo" ] PRIVATE_SETTING_NAME = "git-show-private" PRIVATE_SETTING = utils.BoolSetting(PRIVATE_SETTING_NAME, "Whether or not to show git activity for private repositories") @utils.export("channelset", utils.BoolSetting("git-prevent-highlight", "Enable/disable preventing highlights")) @utils.export("channelset", utils.BoolSetting("git-hide-organisation", "Hide/show organisation in repository names")) @utils.export("channelset", utils.BoolSetting("git-hide-prefix", "Hide/show command-like prefix on git webhook outputs")) @utils.export("channelset", utils.BoolSetting("git-shorten-urls", "Weather or not git webhook URLs should be shortened")) @utils.export("botset", PRIVATE_SETTING) @utils.export("channelset", PRIVATE_SETTING) class Module(ModuleManager.BaseModule): _name = "Webhooks" def on_load(self):
from src import ModuleManager, utils REASON = "User is banned from this channel" @utils.export("channelset", utils.BoolSetting( "ban-enforce", "Whether or not to parse new bans and kick who they affect")) class Module(ModuleManager.BaseModule): @utils.hook("received.mode.channel") def on_mode(self, event): if event["channel"].get_setting("ban-enforce", False): bans = [] kicks = set([]) for mode, arg in event["modes"]: if mode[0] == "+" and mode[1] == "b": bans.append(arg) if bans: umasks = {u.hostmask(): u for u in event["channel"].users} for ban in bans: mask = utils.irc.hostmask_parse(ban) matches = list( utils.irc.hostmask_match_many(umasks.keys(), mask)) for match in matches: kicks.add(umasks[match]) if kicks: nicks = [u.nickname for u in kicks] event["channel"].send_kicks(sorted(nicks), REASON)
#--depends-on commands #--depends-on format_activity #--depends-on permissions from src import EventManager, ModuleManager, utils @utils.export("channelset", utils.BoolSetting( "relay-extras", "Whether or not to relay joins/parts/quits/modes/etc")) class Module(ModuleManager.BaseModule): @utils.hook("new.server") def new_server(self, event): event["server"]._relay_ignore = [] def _get_relays(self, channel): return channel.get_setting("channel-relays", []) def _relay(self, event, channel): if ("parsed_line" in event and event["parsed_line"].id in event["server"]._relay_ignore): event["server"]._relay_ignore.remove(event["parsed_line"].id) return relays = {} for relay_group in channel.get_setting("relay-groups", []): targets = self.bot.get_setting("relay-group-%s" % relay_group, []) for server_id, channel_name in targets: server = self.bot.get_server_by_id(server_id) if server and channel_name in server.channels:
REGEX_IMAGE = re.compile("https?://(?:i\.)?imgur.com/(\w+)") REGEX_GALLERY = re.compile("https?://imgur.com/gallery/(\w+)") GALLERY_FORMAT = "%s%s%sA gallery with %s image%s, %s views, posted %s (%s%s)%s" IMAGE_FORMAT = "%s%s%sA %s image, %sx%s, with %s views, posted %s%s" URL_IMAGE = "https://api.imgur.com/3/image/%s" URL_GALLERY = "https://api.imgur.com/3/gallery/%s" NSFW_TEXT = "(NSFW)" @utils.export("channelset", utils.BoolSetting( "auto-imgur", "Disable/Enable automatically getting info from Imgur URLs")) class Module(ModuleManager.BaseModule): def _prefix(self, data): text = "%s: " % data["id"] if data["nsfw"]: text += "[NSFW] " if data["account_url"]: text += "%s " % data["account_url"] return text @utils.hook("command.regex") @utils.kwarg("ignore_action", False) @utils.kwarg("command", "imgur") @utils.kwarg("pattern", REGEX_IMAGE) def _regex_image(self, event):
#--depends-on channel_access #--depends-on check_mode #--depends-on commands #--depends-on config from src import ModuleManager, utils class UserNotFoundException(Exception): pass class InvalidTimeoutException(Exception): pass @utils.export("channelset", utils.IntSetting("highlight-spam-threshold", "Set the number of nicknames in a message that qualifies as spam")) @utils.export("channelset", utils.BoolSetting("highlight-spam-protection", "Enable/Disable highlight spam protection")) @utils.export("channelset", utils.BoolSetting("highlight-spam-ban", "Enable/Disable banning highlight spammers instead of just kicking")) @utils.export("channelset", utils.Setting("ban-format", "Set ban format ($n = nick, $u = username, $h = hostname)", example="*!$u@$h")) @utils.export("serverset", utils.OptionsSetting("mute-method", ["qmode", "insp", "unreal", "none"], "Set this server's method of muting users")) class Module(ModuleManager.BaseModule): _name = "ChanOp" @utils.hook("timer.unban") def _timer_unban(self, event): server = self.bot.get_server_by_id(event["server_id"]) if server and event["channel_name"] in server.channels:
URL_YOUTUBESEARCH = "https://www.googleapis.com/youtube/v3/search" URL_YOUTUBEVIDEO = "https://www.googleapis.com/youtube/v3/videos" URL_YOUTUBEPLAYLIST = "https://www.googleapis.com/youtube/v3/playlists" URL_YOUTUBESHORT = "https://youtu.be/%s" URL_VIDEO = "https://www.youtube.com/watch?v=%s" URL_PLAYLIST = "https://www.youtube.com/playlist?list=%s" ARROW_UP = "↑" ARROW_DOWN = "↓" @utils.export( "channelset", utils.BoolSetting( "auto-youtube", "Disable/Enable automatically getting info from youtube URLs")) @utils.export("channelset", utils.BoolSetting("youtube-safesearch", "Turn safe search off/on")) class Module(ModuleManager.BaseModule): def on_load(self): self.exports.add("search-youtube", self._search_youtube) def get_video_page(self, video_id, part): return utils.http.request(URL_YOUTUBEVIDEO, get_params={ "part": part, "id": video_id, "key": self.bot.config["google-api-key"] },
#--depends-on commands #--depends-on config #--require-config virustotal-api-key # ^ get API key from https://www.virustotal.com/en/documentation/public-api/ import re from src import ModuleManager, utils URL_VIRUSTOTAL = "https://www.virustotal.com/vtapi/v2/url/report" RE_URL = re.compile(r"https?://\S+", re.I) @utils.export("channelset", utils.BoolSetting( "check-urls", "Enable/Disable automatically checking for malicious URLs")) @utils.export("serverset", utils.BoolSetting( "check-urls", "Enable/Disable automatically checking for malicious URLs")) @utils.export( "channelset", utils.BoolSetting( "check-urls-kick", "Enable/Disable automatically kicking users that send malicious URLs")) class Module(ModuleManager.BaseModule): _name = "CheckURL" @utils.hook("command.regex") @utils.kwarg("ignore_action", False) @utils.kwarg("command", "check-url")
#--depends-on commands #--depends-on config #--depends-on shorturl import hashlib, re, urllib.parse from src import EventManager, ModuleManager, utils @utils.export("channelset", utils.BoolSetting("auto-title", "Disable/Enable automatically getting info titles from URLs")) @utils.export("channelset", utils.BoolSetting("title-shorten", "Enable/disable shortening URLs when getting their title")) @utils.export("channelset", utils.BoolSetting("auto-title-first", "Enable/disable showing who first posted a URL that was auto-titled")) class Module(ModuleManager.BaseModule): def _url_hash(self, url): return "sha256:%s" % hashlib.sha256(url.lower().encode("utf8") ).hexdigest() def _get_title(self, server, channel, url): if not urllib.parse.urlparse(url).scheme: url = "http://%s" % url hostname = urllib.parse.urlparse(url).hostname if utils.http.is_localhost(hostname): self.log.warn("tried to get title of localhost: %s", [url]) return None try: page = utils.http.request(url, soup=True) except utils.http.HTTPWrongContentTypeException: return None
class UserNotFoundException(Exception): pass class InvalidTimeoutException(Exception): pass @utils.export( "channelset", utils.IntSetting( "highlight-spam-threshold", "Set the number of nicknames in a message that qualifies as spam")) @utils.export("channelset", utils.BoolSetting("highlight-spam-protection", "Enable/Disable highlight spam protection")) @utils.export( "channelset", utils.BoolSetting( "highlight-spam-ban", "Enable/Disable banning highlight spammers instead of just kicking")) @utils.export("channelset", utils.Setting( "ban-format", "Set ban format ($n = nick, $u = username, $h = hostname)", example="*!$u@$h")) @utils.export("serverset", utils.OptionsSetting("mute-method", ["qmode", "insp", "unreal", "none"], "Set this server's method of muting users")) class Module(ModuleManager.BaseModule):
#--depends-on commands #--depends-on config #--depends-on permissions import re, time from src import EventManager, ModuleManager, utils WORD_STOP = [",", ":"] KARMA_DELAY_SECONDS = 3 REGEX_KARMA = re.compile(r"^(.*)(\+{2}|\-{2})$") @utils.export("channelset", utils.BoolSetting("karma-verbose", "Enable/disable automatically responding to karma changes")) @utils.export("serverset", utils.BoolSetting("karma-nickname-only", "Enable/disable karma being for nicknames only")) class Module(ModuleManager.BaseModule): def _karma_str(self, karma): karma_str = str(karma) if karma < 0: return utils.irc.color(str(karma), utils.consts.RED) elif karma > 0: return utils.irc.color(str(karma), utils.consts.LIGHTGREEN) return str(karma) @utils.hook("new.user") def new_user(self, event): event["user"]._last_positive_karma = None event["user"]._last_negative_karma = None def _check_throttle(self, user, positive):
#--depends-on config #--depends-on shorturl import time from src import ModuleManager, utils import feedparser RSS_INTERVAL = 60 # 1 minute @utils.export("botset", utils.IntSetting("rss-interval", "Interval (in seconds) between RSS polls", example="120")) @utils.export("channelset", utils.BoolSetting("rss-shorten", "Whether or not to shorten RSS urls")) class Module(ModuleManager.BaseModule): _name = "RSS" def on_load(self): self.timers.add("rss", self.bot.get_setting("rss-interval", RSS_INTERVAL)) def _format_entry(self, server, feed_title, entry, shorten): title = entry["title"] author = entry.get("author", None) author = " by %s" % author if author else "" link = entry.get("link", None) if shorten:
_log.debug( "[HTTP] finishing _handle for %s from %s:%d (%d)", [method, self.client_address[0], self.client_address[1], code]) def do_GET(self): self._handle("GET") def do_POST(self): self._handle("POST") def log_message(self, format, *args): return @utils.export("botset", utils.BoolSetting("rest-api", "Enable/disable REST API")) @utils.export("botset", utils.BoolSetting("rest-api", "Enable/disable REST API minifying")) class Module(ModuleManager.BaseModule): def on_load(self): global _bot _bot = self.bot global _events _events = self.events global _log _log = self.log self.httpd = None