async def clips_vid(session, videoid): video = await get_video_data(videoid) clips = server.db.metadata.tables["clips"] with server.db.engine.begin() as conn: clip_data = conn.execute( sqlalchemy.select([ clips.c.data, clips.c.time, clips.c.rating ]).where(clips.c.vodid == videoid.lstrip('v')).where( clips.c.deleted == False).order_by( clips.c.time.asc())).fetchall() if video is None and clip_data: video = {'start': clip_data[0][1], 'title': 'Unknown video'} clip_data = [{ "slug": clip['slug'], "title": clip['title'], "curator": clip['curator']['display_name'], "starttime": time - video['start'], "endtime": time - video['start'] + datetime.timedelta(seconds=clip['duration']), "start": nice_duration(time - video['start'], 0), "duration": nice_duration(clip['duration'], 0), "embed_html": clip['embed_html'], "game": clip['game'], "thumbnail": clip['thumbnails']['small'], "rating": rating, "overlap": False, } for clip, time, rating in clip_data] lastend = None prevclip = None for clip in clip_data: if lastend is not None and clip['starttime'] <= lastend: clip['overlap'] = True if lastend is None or lastend < clip['endtime']: lastend = clip['endtime'] return flask.render_template("clips_vid.html", video=video, clips=clip_data, session=session)
def get_chat_log(self, user): attachments = [] now = datetime.datetime.now(config["timezone"]) log = self.lrrbot.metadata.tables["log"] with self.lrrbot.engine.begin() as conn: rows = conn.execute( sqlalchemy.select( [log.c.id, log.c.time, log.c.message]).where(log.c.source == user.lower()).where( log.c.time > now - datetime.timedelta(days=1)).limit(3).order_by( log.c.time.asc())).fetchall() logid = -1 for logid, timestamp, message in rows: timestamp = timestamp.astimezone(config["timezone"]) attachments.append({ 'text': slack.escape("%s (%s ago): %s" % (timestamp.strftime("%H:%M"), time.nice_duration(now - timestamp), message)) }) return logid, attachments
def on_message(self, sender, message): action = message['data']['moderation_action'] args = message['data']['args'] mod = message['data']['created_by'] if action == 'timeout': user = args[0] length = int(args[1]) reason = args[2] if len(args) >= 3 else None logid, attachments = self.get_chat_log(user) same_user = (self.last_ban == (user.lower(), logid)) if same_user: attachments = [] self.last_ban = (user.lower(), logid) text = "%s was%s timed out for %s by %s." % ( slack.escape(user), " also" if same_user else "", slack.escape(time.nice_duration(length, 0)), slack.escape(mod)) if reason is not None: text += " Reason: %s" % slack.escape(reason) elif action == 'ban': user = args[0] reason = args[1] if len(args) >= 2 else None logid, attachments = self.get_chat_log(user) same_user = (self.last_ban == (user.lower(), logid)) if same_user: attachments = [] self.last_ban = (user.lower(), logid) text = "%s was%s banned by %s." % (slack.escape(user), " also" if same_user else "", slack.escape(mod)) if reason is not None: text += " Reason: %s" % slack.escape(reason) elif action == 'unban': user = args[0] attachments = [] self.last_ban = None text = "%s was unbanned by %s." % (slack.escape(user), slack.escape(mod)) elif action == 'untimeout': user = args[0] attachments = [] self.last_ban = None text = "%s was untimed-out by %s." % (slack.escape(user), slack.escape(mod)) else: log.info("Got unrecognised message: %r", message['data']) attachments = [] self.last_ban = None text = "%s did a %s: %s" % (slack.escape(mod), slack.escape(action), slack.escape(repr(args))) asyncio. async (slack.send_message(text, attachments=attachments), loop=self.loop).add_done_callback( utils.check_exception)
def uptime_msg(self): stream_info = twitch.get_info() if stream_info and stream_info.get("stream_created_at"): start = dateutil.parser.parse(stream_info["stream_created_at"]) now = datetime.datetime.now(datetime.timezone.utc) return "The stream has been live for %s." % time.nice_duration( now - start, 0) elif stream_info and stream_info.get('live'): return "Twitch won't tell me when the stream went live." else: return "The stream is not live."
def on_message(self, sender, message): log.info("Got message: %r", message['data']) action = message['data']['moderation_action'] args = message['data']['args'] mod = message['data']['created_by'] if action == 'timeout': user = args[0] action = "Timeout: %s" % ctime.nice_duration(int(args[1])) reason = args[2] if len(args) >= 3 else '' last = self.last_chat.get(user.lower(), [''])[0] elif action == 'ban': user = args[0] action = "Ban" reason = args[1] if len(args) >= 2 else '' last = self.last_chat.get(user.lower(), [''])[0] elif action == 'unban': user = args[0] action = "Unban" reason = '' last = '' elif action == 'untimeout': user = args[0] action = "Untimeout" reason = '' last = '' elif action == 'delete': user = args[0] action = "Delete message" reason = '' last = args[1] else: user = '' reason = repr(args) last = '' now = datetime.datetime.now(config["timezone"]) data = [ ("Timestamp", now.strftime("%Y-%m-%d %H:%M:%S")), ("Timestamp (hours bussed)", self.nice_time(now - DESERTBUS_START)), ("Offender's Username", user), ("Moderator", mod), ("Enforcement option/length", action), ("What was the cause of the enforcement action?", reason), ("Last Line", last), ] log.debug("Add row: %r", data) asyncio.ensure_future( gdata.add_rows_to_spreadsheet(SPREADSHEET, [data]), loop=self.loop).add_done_callback(utils.check_exception)
async def clips_vid(session, videoid): video = await get_video_data(videoid) clips = server.db.metadata.tables["clips"] with server.db.engine.begin() as conn: clip_data = conn.execute( sqlalchemy.select([clips.c.data, clips.c.time, clips.c.rating]) .where(clips.c.vodid == videoid.lstrip('v')) .where(clips.c.deleted == False) .order_by(clips.c.time.asc())).fetchall() if video is None and clip_data: video = {'start': clip_data[0][1], 'title': 'Unknown video'} clip_data = [ { "slug": clip['slug'], "title": clip['title'], "curator": clip['curator']['display_name'], "starttime": time - video['start'], "endtime": time - video['start'] + datetime.timedelta(seconds=clip['duration']), "start": nice_duration(time - video['start'], 0), "duration": nice_duration(clip['duration'], 0), "embed_html": clip['embed_html'], "game": clip['game'], "thumbnail": clip['thumbnails']['small'], "rating": rating, "overlap": False, } for clip, time, rating in clip_data ] lastend = None prevclip = None for clip in clip_data: if lastend is not None and clip['starttime'] <= lastend: clip['overlap'] = True if lastend is None or lastend < clip['endtime']: lastend = clip['endtime'] return flask.render_template("clips_vid.html", video=video, clips=clip_data, session=session)
def on_message(self, sender, message): log.info("Got message: %r", message['data']) action = message['data']['moderation_action'] args = message['data']['args'] mod = message['data']['created_by'] if action == 'timeout': user = args[0] action = "Timeout: %s" % ctime.nice_duration(int(args[1])) reason = args[2] if len(args) >= 3 else '' last = self.last_chat.get(user.lower(), [''])[0] elif action == 'ban': user = args[0] action = "Ban" reason = args[1] if len(args) >= 2 else '' last = self.last_chat.get(user.lower(), [''])[0] elif action == 'unban': user = args[0] action = "Unban" reason = '' last = '' elif action == 'untimeout': user = args[0] action = "Untimeout" reason = '' last = '' else: user = '' reason = repr(args) last = '' now = datetime.datetime.now(config["timezone"]) data = [ ("Timestamp", now.strftime("%Y-%m-%d %H:%M:%S")), ("Timestamp (hours bussed)", self.nice_time(now - DESERTBUS_START)), ("Offender's Username", user), ("Moderator", mod), ("Enforcement option/length", action), ("What was the cause of the enforcement action?", reason), ("Last Line", last), ] log.debug("Add row: %r", data) asyncio.ensure_future(gdata.add_rows_to_spreadsheet(SPREADSHEET, [data]), loop=self.loop).add_done_callback(utils.check_exception)
def get_chat_log(self, user): attachments = [] now = datetime.datetime.now(config["timezone"]) log = self.lrrbot.metadata.tables["log"] with self.lrrbot.engine.begin() as conn: rows = conn.execute(sqlalchemy.select([log.c.id, log.c.time, log.c.message]) .where(log.c.source == user.lower()) .where(log.c.time > now - datetime.timedelta(days=1)) .limit(3) .order_by(log.c.time.desc())).fetchall() logid = -1 for logid, timestamp, message in rows[::-1]: timestamp = timestamp.astimezone(config["timezone"]) attachments.append({ 'text': slack.escape("%s (%s ago): %s" % (timestamp.strftime("%H:%M"), time.nice_duration(now - timestamp), message)) }) return logid, attachments
def timestamp(ts, cls='timestamp', tag='span'): """ Outputs a given time (either unix timestamp or datetime instance) as a human-readable time and includes tags so that common.js will convert the time on page-load to the user's timezone and preferred date/time format. """ if isinstance(ts, (int, float)): ts = datetime.datetime.fromtimestamp(ts, tz=pytz.utc) elif ts.tzinfo is None: ts = ts.replace(tzinfo=datetime.timezone.utc) ts = ts.astimezone(config.config['timezone']) if cls == 'timestamp-duration': text = nice_duration(datetime.datetime.now(config.config['timezone']) - ts, 2) else: text = ts.strftime("%A, %d %B, %Y %H:%M:%S %Z") return flask.Markup("<{tag} class=\"{cls}\" data-timestamp=\"{timestamp}\">{text}</{tag}>".format( text=text, timestamp=ts.timestamp(), tag=tag, cls=cls, ))
def timestamp(ts, cls='timestamp', tag='span'): """ Outputs a given time (either unix timestamp or datetime instance) as a human-readable time and includes tags so that common.js will convert the time on page-load to the user's timezone and preferred date/time format. """ if isinstance(ts, (int, float)): ts = datetime.datetime.fromtimestamp(ts, tz=pytz.utc) elif ts.tzinfo is None: ts = ts.replace(tzinfo=datetime.timezone.utc) ts = ts.astimezone(config.config['timezone']) if cls == 'timestamp-duration': text = nice_duration( datetime.datetime.now(config.config['timezone']) - ts, 2) else: text = ts.strftime("%A, %d %B, %Y %H:%M:%S %Z") return flask.Markup( "<{tag} class=\"{cls}\" data-timestamp=\"{timestamp}\">{text}</{tag}>". format( text=text, timestamp=ts.timestamp(), tag=tag, cls=cls, ))
async def update_topic(self): channel = self.eris.get_server( config['discord_serverid']).default_channel header = await rpc.bot.get_header_info() messages = [] if header['is_live']: shows = self.metadata.tables["shows"] games = self.metadata.tables["games"] game_per_show_data = self.metadata.tables["game_per_show_data"] with self.engine.begin() as conn: if header.get('current_game'): game = conn.execute( sqlalchemy.select([ sqlalchemy.func.coalesce( game_per_show_data.c.display_name, games.c.name) ]).select_from( games.outerjoin( game_per_show_data, (game_per_show_data.c.game_id == games.c.id) & (game_per_show_data.c.show_id == header['current_show']['id']))).where( games.c.id == header['current_game'] ['id'])).first() if game is not None: game, = game else: game = None if header.get('current_show'): show = conn.execute( sqlalchemy.select([shows.c.name]).where( shows.c.id == header['current_show']['id']).where( shows.c.string_id != "")).first() if show is not None: show, = show else: show = None if game and show: messages.append("Now live: %s on %s." % (game, show)) elif game: messages.append("Now live: %s." % game) elif show: messages.append("Now live: %s." % show) messages.append(self.uptime_msg()) else: now = datetime.datetime.now(datetime.timezone.utc) events = googlecalendar.get_next_event(googlecalendar.CALENDAR_LRL, after=now) for event in events: if event['start'] > now: message = "In %s: " % time.nice_duration( event['start'] - now, 1) else: message = "%s ago: " % time.nice_duration( now - event['start'], 1) message += event['title'] if event['description'] is not None: message += " (%s)" % (textwrap.shorten( googlecalendar.process_description( event['description']), 200)) message += " at " + event['start'].astimezone( config['timezone']).strftime(googlecalendar.DISPLAY_FORMAT) message += "." messages.append(message) if header.get('advice'): messages.append(header['advice']) await self.eris.edit_channel(channel, topic=textwrap.shorten( " ".join(messages), MAX_TOPIC_LENGTH))
def on_message(self, sender, message): log.info("Got message: %r", message['data']) action = message['data']['moderation_action'] args = message['data']['args'] mod = message['data']['created_by'] if action in ('timeout', 'ban'): user = args[0] logid, attachments = self.get_chat_log(user) same_user = (self.last_ban == (user.lower(), logid)) if same_user: attachments = [] self.last_ban = (user.lower(), logid) else: attachments = [] self.last_ban = None if action == 'timeout': user = args[0] length = time.nice_duration(int(args[1]), 0) if args[1] != '' else '???' reason = args[2] if len(args) >= 3 else None text = "%s was%s timed out for %s by %s." % (slack.escape(user), " also" if same_user else "", slack.escape(length), slack.escape(mod)) if reason is not None: text += " Reason: %s" % slack.escape(reason) elif action == 'ban': user = args[0] reason = args[1] if len(args) >= 2 else None text = "%s was%s banned by %s." % (slack.escape(user), " also" if same_user else "", slack.escape(mod)) if reason is not None: text += " Reason: %s" % slack.escape(reason) elif action == 'unban': user = args[0] text = "%s was unbanned by %s." % (slack.escape(user), slack.escape(mod)) elif action == 'untimeout': user = args[0] text = "%s was untimed-out by %s." % (slack.escape(user), slack.escape(mod)) elif action in ('twitchbot_rejected', 'automod_rejected'): msg_id = message['data']['msg_id'] user = args[0] message = args[1] if not mod: mod = "the strange voices that lie beneath" text = "%s's message was rejected by %s." % (slack.escape(user), slack.escape(mod)) attachments.append({ 'text': slack.escape(message) }) # Approve the message because we're unable to turn off Automod. if config['autoautomod']: asyncio.ensure_future(twitch.twitchbot_approve(msg_id), loop=self.loop).add_done_callback(utils.check_exception) elif action in ('approved_twitchbot_message', 'approved_automod_message'): user = args[0] text = "%s approved %s's message." % (slack.escape(mod), slack.escape(user)) elif action in ('denied_twitchbot_message', 'denied_automod_message'): user = args[0] text = "%s denied %s's message." % (slack.escape(mod), slack.escape(user)) elif action == 'slow': duration = int(args[0]) text = "%s has enabled slow mode: delay %s." % (slack.escape(mod), slack.escape(time.nice_duration(duration, 0))) elif action == 'slowoff': text = "%s has disabled slow mode." % (slack.escape(mod), ) elif action == 'followers': duration = int(args[0]) text = "%s has enabled follower-only mode: minimum age %s." % (slack.escape(mod), slack.escape(time.nice_duration(duration, 0))) elif action == 'followersoff': text = "%s has disabled follower-only mode." % (slack.escape(mod), ) elif action == 'host': target = args[0] text = "%s has enabled hosting of %s." % (slack.escape(mod), slack.escape(target)) elif action == 'unhost': text = "%s has disabled hosting." % (slack.escape(mod), ) elif action == 'mod': target = args[0] text = "%s has made %s a moderator." % (slack.escape(mod), slack.escape(target)) elif action == 'clear': text = "%s cleared the chat." % (slack.escape(mod), ) elif action == 'recent_cheer_dismissal': cheerer = args[0] text = "%s has cleared %s's recent-cheer notice." % (slack.escape(mod), slack.escape(cheerer)) else: text = "%s did a %s: %s" % (slack.escape(mod), slack.escape(action), slack.escape(repr(args))) asyncio.ensure_future(slack.send_message(text, attachments=attachments), loop=self.loop).add_done_callback(utils.check_exception)
def on_message(self, sender, message): log.info("Got message: %r", message['data']) action = message['data']['moderation_action'] args = message['data']['args'] mod = message['data']['created_by'] if action in ('timeout', 'ban'): user = args[0] logid, attachments = self.get_chat_log(user) same_user = (self.last_ban == (user.lower(), logid)) if same_user: attachments = [] self.last_ban = (user.lower(), logid) else: attachments = [] self.last_ban = None if action == 'timeout': user = args[0] length = int(args[1]) reason = args[2] if len(args) >= 3 else None text = "%s was%s timed out for %s by %s." % ( slack.escape(user), " also" if same_user else "", slack.escape(time.nice_duration(length, 0)), slack.escape(mod)) if reason is not None: text += " Reason: %s" % slack.escape(reason) elif action == 'ban': user = args[0] reason = args[1] if len(args) >= 2 else None text = "%s was%s banned by %s." % (slack.escape(user), " also" if same_user else "", slack.escape(mod)) if reason is not None: text += " Reason: %s" % slack.escape(reason) elif action == 'unban': user = args[0] text = "%s was unbanned by %s." % (slack.escape(user), slack.escape(mod)) elif action == 'untimeout': user = args[0] text = "%s was untimed-out by %s." % (slack.escape(user), slack.escape(mod)) elif action == 'twitchbot_rejected': user = args[0] message = args[1] # mod is always "twitchbot", but still... text = "%s's message was rejected by %s." % (slack.escape(user), slack.escape(mod)) attachments.append({'text': slack.escape(message)}) elif action == 'approved_twitchbot_message': user = args[0] text = "%s approved %s's message." % (slack.escape(mod), slack.escape(user)) elif action == 'denied_twitchbot_message': user = args[0] text = "%s denied %s's message." % (slack.escape(mod), slack.escape(user)) elif action == 'slow': duration = int(args[0]) text = "%s has enabled slow mode: delay %s." % (slack.escape( mod), slack.escape(time.nice_duration(duration, 0))) elif action == 'slowoff': text = "%s has disabled slow mode." % (slack.escape(mod), ) elif action == 'followers': duration = int(args[0]) text = "%s has enabled follower-only mode: minimum age %s." % ( slack.escape(mod), slack.escape(time.nice_duration( duration, 0))) elif action == 'followersoff': text = "%s has disabled follower-only mode." % ( slack.escape(mod), ) elif action == 'host': target = args[0] text = "%s has enabled hosting of %s." % (slack.escape(mod), slack.escape(target)) elif action == 'unhost': text = "%s has disabled hosting." % (slack.escape(mod), ) elif action == 'mod': target = args[0] text = "%s has made %s a moderator." % (slack.escape(mod), slack.escape(target)) elif action == 'clear': text = "%s cleared the chat." % (slack.escape(mod), ) elif action == 'recent_cheer_dismissal': cheerer = args[0] text = "%s has cleared %s's recent-cheer notice." % ( slack.escape(mod), slack.escape(cheerer)) else: text = "%s did a %s: %s" % (slack.escape(mod), slack.escape(action), slack.escape(repr(args))) asyncio. async (slack.send_message(text, attachments=attachments), loop=self.loop).add_done_callback( utils.check_exception)
def on_message(self, sender, message): log.info("Got message: %r", message['data']) action = message['data']['moderation_action'] args = message['data']['args'] mod = message['data']['created_by'] if action in ('timeout', 'ban'): user = args[0] logid, attachments = self.get_chat_log(user) same_user = (self.last_ban == (user.lower(), logid)) if same_user: attachments = [] self.last_ban = (user.lower(), logid) else: attachments = [] self.last_ban = None if action == 'timeout': user = args[0] length = time.nice_duration(int(args[1]), 0) if args[1] != '' else '???' reason = args[2] if len(args) >= 3 else None text = "%s was%s timed out for %s by %s." % (slack.escape(user), " also" if same_user else "", slack.escape(length), slack.escape(mod)) if reason is not None: text += " Reason: %s" % slack.escape(reason) elif action == 'ban': user = args[0] reason = args[1] if len(args) >= 2 else None text = "%s was%s banned by %s." % (slack.escape(user), " also" if same_user else "", slack.escape(mod)) if reason is not None: text += " Reason: %s" % slack.escape(reason) elif action == 'unban': user = args[0] text = "%s was unbanned by %s." % (slack.escape(user), slack.escape(mod)) elif action == 'untimeout': user = args[0] text = "%s was untimed-out by %s." % (slack.escape(user), slack.escape(mod)) elif action == 'delete': user = args[0] message = args[1] text = "%s had a message deleted by %s." % (slack.escape(user), slack.escape(mod)) attachments.append({ 'text': slack.escape(message) }) elif action in ('twitchbot_rejected', 'automod_rejected'): msg_id = message['data']['msg_id'] user = args[0] message = args[1] if not mod: mod = "the strange voices that lie beneath" text = "%s's message was rejected by %s." % (slack.escape(user), slack.escape(mod)) attachments.append({ 'text': slack.escape(message) }) # Approve the message because we're unable to turn off Automod. if config['autoautomod']: asyncio.ensure_future(twitch.twitchbot_approve(msg_id), loop=self.loop).add_done_callback(utils.check_exception) elif action in ('approved_twitchbot_message', 'approved_automod_message'): user = args[0] text = "%s approved %s's message." % (slack.escape(mod), slack.escape(user)) elif action in ('denied_twitchbot_message', 'denied_automod_message'): user = args[0] text = "%s denied %s's message." % (slack.escape(mod), slack.escape(user)) elif action == 'slow': duration = int(args[0]) text = "%s has enabled slow mode: delay %s." % (slack.escape(mod), slack.escape(time.nice_duration(duration, 0))) elif action == 'slowoff': text = "%s has disabled slow mode." % (slack.escape(mod), ) elif action == 'followers': duration = int(args[0]) text = "%s has enabled follower-only mode: minimum age %s." % (slack.escape(mod), slack.escape(time.nice_duration(duration, 0))) elif action == 'followersoff': text = "%s has disabled follower-only mode." % (slack.escape(mod), ) elif action == 'host': target = args[0] text = "%s has enabled hosting of %s." % (slack.escape(mod), slack.escape(target)) elif action == 'unhost': text = "%s has disabled hosting." % (slack.escape(mod), ) elif action == 'mod': target = args[0] text = "%s has made %s a moderator." % (slack.escape(mod), slack.escape(target)) elif action == 'clear': text = "%s cleared the chat." % (slack.escape(mod), ) elif action == 'recent_cheer_dismissal': cheerer = args[0] text = "%s has cleared %s's recent-cheer notice." % (slack.escape(mod), slack.escape(cheerer)) else: text = "%s did a %s: %s" % (slack.escape(mod), slack.escape(action), slack.escape(repr(args))) asyncio.ensure_future(slack.send_message(text, attachments=attachments), loop=self.loop).add_done_callback(utils.check_exception)