async def modMention(message, client, typ): split = message.content.split() correctUsageString = getUseString(typ + "role", client) if await checkMinArgs(message, 2, correctUsageString): return sid = await checkInt(message, split[1], correctUsageString) if sid is False: return rid = await checkInt(message, split[2], correctUsageString) if rid is False: return role = message.guild.get_role(int(rid)) if not role: return await sendError(message, f"{split[2]} is not a valid role id.", correctUsageString) mentions = utils.loadJson(globals.MENTION_FILE) sData = utils.loadJson(globals.SERIES_FILE) sName = str(sid) if str(sid) in sData: sName = f"{sData[str(sid)]['title']} ({sName})" if typ == "add": if str(sid) not in mentions: mentions[str(sid)] = [] if str(rid) in mentions[str(sid)]: return await message.channel.send( f"Error. `{role.name} ({rid})` is already a mentioned role for series `{sName}`." ) mentions[str(sid)].append(str(rid)) elif typ == "remove": if str(rid) not in mentions[str(sid)]: return await message.channel.send( f"Error. `{role.name} ({rid})` is not a mentioned role for series `{sName}`." ) mentions[str(sid)] = [ x for x in mentions[str(sid)] if str(x) != str(rid) ] lst = [] for x in mentions[str(sid)]: role = message.guild.get_role(int(rid)) if role: name = role.name else: continue name = "unknown" lst.append(f"`{name} ({x})`") await message.channel.send(f"Pinged roles for **`{sName}`**: " + ", ".join(lst)) utils.dumpJson(mentions, globals.MENTION_FILE)
async def scanMessages(client, last=False): channel = client.get_channel(int(CONFIG['SUBMISSION_CHANNEL'])) log = None if last: log = utils.loadJson(globals.MSG_FILE) if not log: log = {"log": [], "members": {}, "last_parsed": ""} try: if last and log["last_parsed"]: last = await channel.fetch_message(log['last_parsed']) else: last = None except: last = None print("resetting log") log = {"log": [], "members": {}, "last_parsed": ""} async for msg in channel.history(limit=None, oldest_first=True, after=last): print("Scanning", msg.content) log['log'].append(sheetUtils.msgToDict(msg)) log['members'][msg.author.id] = msg.author.name log['last_parsed'] = msg.id with open("data/msg_log.json", "w+") as file: json.dump(log, file, indent=2) parse.parse() return len(log['log'])
async def modUser(message, client, typ): split = message.content.split() correctUsageString = getUseString(typ + "user", client) if await checkMinArgs(message, 1, correctUsageString): return val = await checkInt(message, split[1], correctUsageString) if val is False: return user = client.get_user(val) if not user: return await sendError(message, f"{split[1]} is not a valid user id.", correctUsageString) config = utils.loadJson(globals.CONFIG_FILE) if typ == "add": if str(val) in config["ADMINS"]: return await message.channel.send( f"Error. {user.name} ({val}) is already a bot admin.") config["ADMINS"].append(str(val)) elif typ == "remove": if str(val) not in config["ADMINS"]: return await message.channel.send( f"Error. {user.name} ({val}) is not a bot admin.") config["ADMINS"] = [x for x in config['ADMINS'] if x != str(val)] lst = [] for x in config['ADMINS']: user = client.get_user(int(x)) if user: name = user.name else: name = "unknown" lst.append(f"`{name} ({x})`") await message.channel.send("Current admins: " + ", ".join(lst)) utils.dumpJson(config, globals.CONFIG_FILE)
async def modChannel(message, client, typ): split = message.content.split() correctUsageString = getUseString(typ + "channel", client) if await checkMinArgs(message, 1, correctUsageString): return val = await checkInt(message, split[1], correctUsageString) if val is False: return ch = client.get_channel(val) if not ch: return await sendError(message, f"{split[1]} is not a valid channel id.", correctUsageString) config = utils.loadJson(globals.CONFIG_FILE) if typ == "add": if str(val) in config["UPDATE_CHANNELS"]: return await message.channel.send( f"Error. <#{val}> is already an update channel.") config["UPDATE_CHANNELS"].append(str(val)) elif typ == "remove": if str(val) not in config["UPDATE_CHANNELS"]: return await message.channel.send( f"Error. <#{val}> is not an update channel.") config["UPDATE_CHANNELS"] = [ x for x in config['UPDATE_CHANNELS'] if x != str(val) ] lst = [f"<#{x}>" for x in config['UPDATE_CHANNELS']] await message.channel.send("Current update channels:" + ", ".join(lst)) utils.dumpJson(config, globals.CONFIG_FILE)
def parse(): data = utils.loadJson(globals.MSG_FILE) i, warningCount = 0, 0 matches = [] warningLog = [] parsedData = [] for msg in data['log']: text = msg['content'].split("\n") m, failures = scanMessage(msg) if not m: # print('here',m, failures) continue if failures: cpy = copy.deepcopy(msg) cpy['failed'] = failures warningLog.append(cpy) dct = listToDict(m[0]) msg['parsed'] = dct matches.append(dct) parsedData.append(msg) matches = cleanMatches(matches) # debugPrint(matches, warningLog) with open(globals.PARSED_FILE, "w+") as file: d = { "parsed": parsedData, "warnings": warningLog, "members": data['members'] } json.dump(d, file, indent=2)
async def listSeries(message, client): sData = utils.loadJson(globals.SERIES_FILE) lst = [] for sid in sData: lst += [f"[{utils.zeroPad(sid)}] {sData[sid]['title']}"] join = '\n'.join(lst) text = f"```css\n{join}\n```" await message.channel.send(text)
def updateSeriesData(update): sid = update['sId'] data = utils.loadJson(globals.SERIES_FILE) if sid not in data or True: data[sid] = {} data[sid]['title'] = update['sName'] data[sid]['link'] = update['sLink'] data[sid]['cover'] = update['cover'] html = requests.get(update['sLink']).text soup = bs(html, 'html.parser') desc = soup.find( "div", class_="col-lg-9 col-md-8 col-xs-12 text-muted").findAll( text=True, recursive=False) desc = ''.join(desc).strip() data[sid]['description'] = desc utils.dumpJson(data, globals.SERIES_FILE)
async def on_message(self, message): if message.author.id == self.user.id: return m = message.content.lower().replace(self.prefix, "", 1) args = [message, self] isAdmin = str(message.author.id) in utils.loadJson( globals.CONFIG_FILE)['ADMINS'] if isAdmin: print(message.author.name, message.content) if m.startswith("help"): await help(*args) elif m.startswith("sett"): await settings(*args) elif m.startswith("setde"): await setDelay(*args) elif m.startswith("setdis"): await setDiscordDelay(*args) elif m.startswith("addc"): await modChannel(*args, typ="add") elif m.startswith("removec"): await modChannel(*args, typ="remove") elif m.startswith("addu"): await modUser(*args, typ="add") elif m.startswith("removeu"): await modUser(*args, typ="remove") elif m.startswith("addr"): await modMention(*args, typ="add") elif m.startswith("remover"): await modMention(*args, typ="remove") elif m.startswith("ser"): await listSeries(*args) elif m.startswith("listr"): await listRoles(*args) # todo: hardcode if isAdmin or message.guild.id == 425423910759170049: if m.startswith("stat"): print(message.author.name, message.content) await scanMessages(self, last=True) await stats(*args) elif m.startswith("update"): await updateSheet(self, message)
async def setDiscordDelay(message, client): split = message.content.split() correctUsageString = getUseString("setdelay", client) if await checkMinArgs(message, 1, correctUsageString): return val = await checkInt(message, split[1], correctUsageString) if val is False: return if val < 0: return await sendError(message, "Delay interval must be positive", correctUsageString) config = utils.loadJson(globals.CONFIG_FILE) oldDelay = config["DISCORD_DELAY"] config["DISCORD_DELAY"] = val utils.dumpJson(config, globals.CONFIG_FILE) await message.channel.send( f"Updates are delayed `{val}` seconds (from `{oldDelay}`).")
def getSeriesData(sid): data = utils.loadJson(globals.SERIES_FILE) return data[str(sid)]
from utilss import utils, globals import requests, re, asyncio, json, copy, time from bs4 import BeautifulSoup as bs CONFIG = utils.loadJson(globals.CONFIG_FILE) def parseUpdateDiv(dv): ret = { "chLink": "N/A", "chNum": "-1", "chId": "-1", "sLink": "N/A", "sName": "N/A", "sId": "-1" } linkDiv = dv.find("div", class_="media media-comic-card") infoDiv = dv.find("div", class_="list-body") ret['chLink'] = linkDiv.find("a")['href'].strip() ret['chNum'] = linkDiv.find( "span", class_="badge badge-md text-uppercase bg-darker-overlay").text.strip() ret['chId'] = re.search(r"/(\d+)/(\d+)[/|$]*", ret['chLink']).group(2) ret['cover'] = "https://zeroscans.com/" + re.search( r"(/storage/.+)\);", linkDiv.find("a")['style']).group(1) ret['sLink'] = infoDiv.find("a")['href'].strip() ret['sName'] = infoDiv.find("a").text.strip()
def reload(): global CONFIG, CACHE, MENTIONS CONFIG = utils.loadJson(globals.CONFIG_FILE) CACHE = utils.loadJson(globals.CACHE_FILE, default=globals.CACHE_DEFAULT) MENTIONS = utils.loadJson(globals.MENTION_FILE)
async def stats(message, client): split = [x.lower() for x in message.content.split(maxsplit=1)] data = utils.loadJson(globals.PARSED_FILE) tallies = statUtils.getTallies(data) if len(split) == 1: gStats = statUtils.getGlobalStats(tallies, data, num=3) h1 = ['Type', '30 Days', 'All-time'] h2 = ['Type', 'Users (30 days)', 'Users (all)'] p1 = utils.pprint(gStats['all'], headers=h1) p2 = utils.pprint(gStats['users'], headers=h2) p1 = "\n".join(p1.split("\n")[:-1]) + "\n" + "".join( ["-"] * len(p1.split("\n")[0])) + "\n" + p1.split("\n")[-1] title = "@ All Users" s = f"""```py\n\n{title}\n\n{p1}\n\n{p2}\n```""" s = utils.breakMessage(s, codeblock=True, lang="py") for m in s: await message.channel.send(m) return else: spl = [x.lower() for x in split[1].split()] catMatch = [ x for x in tallies['all'] if x.lower() == spl[0] and spl[0] != 'all' ] if catMatch: catMatch = catMatch[0] flag = False if 'all' in spl: flag = True header = [f'User', '30 Days', 'All-time'] catStats = statUtils.getSingleCatStats(catMatch, tallies, data, allSort=flag) s = f'```py\n\n@ {catMatch.upper()} Stats\n\n{utils.pprint(catStats, headers=header)}\n```' if not flag: s += "\n(Include `all` at the end to sort by all-time counts.)" s = utils.breakMessage(s, codeblock=True, lang="py") for msg in s: await message.channel.send(msg) return else: catStats = statUtils.getCatStats(tallies) username = None try: username = int(split[1].replace("<@!", "").replace(">", "")) username = client.get_user(username).name except ValueError: for x in data['members']: if all( [y.lower() in data['members'][x].lower() for y in spl]): username = data['members'][x] break if not username: return await message.channel.send( f"Error. `{split[1]}` is not a known user.") uStats = statUtils.getUserStats(username, data, tallies) for x in uStats['stats']: cat = x[0].lower() rankRecent = 1 + catStats[cat]['recent'].index(int(x[1])) rankAll = 1 + catStats[cat]['all'].index(int(x[2])) x[1] = f"{x[1].ljust(3)}" + f"(rank-{rankRecent})".rjust(10) x[2] = f"{x[2].ljust(3)}" + f"(rank-{rankAll})".rjust(10) h1 = ['Type'.ljust(7), '30 Days', 'All-time'] h2 = ['Type'.ljust(7), 'Days Ago', 'Chap', 'Series'] p1 = utils.pprint(uStats['stats'], headers=h1) p1 = "\n".join(p1.split("\n")[:-1]) + "\n" + "".join( ["-"] * len(p1.split("\n")[0])) + "\n" + p1.split("\n")[-1] if uStats['recent']: p2 = "\n\n" + utils.pprint(uStats['recent'], headers=h2) else: p2 = "" title = f"@ {username}" s = f"""```py\n{title}\n\n{p1}{p2}\n```""" s = utils.breakMessage(s, codeblock=True, lang="py") for msg in s: await message.channel.send(msg) return
async def settings(message, client): config = utils.loadJson(globals.CONFIG_FILE) config['mentions'] = utils.loadJson(globals.MENTION_FILE) del config["DISCORD_KEY"] # Make channels readable cpy = [] for chid in config['UPDATE_CHANNELS']: uCh = client.get_channel(int(chid)) if int(uCh.guild.id) != int(message.guild.id): cpy.append(uCh.id) else: cpy.append(f"{uCh.name} ({uCh.id})") config['UPDATE_CHANNELS'] = cpy # Make roles readable sData = utils.loadJson(path=globals.SERIES_FILE) cpy = copy.deepcopy(config['mentions']) for sid in cpy: for mid in cpy[sid]: mid = int(mid) role = message.guild.get_role(mid) if role: name = role.name else: if sid in config['mentions']: config['mentions'][sid].remove(str(mid)) if sid in config[ 'mentions'] and not config['mentions'][sid]: del config['mentions'][sid] continue name = "unknown" if str(sid) not in sData and str(sid) != "-1": stitle = "unknown" print("WARNING:", sid, "is an unknown series.") elif str(sid) != "-1": stitle = sData[str(sid)]['title'] if sid != "-1": key = f"{stitle} ({sid})" else: key = "ALL (-1)" val = f"{name} ({mid})" if key not in config['mentions']: config['mentions'][key] = [] del config['mentions'][sid] config['mentions'][key].append(val) # Make admins readable users = [] for uid in config["ADMINS"]: user = client.get_user(int(uid)) if user: name = user.name else: name = "unknown" val = f"{name} ({uid})" users.append(val) config['ADMINS'] = users text = utils.breakMessage(json.dumps(config, indent=2), codeblock=True) for t in text: await message.channel.send(t)