def getStreamerInfo(self, streamername, serverChannelString=None): """ Get info on the provided streamer, if they're live :param streamername: The name of the streamer to get info on :param serverChannelString: The server-channel pair where the request originated from. Needed to determine whether we need to use a nickname :return: A tuple, first entry is a success boolean, second one is the result string with either the error message or the currently live streamers """ # Check if we happen to have the streamer's ID on file, saves retrieving it if streamername in self.watchedStreamersData: streamerId = self.watchedStreamersData[streamername]['clientId'] displayName = self.getStreamerNickname(streamername, serverChannelString) else: isSuccess, result = self.retrieveChannelInfo(streamername) if not isSuccess: return (False, result) streamerId = result['id'] displayName = result['display_name'] # Get stream info isSuccess, result = self.retrieveStreamDataForIds([streamerId], True) if not isSuccess: return (False, result) if len(result) == 0: return ( True, u"{0} doesn't appear to be streaming at the moment. Maybe they've got some old streams you can watch though, here: https://twitch.tv/{0}/videos/all" .format(streamername)) #Streamer is live, return info on them url = "https://twitch.tv/" + streamername return (True, StringUtil.removeNewlines(u"{}: {} [{}] ({})".format( displayName, result[streamerId]['title'], result[streamerId]['game_name'], url)))
def getCurrentlyLiveStreamers(self, serverChannelString): """ Get a string with all the currently live streamers that the provided channel follows. If there's only a few streamers live, more expansive info is shown per streamer :param serverChannelString: The server name followed by the channel name, separated by a space :return: A tuple, first entry is a success boolean, second one is the result string with either the error message or the currently live streamers """ streamerIdsToCheck = {} for streamername, streamerdata in self.watchedStreamersData.iteritems( ): if serverChannelString in streamerdata[ 'followChannels'] or serverChannelString in streamerdata[ 'reportChannels']: streamerIdsToCheck[streamerdata['clientId']] = streamername isSuccess, result = self.retrieveStreamDataForIds(streamerIdsToCheck) if not isSuccess: self.logError( u"[TwitchWatch] An error occurred during a manual live check. " + result) return ( False, "I'm sorry, I wasn't able to retrieve data from Twitch. It's probably entirely their fault, not mine though. Try again in a little while" ) if len(result) == 0: return ( True, "Nobody's live, it seems. Time for videogames and/or random streams, I guess!" ) #One or more streamers are live, show info on each of them reportStrings = [] shouldUseShortReportString = len( result ) >= 4 # Use shorter report strings if there's 4 or more people live for streamerId, streamerdata in result.iteritems(): streamername = streamerIdsToCheck[streamerId] displayname = streamername if self.doesStreamerHaveNickname(streamername, serverChannelString): displayname = self.watchedStreamersData[streamername][ 'nicknames'][serverChannelString] url = u"https://twitch.tv/{}".format(streamername) if shouldUseShortReportString: reportStrings.append(u"{} ({})".format(displayname, url)) else: reportStrings.append( StringUtil.removeNewlines(u"{}: {} [{}] ({})".format( IrcFormattingUtil.makeTextBold(displayname), streamerdata['title'], streamerdata['game_name'], url))) return (True, StringUtil.joinWithSeparator(reportStrings))
def executeScheduledFunction(self): #Go through all our stored streamers, and see if we need to report online status somewhere # If we do, check if they're actually online streamerIdsToCheck = { } #Store as a clientId-to-streamername dict to facilitate reverse lookup in self.streamerdata later for streamername, data in self.watchedStreamersData.iteritems(): if len(data['reportChannels']) > 0: #Ok, store that we need to check whether this stream is online or not # Because doing the check one time for all streamers at once is far more efficient streamerIdsToCheck[data['clientId']] = streamername if len(streamerIdsToCheck) == 0: #Nothing to do! Let's stop now return isSuccess, liveStreamDataById = self.retrieveStreamDataForIds( streamerIdsToCheck.keys()) if not isSuccess: self.logError( u"[TwitchWatch] An error occurred during the scheduled live check. " + liveStreamDataById) #Still update the last checked time, so we do get results when the connection works again self.lastLiveCheckTime = time.time() return #If the last time we checked for updates was (far) longer ago than the time between update checks, we've probably been offline for a while # Any data we retrieve could be old, so don't report it, but just log who's streaming and who isn't if self.lastLiveCheckTime: shouldReport = time.time( ) - self.lastLiveCheckTime <= self.scheduledFunctionTime * 6 else: shouldReport = True if not shouldReport: self.logDebug( "[TwitchWatcher] Skipping reporting on live streams, since our last check was {} seconds ago, which is too long" .format(time.time() - self.lastLiveCheckTime)) self.lastLiveCheckTime = time.time() channelMessages = { } #key is string with server-channel, separated by a space. Value is a list of tuples with data on streams that are live #Go through all the required IDs and check if the API returned info info on that stream. If so, store that data for display later for streamerId, streamername in streamerIdsToCheck.iteritems(): #Check if the requested ID exists in the API reply. If it didn't, the stream is offline if streamerId not in liveStreamDataById: self.watchedStreamersData[streamername][ 'hasBeenReportedLive'] = False #If we have already reported the stream is live, skip over it now. Otherwise report that it has gone live elif not self.watchedStreamersData[streamername][ 'hasBeenReportedLive']: self.watchedStreamersData[streamername][ 'hasBeenReportedLive'] = True if shouldReport: #Stream is live, store some info to display later for serverChannelString in self.watchedStreamersData[ streamername]['reportChannels']: #Add this stream's data to the channel's reporting output if serverChannelString not in channelMessages: channelMessages[serverChannelString] = [] channelMessages[serverChannelString].append({ 'streamername': streamername, 'gameName': liveStreamDataById[streamerId]['game_name'], 'title': liveStreamDataById[streamerId]['title'] }) #Save live status of all the streams self.saveWatchedStreamerData() if shouldReport: #And now report each online stream to each channel that wants it for serverChannelString, streamdatalist in channelMessages.iteritems( ): server, channel = serverChannelString.rsplit(" ", 1) #First check if we're even in the server and channel we need to report to if server not in GlobalStore.bothandler.bots or channel not in GlobalStore.bothandler.bots[ server].channelsUserList: continue reportStrings = [] #If we have a lot of live streamers to report, keep it short. Otherwise, we can be a bit more verbose useShortReportString = len(streamdatalist) >= 4 for streamdata in streamdatalist: displayname = self.getStreamerNickname( streamdata['streamername'], serverChannelString) url = "https://twitch.tv/" + streamdata['streamername'] #A lot of live streamers to report, keep it short. Just the streamer name and the URL if useShortReportString: reportStrings.append(u"{} ({})".format( displayname, url)) # Only a few streamers live, we can be a bit more verbose else: reportStrings.append( StringUtil.removeNewlines( u"{}: {} [{}] ({})".format( IrcFormattingUtil.makeTextBold( displayname), streamdata['title'], streamdata['gameName'], url))) #Now make the bot say it GlobalStore.bothandler.bots[server].sendMessage( channel.encode("utf8"), u"Streamer{} went live: ".format( u's' if len(reportStrings) > 1 else u'') + StringUtil.joinWithSeparator(reportStrings), "say")