async def live(lrrbot, conn, event, respond_to): """ Command: !live Post the currenly live fanstreamers. """ try: await extract_new_channels(lrrbot.loop) except urllib.error.HTTPError: pass streams = await twitch.get_streams_followed() if streams == []: return conn.privmsg(respond_to, "No fanstreamers currently live.") streams.sort(key=lambda e: e["channel"]["display_name"]) tag = "Currently live fanstreamers: " # Full message message = tag + ", ".join([ "%s (%s%s)%s%s" % ( data["channel"]["display_name"], data["channel"]["url"], space.SPACE, " is playing %s" % data["game"] if data.get("game") is not None else "", " (%s)" % data["channel"]["status"] if data["channel"].get("status") not in [None, ""] else "" ) for data in streams ]) if utils.check_length(message): return conn.privmsg(respond_to, message) # Shorter message message = tag + ", ".join([ "%s (%s%s)%s" % ( data["channel"]["display_name"], data["channel"]["url"], space.SPACE, " is playing %s" % data["game"] if data.get("game") is not None else "", ) for data in streams ]) if utils.check_length(message): return conn.privmsg(respond_to, message) # Shortest message message = tag + ", ".join([ "%s (%s%s)" % ( data["channel"]["display_name"], data["channel"]["url"], space.SPACE ) for data in streams ]) return conn.privmsg(respond_to, utils.trim_length(message))
async def live(lrrbot, conn, event, respond_to): """ Command: !live Post the currenly live fanstreamers. """ try: await extract_new_channels(lrrbot.loop) except urllib.error.HTTPError: pass streams = await twitch.get_streams_followed() if streams == []: return conn.privmsg(respond_to, "No fanstreamers currently live.") streams.sort(key=lambda e: e["channel"]["display_name"]) tag = "Currently live fanstreamers: " # Full message message = tag + ", ".join([ "%s (%s%s)%s%s" % (data["channel"]["display_name"], data["channel"]["url"], space.SPACE, " is playing %s" % data["game"] if data.get("game") is not None else "", " (%s)" % data["channel"]["status"] if data["channel"].get("status") not in [None, ""] else "") for data in streams ]) if utils.check_length(message): return conn.privmsg(respond_to, message) # Shorter message message = tag + ", ".join([ "%s (%s%s)%s" % ( data["channel"]["display_name"], data["channel"]["url"], space.SPACE, " is playing %s" % data["game"] if data.get("game") is not None else "", ) for data in streams ]) if utils.check_length(message): return conn.privmsg(respond_to, message) # Shortest message message = tag + ", ".join([ "%s (%s%s)" % (data["channel"]["display_name"], data["channel"]["url"], space.SPACE) for data in streams ]) return conn.privmsg(respond_to, utils.trim_length(message))
async def on_multi_gift_end(self, conn, channel, multi_gift): event = "twitch-subscription-mysterygift" eventtime = multi_gift.pop('eventtime') del multi_gift['remaining'] del self.multi_gifts[multi_gift['login']] names = [i['name'] for i in multi_gift['subscribers']] if len(names) == 0: # fallback just in case, I guess? names = "all %d recipients" % multi_gift['subcount'] elif len(names) == 1: names = names[0] elif len(names) == 2: names = " and ".join(names) else: names[-1] = "and " + names[-1] names = ", ".join(names) storm_count = common.storm.get_combined(self.lrrbot.engine, self.lrrbot.metadata) welcomemsg = "lrrSPOT Thanks for the gift%s, %s! Welcome to %s! (Today's storm count: %d)" % ( '' if multi_gift['subcount'] == 1 else 's', multi_gift['name'], names, storm_count) if not utils.check_length(welcomemsg): names = "all %d recipients" % multi_gift['subcount'] welcomemsg = "lrrSPOT Thanks for the gift%s, %s! Welcome to %s! (Today's storm count: %d)" % ( '' if multi_gift['subcount'] == 1 else 's', multi_gift['name'], names, storm_count) conn.privmsg(channel, welcomemsg) await common.rpc.eventserver.event(event, multi_gift, eventtime)
async def commands_submit(session): data = flask.json.loads(flask.request.values['data']) # Server-side sanity checking for command, response_data in data.items(): if not isinstance(command, str): raise ValueError("Key is not a string") if command == '': raise ValueError("Command is blank") if not isinstance(response_data, dict): raise ValueError("Response data is not a dict") if set(response_data.keys()) != set(('response', 'access')): raise ValueError("Incorrect keys for response_data") if not isinstance(response_data['response'], (tuple, list)): response_data['response'] = [response_data['response']] for response in response_data['response']: if not isinstance(response, str): raise ValueError("Value is not a string or list of strings") if response == '': raise ValueError("Response is blank") if not utils.check_length(response): raise ValueError("Response is too long") if len(response_data['response']) == 1: response_data['response'] = response_data['response'][0] if response_data['access'] not in ('any', 'sub', 'mod'): raise ValueError("Invalid access level") await common.rpc.bot.static.modify_commands(data) history.store('responses', session['user']['id'], data) return flask.json.jsonify(success='OK', csrf_token=server.app.csrf_token())
def get_next_event_text(calendar, after=None, include_current=None, tz=None, verbose=True): """ Build the actual human-readable response to the !next command. The tz parameter can override the timezone used to display the event times. This can be an actual timezone object, or a string timezone name. Defaults to moonbase time. """ if after is None: after = datetime.datetime.now(datetime.timezone.utc) if not tz: tz = config['timezone'] elif isinstance(tz, str): tz = tz.strip() try: tz = common.time.get_timezone(tz) except pytz.exceptions.UnknownTimeZoneError: return "Unknown timezone: %s" % tz events = get_next_event(calendar, after=after, include_current=include_current) if not events: return "There don't seem to be any upcoming scheduled streams" concise_strs = [] verbose_strs = [] for i, ev in enumerate(events): title = ev['title'] if ev['location'] is not None: title += " (%(location)s%(space)s)" % { "location": ev["location"], "space": space.SPACE, } concise_title = title if ev['description'] is not None: title += " (%(description)s)" % { "description": textwrap.shorten(process_description(ev['description']), 200), } # If several events are at the same time, just show the time once after all of them if i == len(events) - 1 or ev['start'] != events[i+1]['start']: if verbose: if ev['start'] < after: nice_duration = common.time.nice_duration(after - ev['start'], 1) + " ago" else: nice_duration = common.time.nice_duration(ev['start'] - after, 1) + " from now" start = ev['start'].astimezone(tz).strftime(DISPLAY_FORMAT) concise_strs.append("%s at %s (%s)" % (concise_title, start, nice_duration)) verbose_strs.append("%s at %s (%s)" % (title, start, nice_duration)) else: concise_strs.append("%s at %s" % (ev['title'], ev['start'].astimezone(tz).strftime(DISPLAY_FORMAT))) else: concise_strs.append(concise_title if verbose else ev['title']) verbose_strs.append(title) if verbose: for strs in [verbose_strs, concise_strs]: if calendar == CALENDAR_LRL: response = "Next scheduled stream: %s." % ", ".join(strs) elif calendar == CALENDAR_FAN: response = "Next scheduled fan stream: %s." % ", ".join(strs) if utils.check_length(response): break else: response = ", ".join(concise_strs) return utils.trim_length(response) # For safety