def display_game_data(self, game_date, game_records, filter, show_info): show_scores = config.CONFIG.parser.getboolean('scores') # might as well show linescore if show_info is given show_linescore = show_scores and (config.CONFIG.parser.getboolean('linescore') or config.CONFIG.parser.getboolean('boxscore') or show_info) show_boxscore = show_scores and config.CONFIG.parser.getboolean('boxscore') border = displayutil.Border(use_unicode=config.UNICODE) if game_records is None: # outl.append("No game data for {}".format(game_date)) LOG.info("No game data for {}".format(game_date)) # LOG.info("No game data to display") return outl = list() # holds list of strings for output # print header header = self._get_header(border, game_date, show_scores, show_linescore) outl.extend(header) games_displayed_count = 0 for game_pk in game_records: if gamedata.apply_filter(game_records[game_pk], filter, FILTERS) is not None: games_displayed_count += 1 outl.extend(self._display_game_details(header, game_pk, game_records[game_pk], show_linescore, show_boxscore, show_info, games_displayed_count)) if games_displayed_count > 0: for line in outl: print(line)
def main(argv=None): """Entry point for mlbv""" # using argparse (2.7+) https://docs.python.org/2/library/argparse.html parser = argparse.ArgumentParser(description=HELP_HEADER, epilog=HELP_FOOTER, formatter_class=argparse.RawDescriptionHelpFormatter) parser.add_argument("--init", action="store_true", help="Generates a config file using a combination of defaults plus prompting for MLB.tv credentials.") parser.add_argument("--usage", action="store_true", help="Display full usage help.") parser.add_argument("-d", "--date", help="Display games/standings for date. Format: yyyy-mm-dd") parser.add_argument("--days", type=int, default=1, help="Number of days to display") parser.add_argument("--tomorrow", action="store_true", help="Use tomorrow's date") parser.add_argument("--yesterday", action="store_true", help="Use yesterday's date") parser.add_argument("-t", "--team", help="Play selected game feed for team, one of: {}".format(mlbgamedata.TEAM_CODES)) parser.add_argument("--info", nargs='?', const='full', metavar='full|short', choices=('full', 'short'), help=("Show extended game information inline (articles/text). " "Default is 'full'. Use --info=short to show only summaries (exclude full articles). " "You can also set this option permanently in your config via: " "info_display_articles=true|false")) parser.add_argument("-f", "--feed", help=("Feed type, either a live/archive game feed or highlight feed " "(if available). Available feeds are shown in game list," "and have a short form and long form (see 'Feed identifiers' section below)")) parser.add_argument("-r", "--resolution", help=("Stream resolution for streamlink (overrides settting in config file). " "Choices: {}. Can also be a comma-separated list of values (no spaces), " "e.g 720p_alt,720p,540p").format(config.BANDWIDTH_CHOICES)) parser.add_argument("-i", "--inning", help=("Start live/archive stream from inning. Format: {t|b}{inning_num}. " "t|b: (optional) top or bottom, inning_num: inning number. " "e.g. '5' - start at 5th inning. 't5' start at top 5th. " "'b5' start at bottom 5th.")) parser.add_argument("--inning-offset", type=int, metavar='SECS', help="Override the inning offset time in seconds. Default=240 (4 minutes)") # TODO remove --from-start, in favour of --inning parser.add_argument("--from-start", action="store_true", help="Start live/archive stream from beginning") parser.add_argument("--favs", help=argparse.SUPPRESS) # help=("Favourite teams, a comma-separated list of favourite teams " "(normally specified in config file)")) parser.add_argument("-o", "--filter", nargs='?', const='favs', metavar='filtername|teams', help=("Filter output. Either a filter name (see --list-filters) or a comma-separated " "list of team codes, eg: 'tor.bos,wsh'. Default: favs")) parser.add_argument("--list-filters", action='store_true', help="List the built-in filters") parser.add_argument("-g", "--game", default='1', choices=('1', '2'), help="Select game number of double-header") parser.add_argument("-s", "--scores", action="store_true", help="Show scores (default off; overrides config file)") parser.add_argument("-n", "--no-scores", action="store_true", help="Do not show scores (default on; overrides config file)") parser.add_argument("-l", "--linescore", nargs='?', const='all', metavar='filter', help="Show linescores. Optional: specify a filter as per --filter option.") parser.add_argument("--boxscore", nargs='?', const='all', metavar='filter', help="Show boxscores. Optional: specify a filter as per --filter option.") parser.add_argument("--username", help=argparse.SUPPRESS) # help="MLB.tv username. Required for live/archived games.") parser.add_argument("--password", help=argparse.SUPPRESS) # help="MLB.tv password. Required for live/archived games.") parser.add_argument("--fetch", "--record", action="store_true", help="Save stream to file instead of playing") parser.add_argument("--wait", action="store_true", help=("Wait for game to start (live games only). Will block launching the player until game time. " "Useful when combined with the --fetch option.")) parser.add_argument("--standings", nargs='?', const='division', metavar='[category]', help=("Display standings. This option will display the selected standings category, then exit. " "'[category]' is one of: '" + ', '.join(standings.STANDINGS_OPTIONS) + "' [default: %(default)s]. " "The standings category can be shortened down to one character (all matching " "categories will be included), e.g. 'div'. " "Can be combined with -d/--date option to show standings for any given date.") ) parser.add_argument("--stats", nargs='?', const='team', metavar='[teamcode]', help=("Display stats. This option will display the selected stats category, then exit. " "Can be combined with -d/--date option to show stats for any given date.") ) parser.add_argument("--recaps", nargs='?', const='all', metavar='FILTER', help=("Play recaps for given teams. " "[FILTER] is an optional filter as per --filter option")) parser.add_argument("-v", "--verbose", action="store_true", help=argparse.SUPPRESS) # help="Increase output verbosity") parser.add_argument("-D", "--debug", action="store_true", help=argparse.SUPPRESS) # help="Turn on debug output") args = parser.parse_args() if args.usage: return display_usage() team_to_play = None feedtype = None if args.init: return config.Config.generate_config(args.username, args.password, "MLB.tv") # get our config config.CONFIG = config.Config(mlbconfig.DEFAULTS, args) # append log files if DEBUG is set (from top of file) util.init_logging(os.path.join(config.CONFIG.dir, os.path.splitext(os.path.basename(sys.argv[0]))[0] + '.log'), True) global LOG LOG = logging.getLogger(__name__) if args.info and args.info == 'short': config.CONFIG.parser['info_display_articles'] = 'false' if args.list_filters: print('List of built filters: ' + ', '.join(sorted(mlbgamedata.FILTERS.keys()))) return 0 if args.debug: config.CONFIG.parser['debug'] = 'true' if args.verbose: config.CONFIG.parser['verbose'] = 'true' if args.username: config.CONFIG.parser['username'] = args.username if args.password: config.CONFIG.parser['password'] = args.password if args.inning_offset is not None: config.CONFIG.parser['stream_start_offset_secs'] = str(args.inning_offset) if args.team: team_to_play = args.team.lower() if team_to_play not in mlbgamedata.TEAM_CODES: # Issue #4 all-star game has funky team codes LOG.warning('Unexpected team code: %s', team_to_play) if args.feed: feedtype = gamedata.convert_to_long_feedtype(args.feed.lower(), mlbgamedata.FEEDTYPE_MAP) if args.resolution: config.CONFIG.parser['resolution'] = args.resolution if args.scores: config.CONFIG.parser['scores'] = 'true' elif args.no_scores: config.CONFIG.parser['scores'] = 'false' if args.linescore: if args.linescore != 'all': config.CONFIG.parser['filter'] = args.linescore config.CONFIG.parser['linescore'] = 'true' if args.boxscore: if args.boxscore != 'all': config.CONFIG.parser['filter'] = args.boxscore config.CONFIG.parser['boxscore'] = 'true' if args.favs: config.CONFIG.parser['favs'] = args.favs if args.filter: config.CONFIG.parser['filter'] = args.filter if config.DEBUG: LOG.info(str(config.CONFIG)) else: LOG.debug(str(config.CONFIG)) if args.yesterday: args.date = datetime.strftime(datetime.today() - timedelta(days=1), "%Y-%m-%d") elif args.tomorrow: args.date = datetime.strftime(datetime.today() + timedelta(days=1), "%Y-%m-%d") elif args.date is None: args.date = datetime.strftime(datetime.today(), "%Y-%m-%d") if args.standings: standings.get_standings(args.standings, args.date, args.filter) return 0 if args.stats: # def get_team_stats(team_code, team_code_id_map, stats_option='all', date_str=None): stats.get_team_stats(args.stats, None, 'all', None) return 0 gamedata_retriever = mlbgamedata.GameDataRetriever() # retrieve all games for the dates given game_day_tuple_list = gamedata_retriever.process_game_data(args.date, args.days) if not team_to_play and not args.recaps: # nothing to play; display the games presenter = mlbgamedata.GameDatePresenter() displayed_count = 0 for game_date, game_records in game_day_tuple_list: presenter.display_game_data(game_date, game_records, args.filter, args.info) displayed_count += 1 if displayed_count < len(game_day_tuple_list): print('') return 0 # from this point we only care about first day in list if len(game_day_tuple_list) > 0: game_date, game_data = game_day_tuple_list[0] else: # nothing to stream return 0 if args.recaps: recap_teams = list() if args.recaps == 'all': for game_pk in game_data: # add the home team recap_teams.append(game_data[game_pk]['home']['abbrev']) else: for team in args.recaps.split(','): recap_teams.append(team.strip()) for game_pk in game_data: game_rec = gamedata.apply_filter(game_data[game_pk], args.filter) if game_rec and (game_rec['home']['abbrev'] in recap_teams or game_rec['away']['abbrev'] in recap_teams): if 'recap' in game_rec['feed']: LOG.info("Playing recap for %s at %s", game_rec['away']['abbrev'].upper(), game_rec['home']['abbrev'].upper()) game_num = 1 if game_rec['doubleHeader'] != 'N': game_num = game_rec['gameNumber'] stream_game_rec = mlbstream.get_game_rec(game_data, game_rec['home']['abbrev'], game_num) mlbstream.play_stream(stream_game_rec, game_rec['home']['abbrev'], 'recap', game_date, args.fetch, None, None, is_multi_highlight=True) else: LOG.info("No recap available for %s at %s", game_rec['away']['abbrev'].upper(), game_rec['home']['abbrev'].upper()) return 0 # LOG.info('Sorry, MLB.tv stream support is broken. You should switch to https://github.com/tonycpsu/streamglob') # return -1 game_rec = mlbstream.get_game_rec(game_data, team_to_play, args.game) if args.wait and not util.has_reached_time(game_rec['mlbdate']): LOG.info('Waiting for game to start. Local start time is %s', util.convert_time_to_local(game_rec['mlbdate'])) print('Use Ctrl-c to quit .', end='', flush=True) count = 0 while not util.has_reached_time(game_rec['mlbdate']): time.sleep(10) count += 1 if count % 6 == 0: print('.', end='', flush=True) # refresh the game data LOG.info('Game time. Refreshing game data after wait...') game_day_tuple_list = gamedata_retriever.process_game_data(args.date, 1) if len(game_day_tuple_list) > 0: game_date, game_data = game_day_tuple_list[0] else: LOG.error('Unexpected error: no game data found after refresh on wait') return 0 game_rec = mlbstream.get_game_rec(game_data, team_to_play, args.game) return mlbstream.play_stream(game_rec, team_to_play, feedtype, args.date, args.fetch, args.from_start, args.inning)