def __init__(self): self.helix_api = Helix(client_id=Settings().config['client_id'], bearer_token=Arguments().oauth_token, use_cache=False) self.formats: List[str] = [] self.whitelist: List[str] = [] self.blacklist: List[str] = [] # Populate format list according to whitelist and blacklist if 'all' in Arguments().formats and 'all' in Settings( ).config['formats']: self.blacklist = Settings( ).config['formats']['all']['whitelist'] or [] self.whitelist = Settings( ).config['formats']['all']['blacklist'] or [] # Append formats to list if they can be used self.formats = [ format_name for format_name in Settings().config['formats'].keys() if self._can_use_format(format_name) ] else: self.formats = [ format_name for format_name in Arguments().formats if self._can_use_format(format_name) ]
def get_vod(vod: int, client: twitch.Helix): """ Given a twitch Vod ID and Twitch API Client, return that video object and throw error if given an incorrect Vod iD :param vod: Twitch video ID , Twitch-Python Helix client :return: video: Twitch Helix API video object - twitch.helix.Video """ # check if the video exists and is legitimate based on id try: video = client.video(video_id=vod) except requests.exceptions.HTTPError: sys.exit('Invalid VoD ID entered.') choice = input((f"Is '{video.title}' by {video.user_name} of duration {video.duration} created on {video.created_at} your requested VoD? (y/n)")) if choice.lower() == "y": return video else: sys.exit("Operation cancelled by user.")
import webbrowser import os from twitch import Helix from subprocess import Popen import tkinter from tkinter import * client = Helix(client_id='', bearer_token='') #Need to grab twitch client ID count = 20 #Change this number to change the amount of streamers the twitch API pulls game_name = "warframe" f = input("write game name : ") while (len(f) > 0): if client.game(name=f) == None: f = input("wrong name write game name : ") else: game_name = f break game = client.game(name=game_name).id print(game) def check_for_streams(): global streams streams = client.streams(game_id=game, first=count).users #credit to @jancodes for the idea def multiTwitch(myList): Popen(
class Downloader: def __init__(self): self.helix_api = Helix(client_id=Settings().config['client_id'], bearer_token=Arguments().oauth_token, use_cache=False) self.formats: List[str] = [] self.whitelist: List[str] = [] self.blacklist: List[str] = [] # Populate format list according to whitelist and blacklist if 'all' in Arguments().formats and 'all' in Settings( ).config['formats']: self.blacklist = Settings( ).config['formats']['all']['whitelist'] or [] self.whitelist = Settings( ).config['formats']['all']['blacklist'] or [] # Append formats to list if they can be used self.formats = [ format_name for format_name in Settings().config['formats'].keys() if self._can_use_format(format_name) ] else: self.formats = [ format_name for format_name in Arguments().formats if self._can_use_format(format_name) ] def _can_use_format(self, format_name: str) -> bool: """ Check if format name should be used based on whitelist and blacklist :param format_name: Name of format :return: If format should be used """ # Lowercase format name format_name = format_name.lower() # Reserved format names if format_name in ['all']: return False # Format does not exist if format_name not in Settings().config['formats'].keys(): return False # Whitelisted formats if self.whitelist and format_name not in self.whitelist: return False # Blacklisted formats if self.blacklist and format_name in self.blacklist: return False return True def video(self, video: Video) -> None: """ Download chat from video :param video: Video object :return: None """ # Parse video duration regex = re.compile( r'((?P<hours>\d+?)h)?((?P<minutes>\d+?)m)?((?P<seconds>\d+?)s)?') parts = regex.match(video.duration).groupdict() time_params = {} for name, param in parts.items(): if param: time_params[name] = int(param) video_duration = datetime.timedelta(**time_params) formatter = Formatter(video) # Special case for JSON # Build JSON object before writing it if 'json' in self.formats: Logger().log('Downloading JSON data', Log.VERBOSE) output: str = Pipe( Settings().config['formats']['json']['output']).output( video.data) os.makedirs(os.path.dirname(output), exist_ok=True) with open(output + ".tmp", 'w', encoding='utf-8') as file: file.write("{\n") file.write("\"video\": ") file.write(json.dumps(video.data, indent=4)) file.write(",\n") file.write("\"comments\": [\n") comment = None for comment in video.comments: # Skip unspecified users if a list is provided. if Arguments().users and comment.commenter.name.lower( ) not in Arguments().users: continue # If specified, only include messages that include a specified string if Arguments().includes and Arguments( ).includes not in comment.message.body.lower(): continue file.write(json.dumps(comment.data, indent=4)) file.write(",\n") # Ignore comments that were posted after the VOD finished if Settings().config['formats']['json'].get( 'comments', {}).get('ignore_new_comments', False): comment_date = dateutil.parser.parse( comment.created_at) vod_finish_date = dateutil.parser.parse( video.created_at) + video_duration if comment_date > vod_finish_date: continue if Logger().should_print_type(Log.PROGRESS): self.draw_progress( current=comment.content_offset_seconds, end=video_duration.seconds, description='json') if comment: file.seek(file.tell() - 2) file.write("\n]\n") file.write("}\n") os.rename(output + ".tmp", output) Logger().log(f'[json] {output}') # For each format (ignore json this time) for format_name in [x for x in self.formats if x not in ['json']]: Logger().log(f'Formatting chat using: {format_name}', Log.VERBOSE) # Get (formatted_comment, comment), output comment_tuple, output = formatter.use(format_name) # Create output directory and write to file os.makedirs(os.path.dirname(output), exist_ok=True) with open(output, '+w', encoding='utf-8') as file: # For every comment in video for formatted_comment, comment in comment_tuple: # Skip unspecified users if a list is provided. if Arguments().users and comment.commenter.name.lower( ) not in Arguments().users: continue # If specified, only include messages that include a specified string if Arguments().includes and Arguments().includes.lower( ) not in comment.message.body.lower(): continue # Ignore comments that were posted after the VOD finished if Settings().config['formats'][format_name].get( 'comments', {}).get('ignore_new_comments', False): comment_date = dateutil.parser.parse( comment.created_at) vod_finish_date = dateutil.parser.parse( video.created_at) + video_duration if comment_date > vod_finish_date: continue # Draw progress if comment and Logger().should_print_type(Log.PROGRESS): self.draw_progress( current=comment.content_offset_seconds, end=video_duration.seconds, description=format_name) # Display preview Logger().log(formatted_comment, Log.PREVIEW) # Write comment to file file.write('{}\n'.format(formatted_comment)) Logger().log('[{}] {}'.format(format_name, output)) def videos(self, video_ids: List[int]) -> None: """ Download multiple video ids :param video_ids: List of video ids :return: None """ for video in self.helix_api.videos(video_ids): Logger().log(format('\n{}'.format(video.title)), Log.REGULAR) self.video(video) def channels(self, channels: List[str]) -> None: """ Download videos from multiple channels :param channels: List of channel names :return: None """ for channel, videos in self.helix_api.users(channels).videos( first=Arguments().first): Logger().log(format('\n{}'.format(channel.display_name)), Log.REGULAR) for video in videos: Logger().log(format('\n{}'.format(video.title)), Log.REGULAR) self.video(video) @staticmethod def draw_progress(current: float, end: float, description: str = 'Downloading') -> None: """ Draw download progress :param current: Current chat position (seconds) :param end: End position (seconds) :param description: Progress description :return: """ sys.stdout.write('[{}] {}%\r'.format( description, '%.2f' % min(current * 10 / end * 10, 100.00))) sys.stdout.flush()
def __init__(self, clientID: str, bearer_token: str) -> None: self.helixClient : Helix = Helix(client_id=clientID, bearer_token=bearer_token, use_cache=False) self.commentData : Chat = Chat() self.commentAnalyzer : Analyzer = Analyzer() self.currentVideo : Video = None
def main(): parser = argparse.ArgumentParser(description="Twitch notifications") parser.add_argument("-c", "--channel", default="#video", help="Slack channel") parser.add_argument( "-n", "--notifications", default="#ci", help="Slack channel notifications for errors or warnings") parser.add_argument("-i", "--interval", default=30, help="Update interval in seconds", type=int) parser.add_argument("-u", "--users", default="", help="Twitch users") args = parser.parse_args() remember_online_users = [] TWITCH_CLIENT_ID = os.environ["TWITCH_CLIENT_ID"] TWITCH_CLIENT_SECRET = os.environ["TWITCH_CLIENT_SECRET"] def bearer(): global twitch_access_token_expires_in global twitch_access_token if (twitch_access_token_expires_in < (60 * 15) and not twitch_access_token): connection = http.client.HTTPSConnection("id.twitch.tv") connection.request( "POST", "/oauth2/token?client_id=" + TWITCH_CLIENT_ID + "&client_secret=" + TWITCH_CLIENT_SECRET + "&grant_type=client_credentials") response = json.loads( connection.getresponse().read().decode('utf8')) twitch_access_token = response['access_token'] twitch_access_token_expires_in = int(response['expires_in']) return twitch_access_token while (True): twitch = Helix(client_id=TWITCH_CLIENT_ID, client_secret=TWITCH_CLIENT_SECRET, bearer_token=bearer()) slack = WebClient(token=os.environ["SLACK_API_KEY"]) try: for user in args.users.split(","): if twitch.user(user).is_live: print("TWITCH_LIVE: {}".format(user)) if user not in remember_online_users: remember_online_users.append(user) slack.chat_postMessage( channel=args.channel, attachments=[{ "text": "TWITCH_LIVE: https://www.twitch.tv/{}".format( user), "color": "#ff0000" }]) else: if user in remember_online_users: remember_online_users.remove(user) except Exception as exception: print(exception) slack.chat_postMessage( channel=args.notifications, attachments=[{ "text": "ERROR: reevefresh: Failed to fetch Twitch users status", "color": "#ff0000" }]) print("Online users: {}\n".format(",".join(remember_online_users))) time.sleep(args.interval)
TODO: -add emoji support for exporting data to files -allow users to get VODs from specific timeframes -allow users to search for messages from specific users -integrate this into a webapp to host on the website -make this into a class? -bugfixing ''' from twitch import Helix import re, time, argparse import cfg # --- API key --- helix = Helix(client_id=cfg.CLIENT_ID, bearer_token=cfg.BEARER_TOKEN, use_cache=True) # --- Argument parser --- parser = argparse.ArgumentParser(description="View VOD comments and search through them.") parser.add_argument("-u", "--user", help="desired user to view") parser.add_argument("-c", "--count", help="number of most recent vods to view", type=int, default=1) parser.add_argument("-s", "--search", help="term to search for in vods") parser.add_argument("-t", "--realtime", help="include real-world time comments were posted at", action="store_true") args = parser.parse_args() # --- Main stuff --- user = helix.user(args.user if args.user else input('User: '******'Number of VODs to search: ')) vods = user.videos(first=vodCount) searchTerm = args.search if args.search else input('Search for: ')
def __acquire_authorized_api(self) -> Helix: self.__bearer_token = self.__acquire_token() self.__api = Helix(client_id=self.__client_id, client_secret=self.__client_secret, bearer_token=f'bearer {self.__bearer_token}') return self.__api
def __get_user(self, api: Helix, nick_or_id: Union[str, int]) -> Optional[User]: return api.user(nick_or_id)
# stdlib from importlib import import_module from os import O_PATH from rx.core.typing import Observer # 3rd party from twitch import Chat, Helix from twitch.chat import Message # local from .. import config from ..web import app from .commands import * message_handlers = [] # Twitch API client helix = Helix(config.CLIENT_ID, config.CLIENT_SECRET) user = helix.user(config.USERNAME) for mod in config.HANDLERS: module = import_module(f'..{mod}.bot', __name__) message_handlers.append(getattr(module, 'handle_message')) class MessageHandler(Observer): "Message handling Observer" def on_completed(_): pass def on_error(_):