def get_game_rec(game_data, team_to_play): """ """ game_rec = None for game_pk in game_data: if team_to_play in (game_data[game_pk]['away_abbrev'], game_data[game_pk]['home_abbrev']): game_rec = game_data[game_pk] break if game_rec is None: util.die("No game found for team {}".format(team_to_play)) return game_rec
def login(): """ taken from plugin.video.mlbtv """ url = 'https://secure.mlb.com/pubajaxws/services/IdentityPointService' headers = { "SOAPAction": "http://services.bamnetworks.com/registration/identityPoint/identify", "Content-type": "text/xml; charset=utf-8", "User-Agent": "Dalvik/2.1.0 (Linux; U; Android 6.0.1; Hub Build/MHC19J)", "Connection": "Keep-Alive" } payload = "<?xml version='1.0' encoding='UTF-8'?" payload += '<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">' payload += '<SOAP-ENV:Body><tns:identityPoint_identify_request xmlns:tns="http://services.bamnetworks.com/registration/types/1.4">' payload += '<tns:identification type="email-password"><tns:id xsi:nil="true"/>' payload += '<tns:fingerprint xsi:nil="true"/>' payload += '<tns:email>' payload += '<tns:id xsi:nil="true"/>' payload += '<tns:address>{}</tns:address>'.format( config.CONFIG.parser['username']) payload += '</tns:email>' payload += '<tns:password>{}</tns:password>'.format( config.CONFIG.parser['password']) payload += '<tns:mobilePhone xsi:nil="true"/>' payload += '<tns:profileProperty xsi:nil="true"/>' payload += '</tns:identification>' payload += '</tns:identityPoint_identify_request>' payload += '</SOAP-ENV:Body>' payload += '</SOAP-ENV:Envelope>' util.log_http(url, 'post', headers, sys._getframe().f_code.co_name) req = requests.post(url, headers=headers, data=payload, verify=config.VERIFY_SSL) """ Bad username => <status><code>-1000</code><message> [Invalid credentials for identification] [com.bamnetworks.registration.types.exception.IdentificationException: Account doesn't exits]</message><exceptionClass>com.bamnetworks.registration.types.exception.IdentificationException</exceptionClass><detail type="identityPoint" field="exists" message="false" messageKey="identityPoint.exists" /><detail type="identityPoint" field="email-password" message="identification error on identity point of type email-password" messageKey="identityPoint.email-password" /></status> Bad password => <status><code>-1000</code><message> [Invalid credentials for identification] [com.bamnetworks.registration.types.exception.IdentificationException: Invalid Password]</message><exceptionClass>com.bamnetworks.registration.types.exception.IdentificationException</exceptionClass><detail type="identityPoint" field="exists" message="true" messageKey="identityPoint.exists" /><detail type="identityPoint" field="email-password" message="identification error on identity point of type email-password" messageKey="identityPoint.email-password" /></status> Good => <status><code>1</code><message>OK</message></status> """ if find_text_in_str(req.text, '<code>', '</code>') != '1': LOG.debug('Login Error: r.text: %s', req.text) msg = find_text_in_str( req.text, 'com.bamnetworks.registration.types.exception.IdentificationException: ', ']</message>') util.die('Login Error: {}'.format(msg)) LOG.debug('Login successful') save_cookies(req.cookies)
def play_stream(game_rec, team_to_play, feedtype, date_str, fetch, login_func, from_start, offset=None, duration=None, is_multi_highlight=False): if feedtype is not None and feedtype in config.HIGHLIGHT_FEEDTYPES: # handle condensed/recap playback_url = find_highlight_url_for_team(game_rec, feedtype) if playback_url is None: util.die("No playback url for feed '{}'".format(feedtype)) play_highlight(playback_url, get_fetch_filename(date_str, game_rec, feedtype, fetch), is_multi_highlight) else: # handle full game (live or archive) # this is the only feature requiring an authenticated session auth_cookie = auth.get_auth_cookie() if auth_cookie is None: login_func() # auth.login(config.CONFIG.parser['username'], # config.CONFIG.parser['password'], # config.CONFIG.parser.getboolean('use_rogers', False)) LOG.debug('Authorization cookie: {}'.format(auth.get_auth_cookie())) media_playback_id, event_id = select_feed_for_team( game_rec, team_to_play, feedtype) if media_playback_id is not None: stream_url, media_auth = fetch_stream(game_rec['game_pk'], media_playback_id, event_id) if stream_url is not None: if config.SAVE_PLAYLIST_FILE: save_playlist_to_file(stream_url, media_auth) streamlink( stream_url, media_auth, get_fetch_filename(date_str, game_rec, feedtype, fetch), from_start, offset, duration) else: LOG.error("No stream URL found") else: LOG.info("No game stream found for %s", team_to_play) return 0
def play_stream(game_rec, team_to_play, feedtype, date_str, fetch, from_start, inning_ident, is_multi_highlight=False): if game_rec['doubleHeader'] != 'N': LOG.info('Selected game number %s of doubleheader', game_rec['gameNumber']) if feedtype is not None and feedtype in config.HIGHLIGHT_FEEDTYPES: # handle condensed/recap playback_url = find_highlight_url_for_team(game_rec, feedtype) if playback_url is None: util.die("No playback url for feed '{}'".format(feedtype)) play_highlight(playback_url, get_fetch_filename(date_str, game_rec, feedtype, fetch), is_multi_highlight) else: # handle full game (live or archive) # this is the only feature requiring an authenticated session import mlbam.session as session mlb_session = session.MLBSession() media_playback_id, media_state = select_feed_for_team( game_rec, team_to_play, feedtype) if media_playback_id is not None: stream_url = mlb_session.lookup_stream_url(game_rec['game_pk'], media_playback_id) if stream_url is not None: offset = None if config.SAVE_PLAYLIST_FILE: mlb_session.save_playlist_to_file(stream_url) if inning_ident: offset = _calculate_inning_offset(inning_ident, media_state, game_rec) streamlink( stream_url, mlb_session, get_fetch_filename(date_str, game_rec, feedtype, fetch), from_start, offset) else: LOG.error("No stream URL found") else: LOG.info("No game stream found for %s", team_to_play) return 0
def get_game_rec(game_data, team_to_play, game_number_str): """ game_number_str: is an string 1 or 2 indicating game number for doubleheader """ game_rec = None for game_pk in game_data: if team_to_play in (game_data[game_pk]['away']['abbrev'], game_data[game_pk]['home']['abbrev']): if game_data[game_pk][ 'doubleHeader'] != 'N' and game_number_str != game_data[ game_pk]['gameNumber']: # game is doubleheader but not our game_number continue game_rec = game_data[game_pk] break if game_rec is None: if int(game_number_str) > 1: util.die( "No second game available for team {}".format(team_to_play)) util.die("No game found for team {}".format(team_to_play)) return game_rec
def get_session_key(game_pk, event_id, content_id, auth_cookie): """ game_pk: game_pk event_id: eventId content_id: mediaPlaybackId """ raise Exception("Not implemented") session_key_file = os.path.join(config.CONFIG.dir, 'sessionkey') if os.path.exists(session_key_file): if datetime.today() - datetime.fromtimestamp( os.path.getmtime(session_key_file)) < timedelta(days=1): with open(session_key_file, 'r') as f: for line in f: session_key = line.strip() LOG.debug( 'Using cached session key: {}'.format(session_key)) return session_key LOG.debug("Requesting session key") epoch_time_now = str(int(round(time.time() * 1000))) url = 'https://mf.svc.nhl.com/ws/media/mf/v2.4/stream?eventId={}&format=json&platform={}&subject=NHLTV&_={}' url = url.format(event_id, config.CONFIG.platform, epoch_time_now) headers = { "Accept": "application/json", "Accept-Encoding": "identity", "Accept-Language": "en-US,en;q=0.8", "Connection": "keep-alive", "Authorization": auth_cookie, "User-Agent": config.CONFIG.ua_pc, "Origin": "https://www.nhl.com", "Referer": "https://www.nhl.com/tv/{}/{}/{}".format(game_pk, event_id, content_id) } util.log_http(url, 'get', headers, sys._getframe().f_code.co_name) r = requests.get(url, headers=headers, cookies=load_cookies(), verify=config.VERIFY_SSL) json_source = r.json() LOG.debug('Session key json: {}'.format(json_source)) if json_source['status_code'] == 1: if json_source['user_verified_event'][0]['user_verified_content'][0][ 'user_verified_media_item'][0]['blackout_status'][ 'status'] == 'BlackedOutStatus': session_key = 'blackout' LOG.debug('Event blacked out: {}'.format( json_source['user_verified_event'][0]['user_verified_content'] [0]['user_verified_media_item'][0])) else: session_key = str(json_source['session_key']) else: msg = json_source['status_message'] util.die('Could not get session key: {}'.format(msg)) LOG.debug('Retrieved session key: {}'.format(session_key)) update_session_key(session_key) return session_key
def play_stream(game_data, team_to_play, game_number_str, feedtype, date_str, fetch, wait_for_start): """ game_number_str: is an string 1 or 2 indicating game number for doubleheader """ game_rec = None for game_pk in game_data: if team_to_play in (game_data[game_pk]['away']['abbrev'], game_data[game_pk]['home']['abbrev']): if game_data[game_pk][ 'doubleHeader'] != 'N' and game_number_str != game_data[ game_pk]['gameNumber']: # game is doubleheader but not our game_number continue game_rec = game_data[game_pk] break if game_rec is None: if int(game_number_str) > 1: util.die( "No second game available for team {}".format(team_to_play)) util.die("No game found for team {}".format(team_to_play)) if game_rec['doubleHeader'] != 'N': LOG.info('Selected game number %s of doubleheader', game_rec['gameNumber']) if feedtype is not None and feedtype in config.HIGHLIGHT_FEEDTYPES: # handle condensed/recap playback_url = find_highlight_url_for_team(game_rec, feedtype) if playback_url is None: util.die("No playback url for feed '{}'".format(feedtype)) play_highlight(playback_url, get_fetch_filename(date_str, game_rec, feedtype, fetch)) else: # handle full game (live or archive) # this is the only feature requiring an authenticated session import mlbam.session as session mlb_session = session.MLBSession() if wait_for_start and not _has_game_started(game_rec['mlbdate']): LOG.info('Waiting for game to start. Local start time is ' + util.convert_time_to_local(game_rec['mlbdate'])) print('Use Ctrl-c to quit .', end='', flush=True) count = 0 while not _has_game_started(game_rec['mlbdate']): time.sleep(10) count += 1 if count % 6 == 0: print('.', end='', flush=True) media_playback_id, event_id = select_feed_for_team( game_rec, team_to_play, feedtype) if media_playback_id is not None: stream_url = mlb_session.lookup_stream_url(game_rec['game_pk'], media_playback_id) if stream_url is not None: if config.DEBUG: mlb_session.save_playlist_to_file(stream_url) streamlink( stream_url, mlb_session, get_fetch_filename(date_str, game_rec, feedtype, fetch)) else: LOG.error("No stream URL") else: LOG.info("No game found for {}".format(team_to_play)) return 0
def nhl_login(): """Authenticates user to nhl site.""" url = 'https://user.svc.nhl.com/oauth/token?grant_type=client_credentials' headers = { "Accept": "application/json", "Accept-Encoding": "identity", "Accept-Language": "en-US,en;q=0.8", "User-Agent": config.CONFIG.ua_pc, "Origin": "https://www.nhl.com", "Authorization": "Basic d2ViX25obC12MS4wLjA6MmQxZDg0NmVhM2IxOTRhMThlZjQwYWM5ZmJjZTk3ZTM=", } userid = config.CONFIG.parser['username'] passwd = config.CONFIG.parser['password'] use_rogers = config.CONFIG.parser.getboolean('use_rogers', False) util.log_http(url, 'post', headers, sys._getframe().f_code.co_name) r = requests.post(url, headers=headers, data='', cookies=load_cookies(), verify=config.VERIFY_SSL) if r.status_code >= 400: util.die("Authorization cookie couldn't be downloaded.") json_source = r.json() if get_auth_cookie() is not None: LOG.debug('login: already logged in (we have a valid cookie)') return auth_cookie = json_source['access_token'] if use_rogers: LOG.info("Logging in via Rogers") url = 'https://activation-rogers.svc.nhl.com/ws/subscription/flow/rogers.login' login_data = '{"rogerCredentials":{"email":%s,"password":%s}}' % ( userid, passwd) # referer = "https://www.nhl.com/login/rogers" else: LOG.info("Logging in via NHL") url = 'https://user.svc.nhl.com/v2/user/identity' login_data = '{"email":{"address":%s},"type":"email-password","password":{"value":%s}}' % ( userid, passwd) headers = { "Accept": "*/*", "Accept-Encoding": "identity", "Accept-Language": "en-US,en;q=0.8", "Content-Type": "application/json", "Authorization": auth_cookie, "Connection": "keep-alive", "User-Agent": config.CONFIG.ua_pc } util.log_http(url, 'post', headers, sys._getframe().f_code.co_name) r = requests.post(url, headers=headers, data=login_data, cookies=load_cookies(), verify=config.VERIFY_SSL) if r.status_code >= 400: try: json_source = r.json() msg = json_source['message'] except Exception as e: msg = "Please check that your username and password are correct" LOG.debug('Login Error: json_source: {}'.format(json_source)) util.die('Login Error: {}'.format(msg)) LOG.debug('Login successful') save_cookies(r.cookies)
def fetch_stream(game_pk, content_id, event_id): """ game_pk: game_pk event_id: eventId content_id: mediaPlaybackId """ stream_url = None media_auth = None auth_cookie = auth.get_auth_cookie() if auth_cookie is None: LOG.error("fetch_stream: not logged in") return stream_url, media_auth session_key = auth.get_session_key(game_pk, event_id, content_id, auth_cookie) if session_key is None: return stream_url, media_auth elif session_key == 'blackout': msg = ( 'The game you are trying to access is not currently available due to local ' 'or national blackout restrictions.\n' ' Full game archives will be available 48 hours after completion of this game.' ) LOG.info('Game Blacked Out: {}'.format(msg)) return stream_url, media_auth url = config.CONFIG.mf_svc_url url += '?contentId=' + content_id url += '&playbackScenario=' + config.CONFIG.playback_scenario url += '&platform=' + config.CONFIG.platform url += '&sessionKey=' + urllib.parse.quote_plus(session_key) # Get user set CDN if config.CONFIG.parser['cdn'] == 'akamai': url += '&cdnName=MED2_AKAMAI_SECURE' elif config.CONFIG.parser['cdn'] == 'level3': url += '&cdnName=MED2_LEVEL3_SECURE' headers = { "Accept": "*/*", "Accept-Encoding": "identity", "Accept-Language": "en-US,en;q=0.8", "Connection": "keep-alive", "Authorization": auth_cookie, "User-Agent": config.CONFIG.svc_user_agent, "Proxy-Connection": "keep-alive" } util.log_http(url, 'get', headers, sys._getframe().f_code.co_name) r = requests.get(url, headers=headers, cookies=auth.load_cookies(), verify=config.VERIFY_SSL) json_source = r.json() if json_source['status_code'] == 1: media_item = json_source['user_verified_event'][0][ 'user_verified_content'][0]['user_verified_media_item'][0] if media_item['blackout_status']['status'] == 'BlackedOutStatus': msg = ( 'The game you are trying to access is not currently available due to local ' 'or national blackout restrictions.\n' 'Full game archives will be available 48 hours after completion of this game.' ) util.die('Game Blacked Out: {}'.format(msg)) elif media_item['auth_status'] == 'NotAuthorizedStatus': msg = 'You do not have an active subscription. To access this content please purchase a subscription.' util.die('Account Not Authorized: {}'.format(msg)) else: stream_url = media_item['url'] media_auth = '{}={}'.format( str(json_source['session_info']['sessionAttributes'][0] ['attributeName']), str(json_source['session_info']['sessionAttributes'][0] ['attributeValue'])) session_key = json_source['session_key'] auth.update_session_key(session_key) else: msg = json_source['status_message'] util.die('Error Fetching Stream: {}', msg) LOG.debug('fetch_stream stream_url: ' + stream_url) LOG.debug('fetch_stream media_auth: ' + media_auth) return stream_url, media_auth