def start(bot): target_scope = [ AuthScope.ANALYTICS_READ_GAMES, AuthScope.BITS_READ, AuthScope.CHANNEL_EDIT_COMMERCIAL, AuthScope.CHANNEL_MANAGE_BROADCAST, AuthScope.CHANNEL_MANAGE_POLLS, AuthScope.CHANNEL_MANAGE_PREDICTIONS, AuthScope.CHANNEL_MANAGE_REDEMPTIONS, AuthScope.CHANNEL_MODERATE, AuthScope.CHANNEL_READ_HYPE_TRAIN, AuthScope.CHANNEL_READ_POLLS, AuthScope.CHANNEL_READ_PREDICTIONS, AuthScope.CHANNEL_READ_REDEMPTIONS, AuthScope.CHANNEL_READ_SUBSCRIPTIONS, AuthScope.CHANNEL_SUBSCRIPTIONS, AuthScope.CHAT_EDIT, AuthScope.CHAT_READ, AuthScope.CLIPS_EDIT, AuthScope.MODERATION_READ, AuthScope.USER_EDIT_BROADCAST, AuthScope.USER_MANAGE_BLOCKED_USERS, AuthScope.USER_READ_BLOCKED_USERS, AuthScope.USER_READ_BROADCAST, AuthScope.USER_READ_FOLLOWS, AuthScope.USER_READ_SUBSCRIPTIONS ] twitch = Twitch(config['client_id'], config['client_secret']) twitch.authenticate_app([]) twitch.set_user_authentication(config['twitch_token'], target_scope, config['refresh_token']) def callback_bits(uuid: UUID, data: dict): print(f"Got callback for UUID {str(uuid)}") print(data) pubsub.bits(bot, data['data']) def callback_subscriptions(uuid: UUID, data: dict): print(f"Got callback for UUID {str(uuid)}") print(data) pubsub.subscription(bot, data['data']) def callback_points(uuid: UUID, data: dict): print(f"Got callback for UUID {str(uuid)}") print(data) pubsub.points(bot, data['data']) user_id = twitch.get_users(logins=['will_am_i_'])['data'][0]['id'] pubsubs = PubSub(twitch) pubsubs.start() bits_uuid = pubsubs.listen_bits(user_id, callback_bits) subscriptions_uuid = pubsubs.listen_channel_subscriptions( user_id, callback_subscriptions) points_uuid = pubsubs.listen_channel_points(user_id, callback_points) #pubsubs.stop()
def setup_platform( hass: HomeAssistant, config: ConfigType, add_entities: AddEntitiesCallback, discovery_info: DiscoveryInfoType | None = None, ) -> None: """Set up the Twitch platform.""" channels = config[CONF_CHANNELS] client_id = config[CONF_CLIENT_ID] client_secret = config[CONF_CLIENT_SECRET] oauth_token = config.get(CONF_TOKEN) try: client = Twitch( app_id=client_id, app_secret=client_secret, target_app_auth_scope=OAUTH_SCOPES, ) client.auto_refresh_auth = False except TwitchAuthorizationException: _LOGGER.error("Invalid client ID or client secret") return if oauth_token: try: client.set_user_authentication(token=oauth_token, scope=OAUTH_SCOPES, validate=True) except MissingScopeException: _LOGGER.error("OAuth token is missing required scope") return except InvalidTokenException: _LOGGER.error("OAuth token is invalid") return channels = client.get_users(logins=channels) add_entities( [TwitchSensor(channel, client) for channel in channels["data"]], True, )
class TwitchNotifier(commands.Cog): def __init__(self, bot): self.bot: 'PixlBot' = bot self.config = bot.config['TwitchNotifier'] self.backend = FileBackend('db') self.backend.autocommit = True self.bot.logger.info("Twitch notifier plugin ready") self.uuids = [] self.online_uuids = [] self.sslcontext = ssl.SSLContext() self.sslcontext.load_cert_chain(self.config['cert_path'], self.config['key_path']) self._twitch_init_() def _twitch_init_(self): self.bot.logger.info("Registering with Twitch...") self.twitch = Twitch(self.config['id'], self.config['secret']) self.twitch.authenticate_app([]) self.bot.logger.info( f"Registering webhook endpoint {self.config['myurl']} ...") self.hook = TwitchWebHook(self.config['myurl'], self.config['id'], self.config['port'], ssl_context=self.sslcontext) self.hook.authenticate(self.twitch) self.bot.logger.info("Clearing all hook subscriptions...") self.hook.unsubscribe_all(self.twitch) # Clear all subs on startup self.hook.start() self._register_all() def _login_to_id(self, name: str) -> Optional[str]: """Returns the twitch ID for a given login name, or None if the name couldn't be resolved.""" try: res: dict = self.twitch.get_users(logins=[name]) except TwitchBackendException as e: self.bot.logger.error(f"Backend error fetching user! {e}") return None if len(res) == 0: return None else: return res['data'][0]['id'] def _register_all(self): """Attempts to register stream_changed callbacks for all configured users.""" self.bot.logger.info("Registering callbacks for all watched users..") users = self.backend.filter(TwitchWatchedUser, {'twitch_name': { "$exists": True }}) if not users: self.bot.logger.info("No users to watch. No callbacks registered.") else: for u in users: self.bot.logger.info(f"Registering: {u['twitch_name']}") success, uuid = self.hook.subscribe_stream_changed( u['twitch_id'], self._cb_stream_changed) if success and uuid: self.uuids.append(uuid) self.bot.logger.info( f"{success}: registered subscription UUID: {uuid}") else: self.bot.logger.error( f"{success}: failed registering subscription: {uuid}") def _cb_stream_changed(self, uuid, data): """Callback for Twitch webhooks, fires on stream change event""" self.bot.logger.debug(f"Callback data for {uuid}: {data}") if data["type"] == "offline": if uuid in self.online_uuids: self.online_uuids.remove( uuid ) # Stupid twitch sending the same damn webhook multiple times... return else: self.bot.logger.debug( f"Ignoring duplicate offline callback for {uuid}") return elif data["type"] == "live": if uuid in self.online_uuids: self.bot.logger.debug( f"Ignoring duplicate live callback for {uuid}") return else: self.online_uuids.append(uuid) else: self.bot.logger.error( f"Got a callback type we can't handle: {data['type']}") return if uuid not in self.uuids: self.bot.logger.error( f"Got a callback for a UUID we're not tracking: {uuid}, my UUIDs: {self.uuids}" ) return try: item = self.backend.get(TwitchWatchedUser, {"twitch_id": data["user_id"]}) except TwitchWatchedUser.DoesNotExist: self.bot.logger.error( f"Got a callback for a USER we're not tracking: {data['user_id']} -> {data['user_name']}" ) return channel: discord.TextChannel = self.bot.get_channel( item['notify_channel']) width = 640 height = 360 url = data['thumbnail_url'].format(width=width, height=height) tu = self.twitch.get_users(data['user_id'])['data'][0] self.bot.logger.debug(tu) embed = discord.Embed( title=f"Now streaming {data['game_name']}", description=data['title'], color=discord.Color.green(), ) embed.set_image(url=url) embed.set_thumbnail(url=tu["profile_image_url"]) embed.set_author(name=item["twitch_name"], url=f"https://twitch.tv/{data['user_name']}") embed.add_field(name="Watch live at", value=f"https://twitch.tv/{data['user_name']}") self.bot.loop.create_task( channel. send( # This isn't an async function, so enqueue it manually embed=embed)) self.bot.logger.info( f"Successfully sent online notification for {data['user_id']}") @cog_ext.cog_subcommand( base="Twitchwatch", name="add_notification", description="Add a go live notification for Twitch", options=[twitch_name, notify_channel, notify_text], guild_ids=util.guilds) async def add_notification(self, ctx: SlashContext, twitch_name: str, notify_channel: discord.TextChannel, notify_text: str): twitch_id = self._login_to_id(twitch_name) try: self.backend.get(TwitchWatchedUser, {'twitch_name': twitch_name}) except TwitchWatchedUser.DoesNotExist: pass except TwitchWatchedUser.MultipleDocumentsReturned: self.bot.logger.error( "Multiple users returned - database inconsistent???") return if not twitch_id: await ctx.send(embed=mkembed( 'error', f"Unable to get the Twitch ID for the name {twitch_name}")) return await ctx.defer() # This bit can take a minute. success, uuid = self.hook.subscribe_stream_changed( twitch_id, self._cb_stream_changed) if success and uuid: self.uuids.append(uuid) self.bot.logger.info( f"{success}: registered subscription UUID: {uuid}") else: self.bot.logger.error( f"{success}: failed registering subscription: {uuid}") await ctx.send("Bluh, couldn't register the webhook with twitch :(" ) return item = TwitchWatchedUser({ 'twitch_name': twitch_name, 'twitch_id': twitch_id, 'discord_name': ctx.author.id, 'notify_channel': notify_channel.id, 'notify_text': notify_text, 'uuid': str(uuid) }) self.bot.logger.debug(f"DB object dump: {item.__dict__}") self.backend.save(item) await ctx.send(embed=mkembed("done", f"Notification added for {twitch_name}", channel=notify_channel.name)) @cog_ext.cog_subcommand( base="Twitchwatch", name="del_notification", description="Remove a go live notification for Twitch", options=[twitch_name], guild_ids=util.guilds) async def del_notification(self, ctx: SlashContext, twitch_name: str): try: item = self.backend.get(TwitchWatchedUser, {'twitch_name': twitch_name}) except TwitchWatchedUser.DoesNotExist: await ctx.send(embed=mkembed( "error", f"No notification exists for {twitch_name}")) return self.hook.unsubscribe(item['uuid']) self.bot.logger.info(f"Removing watch {item['uuid']}: {twitch_name}") self.backend.delete(item) if item['uuid'] in self.uuids: self.uuids.remove(item['uuid']) await ctx.send( embed=mkembed("done", f"Notification for {twitch_name} removed."))
class DiscordTwitchWebhook(): def __init__(self, twitch_appid, twitch_secret, callback_url): self.discord_username = "******" self.twitch = Twitch(twitch_appid, twitch_secret) self.callback_url = callback_url self.hook = TwitchWebHook(callback_url, twitch_appid, 8080) self.authenticated = False self.subscriptions = [] def authenticate(self): self.authenticated = False try: self.twitch.authenticate_app([]) self.hook.authenticate(self.twitch) except TwitchAuthorizationException: print("Twitch authentication failed") except RuntimeError: print("Webhook must be https") else: self.authenticated = True return self.authenticated def subscribe_user(self, user: DiscordTwitchCallback): if not self.authenticated: raise Exception #TODO handle more exceptions user_data = self.twitch.get_users(logins=[user.username]) user.data = user_data['data'][0] user.id = user.data['id'] if user not in self.subscriptions: ret, user.uuid = self.hook.subscribe_stream_changed( user.id, self.callback_stream_changed) if ret: self.subscriptions.append(user) else: print(f"Failed to subscribe to {user.username}") def unsubscribe_user(self, user: DiscordTwitchCallback): #TODO return def start(self): self.hook.start() def stop(self): self.hook.unsubscribe_all(self.twitch) self.hook.stop() def callback_stream_changed(self, uuid, twdata): print('Callback for UUID ' + str(uuid), twdata) user = next((user for user in self.subscriptions if user.uuid == uuid), None) if user == None: print("Callback failed") return if twdata['type'] == 'live': emb = self.create_embed(twdata) user.run_callback(emb) def create_embed(self, twdata): return Embed(title=f"{twdata['user_name']}", description=f"{twdata['user_name']} is streaming {twdata['game_name']}! Get in here!", color=6570404, url=f"https://twitch.tv/{twdata['user_name']}") \ .set_image(url=twdata['thumbnail_url'].format(width="1280", height="720"))
twitchSettings = json.load(f) # Need to read and update channel redemptions scopes = [ AuthScope.CHANNEL_READ_REDEMPTIONS, AuthScope.CHANNEL_MANAGE_REDEMPTIONS ] twitch = Twitch(twitchSettings["TwitchAppId"], app_secret=None, authenticate_app=False, target_app_auth_scope=scopes) auth = UserAuthenticator(twitch, scopes, force_verify=False) # this will open your default browser and prompt you with the twitch verification website token, refresh_token = auth.authenticate() # add User authentication twitch.set_user_authentication(token, scopes, refresh_token) user_id = twitch.get_users() def channel_points(uuid: UUID, data: dict) -> None: print('got callback for UUID ' + str(uuid)) pprint(data) # starting up PubSub pubsub = PubSub(twitch) pubsub.start() # you can either start listening before or after you started pubsub. uuid = pubsub.listen_channel_points(user_id, channel_points)
# auth = UserAuthenticator( # twitch, auth_scope) # token, refresh_token = auth.authenticate() # this will open a webpage # print(token, refresh_token) # setting the user authentication so any api call will also use it twitch.set_user_authentication(TOKEN, auth_scope, REFRESH_TOKEN) # setting up the Webhook itself sslContext = ssl.SSLContext(protocol=ssl.PROTOCOL_TLS) hook = TwitchWebHook(PUBLIC_ADDR, APP_ID, PORT, ssl_context=sslContext) # this will use the highest authentication set, which is the user authentication. hook.authenticate(twitch) # some hooks don't require any authentication, which would remove the requirement to set up a https reverse proxy # if you don't require authentication just dont call authenticate() hook.start() user_info = twitch.get_users() user_id = user_info['data'][0]['id'] print(f'User ID : {user_id}') # the hook has to run before you subscribe to any events since the twitch api will do a handshake this this webhook as soon as you subscribe success, uuid_stream = hook.subscribe_stream_changed(str(user_id), callback_stream_changed) print(f'Was subscription successfull?: {success}') # now we are fully set up and listening to our webhooks, lets wait for a user imput to stop again: input('[+] Press enter to stop...') # lets unsubscribe again success = hook.unsubscribe(uuid_stream) print(f'was unsubscription successfull?: {success}') # since hook.unsubscribe_on_stop is true, we dont need to unsubscribe manually, so lets just stop
class TwitchState(): """API documentation https://dev.twitch.tv/docs/api/reference#get-streams """ def __init__(self): self.cfg = configs() self.CLIENT_ID = self.cfg.get_client_id() self.CLIENT_SECRET = self.cfg.get_client_secret() self.twitch = Twitch(self.get_client_id(), self.get_client_secret()) self.OAUTH_TOKEN = self.twitch.get_app_token() self.HEADERS = { 'Client-ID': self.get_client_id(), 'Authorization': f'Bearer {self.get_oauth_token()}' } self.LIVE = True self.OFFLINE = False self.LIVE_CHANNEL_ID = self.cfg.get_live_channel_id() self.streamer_list = self.cfg.get_streamer_list() def streamer_factory(self, usr, discord_name, data): """Creates a streamer object to be stored.""" stream_bro = self.twitch.get_users(logins=[usr]) if len(stream_bro) > 0: self.cfg.setProperty("Streamers", data, discord_name) return stream_bro else: return False def get_live_channel_id(self): return self.LIVE_CHANNEL_ID def get_client_id(self): return self.CLIENT_ID def get_client_secret(self): return self.CLIENT_SECRET def get_oauth_token(self): return self.OAUTH_TOKEN def get_headers(self): return self.HEADERS def is_user_live(self, username, returnData=False): endpoint = 'https://api.twitch.tv/helix/streams' #endpoint = 'http://localhost:17563' my_params = {'user_login': username} response = requests.get(endpoint, headers=self.get_headers(), params=my_params) data = response.json()['data'] #pprint(data) if len(data) == 0: return False if returnData: return data return data[0]['type'] == 'live'
import os import ujson from pygments import highlight, lexers, formatters from twitchAPI.twitch import Twitch # settings TWITCH_CLIENT_ID = os.environ.get('TWITCH_CLIENT_ID') TWITCH_CLIENT_SECRET = os.environ.get('TWITCH_CLIENT_SECRET') # create instance of twitch API twitch = Twitch(TWITCH_CLIENT_ID, TWITCH_CLIENT_SECRET) twitch.authenticate_app([]) # get ID of user user_info = twitch.get_users(logins=['inthevalley2020']) formatted_json = ujson.dumps(user_info, sort_keys=True, indent=4) colorful_json = highlight(formatted_json, lexers.JsonLexer(), formatters.TerminalFormatter()) print(colorful_json)
from twitchAPI.pubsub import PubSub from twitchAPI.twitch import Twitch from twitchAPI.types import AuthScope from uuid import UUID from your_stuff import your_id, your_secret, your_oa, your_username import rekters # Authentication Setup and Info twitch = Twitch(your_id, your_secret) twitch.authenticate_app([]) twitch.set_user_authentication(your_oa, [AuthScope.CHANNEL_READ_REDEMPTIONS], your_oa) user_id = twitch.get_users(logins=[your_username])['data'][0]['id'] # Controllers def Channel_Pt_Controller(uuid: UUID, data: dict) -> None: redeemer = data["data"]["redemption"]["user"]["display_name"] reward = data["data"]["redemption"]["reward"]["title"] command = data["data"]["redemption"]["user_input"] command = command.lower() print(redeemer + " Is going to rek you.") if reward == "Do a little dance": rekters.Do_Alittle_Dance(command, 5) print("\n press ENTER to close") elif reward == "Shoot'em Up": rekters.Mouse_Hold(command, 5) print("\n press ENTER to close") else: print("That reward doesn't exist")
class TwitchClip(commands.Cog): def __init__(self, bot): self.bot = bot self.client_id = os.getenv('TWITCH_CLIENT_ID') self.client_secret = os.getenv('TWITCH_SECRET') self.twitch = Twitch(self.client_id, self.client_secret) self.conn = psycopg2.connect(user=os.getenv("PGUSER"), password=os.getenv("PGPASSWORD"), host=os.getenv("PGHOST"), port=os.getenv("PGPORT"), database=os.getenv("PGDATABASE")) self.curs = self.conn.cursor() self.fetch_tokens() self.scope = [AuthScope.CLIPS_EDIT] self.update_twitch_tokens() self.twitch.set_user_authentication(self.access_token, self.scope, self.refresh_token) @commands.command(aliases=['c']) async def clip(self, ctx, streamer): """Get a Twitch Clip""" self.update_twitch_tokens() # Get the streamer's ID streamer_info = self.streamer_check(streamer) if len(streamer_info) == 0: embed = discord.Embed(title="Streamer not found", color=discord.Colour.from_rgb(255, 0, 0)) await ctx.send(embed=embed) return streamer_id = streamer_info[0]['id'] create_clip = self.twitch.create_clip(broadcaster_id=streamer_id) if 'error' in create_clip: embed = discord.Embed(title=f"{create_clip['message']}", color=discord.Colour.from_rgb(255, 0, 0)) await ctx.send(embed=embed) return elif len(create_clip['data']) == 0: embed = discord.Embed(title="Streamer not found", color=discord.Colour.from_rgb(255, 0, 0)) await ctx.send(embed=embed) return clip_url = f"https://clips.twitch.tv/{create_clip['data'][0]['id']}" await ctx.send(clip_url) def update_twitch_tokens(self): self.fetch_tokens() # refresh twitch new_tokens = refresh_access_token(self.refresh_token, self.client_id, self.client_secret) self.access_token = new_tokens[0] self.refresh_token = new_tokens[1] # Update the access token update_access_query = f"UPDATE twitchclips SET token = '{new_tokens[0]}' WHERE id = 2" update_refresh_query = f"UPDATE twitchclips SET token = '{new_tokens[1]}' WHERE id = 3" self.curs.execute(update_access_query) self.curs.execute(update_refresh_query) def fetch_tokens(self): self.curs.execute("SELECT * FROM twitchclips") rows = self.curs.fetchall() for row in rows: if row[0] == 2: self.access_token = row[2] if row[0] == 3: self.refresh_token = row[2] def streamer_check(self, streamer): if streamer == "tt" or streamer == "t1" or streamer == "t": streamer = "loltyler1" elif streamer == "x" or streamer == "cow": streamer = "xqcow" elif streamer == "dlift" or streamer == "lift": streamer = "doublelift" return self.twitch.get_users(logins=[streamer])['data']
class Streamer: global TWITCH_APP_ID global TWITCH_SECRET global StreamerName global StreamerID isID = False def __init__(self, TWITCH_APP_ID, TWITCH_SECRET, User, isID = False): self.reader = codecs.getreader('utf-8') self.TWITCH_APP_ID = TWITCH_APP_ID self.TWITCH_SECRET = TWITCH_SECRET self.twitch = Twitch(self.TWITCH_APP_ID, self.TWITCH_SECRET) self.StreamerName = User self.isID = isID self.LOCK = False if not self.isID: self.StreamerID = self.getUserID() def getUserID(self): if self.isID: return self.StreamerName self.twitch.authenticate_app([]) data = self.twitch.get_users(logins=[self.StreamerName]) return data['data'][0]['id'] def isStreaming(self): data = self.twitch.get_streams(user_id=self.StreamerID) if len(data['data']) != 0: if data['data'][0]['type'] == 'live': return True return False def getStreamLink(self): return 'https://www.twitch.tv/' + str(self.StreamerName.lower()) def lock(self): self.LOCK = True def unlock(self): self.LOCK = False def lockStatus(self): return self.LOCK def getGame(self): if self.isStreaming(): data = self.twitch.get_streams(user_id=self.StreamerID) game = data['data'][0]['game_name'] return game return False def getViewers(self): if self.isStreaming(): data = self.twitch.get_streams(user_id=self.StreamerID) viewers = data['data'][0]['viewer_count'] return viewers return False def getTitle(self): if self.isStreaming(): data = self.twitch.get_streams(user_id=self.StreamerID) title = data['data'][0]['title'] return title return False def getThumbnail(self): if self.isStreaming(): data = self.twitch.get_streams(user_id=self.StreamerID) thumbnail = data['data'][0]['thumbnail_url'] thumbnail = thumbnail.format(width='1920', height='1080') return thumbnail return False def getProfilePicture(self): data = self.twitch.get_users(logins=self.StreamerName) picture = data['data'][0]['profile_image_url'] return picture def getStreamerName(self): return self.StreamerName
class TwitchAPIHandler: """ A wrapper to interact with the twitch API """ def __init__(self, client_id: str, client_secret: str): self.twitch = Twitch(client_id, client_secret) def get_streams_data(self, usernames): """ Gets all stream information from a list of given usernames :param usernames: The list of usernames :return: The JSON data of the request """ result = [] batches = split_to_100s(usernames) for batch in batches: batch_result = [] try: batch_result.extend( self.twitch.get_streams(user_login=batch).get("data")) except TwitchAPIException: logger.error( f"Streams data not received for batch, invalid request") for user in batch: try: batch_result.extend( self.twitch.get_streams( user_login=user).get("data")) except TwitchAPIException: logger.error( "User data cannot be found, invalid request") result.extend(batch_result) return result def get_user_data(self, usernames=None, ids=None): """ Gets the user information of a given user :param usernames: The display twitch usernames of the users :param ids: The unique twitch ids of the users :return: The JSON information of the user's data """ result = [] if usernames: user_list = split_to_100s(usernames) for u_batch in user_list: result += self.twitch.get_users(logins=u_batch).get("data") if ids: id_list = split_to_100s(ids) for id_batch in id_list: result += self.twitch.get_users(logins=id_batch).get("data") return result def get_game_data(self, game_id): """ Gets the game information of a given game :param game_id: The twitch game ID of a game :return: The JSON information of the game's data """ if game_id != "": game_data = self.twitch.get_games(game_ids=game_id) return game_data.get("data")[0] else: return None def get_team_users(self, team_id): """ Gets the users data about a given team :param team_id: The team name of the twitch team :return: the JSON information of the users """ return (self.get_team_data(team_id)).get("users") def get_team_data(self, team_id): """ Gets the users data about a given team :param team_id: The team name of the twitch team :return: the JSON information of the users """ a = self.twitch.get_teams(name=team_id) return a.get("data")[0]
auth = UserAuthenticator(twitch, target_scope, force_verify=False) # this will open your default browser and prompt you with the twitch verification website token, refresh_token = auth.authenticate() print(token, refresh_token) # add User authentication twitch.set_user_authentication(token, target_scope, refresh_token) # starting up PubSub pubsub = PubSub(twitch) pubsub.start() user_id = twitch.get_users(logins=[TWITCH_CHANNEL_NAME])['data'][0]['id'] pprint(twitch.get_users(logins=[TWITCH_CHANNEL_NAME])) # you can either start listening before or after you started pubsub. # uuid1 = pubsub.listen_whispers(user_id, callback_function) uuid2 = pubsub.listen_channel_points(user_id, callback_function) uuid3 = pubsub.listen_channel_subscriptions(user_id, callback_function) uuid4 = pubsub.listen_bits(user_id, callback_function) # print(uuid2) input('press ENTER to close...') # you do not need to unlisten to topics before stopping but you can listen and unlisten at any moment you want # pubsub.unlisten(uuid1) pubsub.unlisten(uuid2)
class Twitch(commands.Cog): """Get live updates for your favourite twitch streamers """ def __init__(self, disclient, twitch_id, twitch_sec): self.disclient = disclient self.disclient.loop.create_task(self.get_online_streams()) self.twitch = Twitchy( twitch_id, twitch_sec, ) self.twitch.authenticate_app([]) self.time_format = '%Y-%m-%d %H:%M:%S' async def get_online_streams(self): await self.disclient.wait_until_ready() print('Looking for live Twitch streams!') while not self.disclient.is_closed(): try: # print("checking twitch") check = get_all_twitch_channels_to_check(3) if not check: await asyncio.sleep(60) continue if len(check) > 100: # need to split list into lengths of 100 in future # get_streams only takes 100 inputs at a time check = check[:99] ids = [str(x) for x in check.keys()] b = self.twitch.get_streams(user_id=ids) for stream in b["data"]: c = self.twitch.get_users(user_ids=stream["user_id"]) linkend = c['data'][0]['login'] link = f"https://www.twitch.tv/{linkend}" username = stream['user_name'] desc = stream['title'] msg = f"`{username}` is live! {link}" image_url = f"""{stream['thumbnail_url'].format( width=852, height=480)}?{str(datetime.datetime.now().timestamp())}""" embed = discord.Embed(title=msg, description=desc, color=discord.Color.purple()) embed.set_image(url=image_url) embed.add_field(name='Playing', value=stream['game_name']) check_time = datetime.datetime.strptime( stream['started_at'], '%Y-%m-%dT%H:%M:%SZ') check_time.strftime(self.time_format) if check[int(stream['user_id'])] != check_time: update_twitch_last_live(stream['user_id'], check_time) else: continue channels = get_channels_following_twitch_stream( stream['user_id']) if not channels: await asyncio.sleep(60) continue for chan in channels: channel = self.disclient.get_channel(int(chan)) # set ping roles up in the future # gid = channel.guild.id # rol = self.disclient.get_guild(gid).roles # tr = discord.utils.get(rol, name="twitch") await channel.send( embed=embed ) # content=tr.mention, for when roles are assigned except Exception as e: print(e) # delay 60 seconds before checking again await asyncio.sleep(60) @commands.command( aliases=['followstream', 'follow_stream', 'followtwitch']) @commands.guild_only() @commands.has_permissions(administrator=True) async def follow_twitch(self, ctx, stream): """Follows a twitch stream in this channel! Live updates will be posted here. .follow_twitch <username or link>""" channel = ctx.channel.id if "twitch.tv" in stream: stream = stream.split("/")[-1].lower() else: stream = stream.lower() user = self.twitch.get_users(logins=stream) print(user) if not user: await ctx.send( embed=error_embed(f"Failed to find Twitch user {stream}!")) return for d in user["data"]: ayed = str(d["id"]) add_channel(channel) add_twitch_channel_to_db(ayed) followed = follow_twitch_channel_db(channel, ayed) if followed: display_name = d['display_name'] profile_image = d['profile_image_url'] link = f"https://www.twitch.tv/{d['login']}" msg = f'This channel will now receive updates on when {display_name} goes live at {link}' embed = discord.Embed( title=f'Successfully Followed {display_name}!', description=msg, color=discord.Color.purple()) embed.set_thumbnail(url=profile_image) await ctx.send(embed=embed) else: await ctx.send(embed=error_embed( f"Failed to follow {stream} in this channel!")) @commands.command( aliases=['unfollowstream', 'unfollow_stream', 'unfollowtwitch']) @commands.guild_only() @commands.has_permissions(administrator=True) async def unfollow_twitch(self, ctx, stream): """Unfollows a twitch stream followed in this channel. .unfollow_twitch <username or link>""" channel = ctx.channel.id if "twitch.tv" in stream: stream = stream.split("/")[-1].lower() else: stream = stream.lower() user = self.twitch.get_users(logins=stream) if not user: await ctx.send( embed=error_embed(f"Failed to find Twitch user {stream}!")) return for d in user["data"]: ayed = str(d["id"]) unfollowed = unfollow_twitch_channel_db(channel, ayed) if unfollowed: await ctx.send(embed=success_embed( f"Unfollowed {stream} in this channel!")) else: await ctx.send(embed=error_embed( f"Failed to unfollow {stream} in this channel!")) @commands.command(name='twitch', aliases=['twitchs', 'twitches']) @commands.guild_only() async def twitches(self, ctx): """Returns a list of all twitch users followed in this server!""" guild = ctx.guild chans = get_all_twitch_followed_in_guild() chan_dict = {} for pair in chans: if pair[0] not in chan_dict: chan_dict.update({pair[0]: [pair[-1]]}) else: chan_dict[pair[0]].append(pair[-1]) msg = '' for channel in guild.channels: if channel.id in chan_dict: for twitch in chan_dict[channel.id]: twitch_str = str(twitch) twitch = self.twitch.get_users(user_ids=[twitch_str]) twitch = twitch['data'][0]['login'] spacing = 39 - len(channel.name + twitch) chan_str = f"`#{channel.name}{' ' * spacing}{twitch}`\n" msg = msg + chan_str if msg == '': await ctx.send( embed=error_embed('No Twitch streams followed in this server!') ) else: add_to_start = f"`Channel Name{' ' * 17}Twitch User`\n" msg = add_to_start + msg embed = discord.Embed( title=f'Twitch Streams Followed in {guild.name}!', description=msg, color=discord.Color.purple()) await ctx.send(embed=embed)
) else: HUE_KEY = resp["success"]["username"] print( f"Your key is: {HUE_KEY}\nEdit the script and add this key to `HUE_KEY` to skip this step in the future." ) # setting up Authentication and getting your user id twitch.authenticate_app([]) target_scope = [AuthScope.CHANNEL_READ_REDEMPTIONS] auth = UserAuthenticator(twitch, target_scope, force_verify=False) # this will open your default browser and prompt you with the twitch verification website token, refresh_token = auth.authenticate() twitch.set_user_authentication(token, target_scope, refresh_token) user_id = twitch.get_users(logins=[USERNAME])['data'][0]['id'] # starting up PubSub pubsub = PubSub(twitch) pubsub.start() # you can either start listening before or after you started pubsub. uuid = pubsub.listen_whispers(user_id, callback) # uuid = pubsub.listen_channel_points(user_id, callback) input('press ENTER to close...\n') # you do not need to unlisten to topics before stopping but you can listen and unlisten at any moment you want pubsub.unlisten(uuid) pubsub.stop()
if __name__ == '__main__': print('~starting script~') # Create an instance of the REST client. aio = Client(private_const.ADAFRUIT_IO_USERNAME, private_const.ADAFRUIT_IO_KEY) feed = Feed(name="ledfeed") # create instance of twitch API twitch = Twitch(private_const.app_id, private_const.app_secret) twitch.authenticate_app([]) # get ID of user user_info = twitch.get_users(logins=[private_const.username]) user_id = user_info['data'][0]['id'] # set up channel point redemption pubsub target_scope = [AuthScope.CHANNEL_READ_REDEMPTIONS] auth = UserAuthenticator(twitch, target_scope, force_verify=False) token, refresh_token = auth.authenticate() twitch.set_user_authentication(token, target_scope, refresh_token) pubsub = PubSub(twitch) pubsub.start() # you can either start listening before or after you started pubsub. print('~connected to twitch~') # listen to channel points. enter callback function when redemption occurs
for user_id_line in user_id_lines: user_id = user_id_line.strip() user_id_set.add(user_id) user_id_list = list(sorted(user_id_set)) chunked_namelists = [*chunks(name_list, 100)] chunked_user_id_lists = [*chunks(user_id_list, 100)] with open("namelist_cleaned.txt", "w") as name_file, open("user_id_list_cleaned.txt", "w") as id_file: progressbar = tqdm.tqdm(chunked_namelists, file=sys.stdout, ascii=True, desc="User names") for chunk in progressbar: user_infos = twitch.get_users(logins=chunk).get("data") for user_info in user_infos: name_file.write(f"{user_info.get('login')}\n") id_file.write(f"{user_info.get('id')}\n") name_file.flush() id_file.flush() progressbar = tqdm.tqdm(chunked_user_id_lists, file=sys.stdout, ascii=True, desc="User id's") for chunk in progressbar: user_infos = twitch.get_users(user_ids=chunk).get("data") for user_info in user_infos: name_file.write(f"{user_info.get('login')}\n") id_file.write(f"{user_info.get('id')}\n")
else: try: TOKEN, REFRESH_TOKEN = refresh_access_token( REFRESH_TOKEN, CLIENT_ID, CLIENT_SECRET ) except InvalidRefreshTokenException: TOKEN, REFRESH_TOKEN = auth.authenticate() twitch_secrets["TOKEN"] = TOKEN twitch_secrets["REFRESH_TOKEN"] = REFRESH_TOKEN update_twitch_secrets(twitch_secrets) twitch.set_user_authentication(TOKEN, target_scope, REFRESH_TOKEN) user_id = twitch.get_users(logins=[USERNAME])["data"][0]["id"] # starting up PubSub pubsub = PubSub(twitch) pubsub.start() # you can either start listening before or after you started pubsub. if WHISPER_MODE: uuid = pubsub.listen_whispers(user_id, callback) else: uuid = pubsub.listen_channel_points(user_id, callback) input("Now listening for events.\nPress ENTER at any time to stop.\n") # you do not need to unlisten to topics before stopping but you can listen and unlisten at any moment you want pubsub.unlisten(uuid) pubsub.stop()