示例#1
0
文件: cli.py 项目: ryukinix/mal
def main():
    parser = create_parser()
    # Parse arguments
    if len(sys.argv) <= 1:
        args = parser.parse_args(['-h'])
    else:
        args = parser.parse_args()

    if args.version:
        print(mal.__version__)
        sys.exit(0)

    # if the command is login, create credentials and exits
    # NOTE: if this statement is removed the `mal login` and
    # no credentials exists, login.create_credentials() will
    # be called twice! On login.get_credentials and args.func(mal, args)
    if args.command == 'login':
        login.create_credentials()
        sys.exit(0)

    # Check if authorized
    config = login.get_credentials()
    if config['config']['animation'].lower() == 'false':
        decorating.animated.enabled = False

    mal_api = MyAnimeList.login(config)
    if not mal_api:
        print(color.colorize('Invalid credentials! :(', 'red', 'bold'))
        print(color.colorize('Tip: Try "mal login" again :D', 'white', 'bold'))
        sys.exit(1)

    # Execute sub command
    args.func(mal_api, args)
示例#2
0
文件: cli.py 项目: taktoa/mal
def main():
    parser = create_parser()
    # Parse arguments
    if len(sys.argv) <= 1:
        args = parser.parse_args(['-h'])
    else:
        args = parser.parse_args()

    if args.version:
        print(mal.__version__)
        sys.exit(0)

    # if the command is login, create credentials and exits
    # NOTE: if this statement is removed the `mal login` and
    # no credentials exists, login.create_credentials() will
    # be called twice! On login.get_credentials and args.func(mal, args)
    if args.command == 'login':
        login.create_credentials()
        sys.exit(0)

    # Check if authorized
    config = login.get_credentials()
    if config['config']['animation'].lower() == 'false':
        decorating.animated.enabled = False

    mal_api = MyAnimeList.login(config)
    if not mal_api:
        print(color.colorize('Invalid credentials! :(', 'red', 'bold'))
        print(color.colorize('Tip: Try "mal login" again :D', 'white', 'bold'))
        sys.exit(1)

    # Execute sub command
    args.func(mal_api, args)
示例#3
0
def search(mal, regex, full=False):
    """Search the MAL database for an anime."""
    result = mal.search(regex)
    # if no results or only one was found we treat them special
    if len(result) == 0:
        print(color.colorize("No matches in MAL database ᕙ(⇀‸↼‶)ᕗ", 'red'))
        return
    if len(result) == 1: full = True # full info if only one anime was found

    lines = ["{index}: {title}", "  Episodes: {episodes}\tScore: {score}", "  Synopsis: {synopsis}"]
    extra_lines = ["  Start date: {start}\tEnd data: {end}", "  Status: {status}"]

    print("Found", color.colorize(str(len(result)), "cyan", "underline"), "animes:")
    for i, anime in enumerate(result):
        # replace tags and special html chars (like &mdash;) with actual characters
        synopsis = html.unescape(str(anime["synopsis"])).replace("<br />", "")
        if len(synopsis) > 70 and not full:
            synopsis = synopsis[:70] + "..."

        # this template/line stuff might need some refactoring
        template = {
            "index": str(i + 1),
            "title": color.colorize(anime["title"], "red", "bold"),
            "episodes": color.colorize(anime["episodes"], "white", "bold"),
            "score": color.score_color(float(anime["score"])),
            "synopsis": synopsis,
            "start": anime["start_date"] if anime["start_date"] != "0000-00-00" else "NA",
            "end": anime["end_date"] if anime["end_date"] != "0000-00-00" else "NA",
            "status": anime["status"]
        }
        print("\n".join(line.format_map(template) for line in lines))
        if full: print("\n".join(line.format_map(template) for line in extra_lines))
        print("\n")
示例#4
0
def print_error(error_name, status, reason):
    padding = (len(error_name) + 2) * ' '
    error = color.colorize(error_name, 'red', 'bold')
    status = color.colorize(status, 'cyan')
    print(('{error}: {status}\n'
           '{padding}{reason} ¯\_(ツ)_/¯'.format_map(locals())),
          file=sys.stderr)
示例#5
0
文件: core.py 项目: ryukinix/mal
def search(mal, regex, full=False):
    """Search the MAL database for an anime."""
    result = mal.search(regex)
    # if no results or only one was found we treat them special
    if len(result) == 0:
        print(color.colorize("No matches in MAL database ᕙ(⇀‸↼‶)ᕗ", 'red'))
        return
    if len(result) == 1: full = True # full info if only one anime was found

    lines = ["{index}: {title}", "  Episodes: {episodes}\tScore: {score}", "  Synopsis: {synopsis}"]
    extra_lines = ["  Start date: {start}\tEnd data: {end}", "  Status: {status}"]

    print("Found", color.colorize(str(len(result)), "cyan", "underline"), "animes:")
    for i, anime in enumerate(result):
        # replace tags and special html chars (like &mdash;) with actual characters
        synopsis = html.unescape(str(anime["synopsis"])).replace("<br />", "")
        if len(synopsis) > 70 and not full:
            synopsis = synopsis[:70] + "..."

        # this template/line stuff might need some refactoring
        template = {
            "index": str(i + 1),
            "title": color.colorize(anime["title"], "red", "bold"),
            "episodes": color.colorize(anime["episodes"], "white", "bold"),
            "score": color.score_color(float(anime["score"])),
            "synopsis": synopsis,
            "start": anime["start_date"] if anime["start_date"] != "0000-00-00" else "NA",
            "end": anime["end_date"] if anime["end_date"] != "0000-00-00" else "NA",
            "status": anime["status"]
        }
        print("\n".join(line.format_map(template) for line in lines))
        if full: print("\n".join(line.format_map(template) for line in extra_lines))
        print("\n")
示例#6
0
文件: utils.py 项目: xxami/mal
def print_error(error_name, status, reason, kill=False):
    padding = (len(error_name) + 2) * ' '
    error = color.colorize(error_name, 'red', 'bold')
    status = color.colorize(status, 'cyan')
    print(('{error}: {status}\n'
           '{padding}{reason} ¯\_(ツ)_/¯'.format_map(locals())),
          file=sys.stderr)
    if kill:
        os._exit(1)
示例#7
0
def drop(mal, regex):
    """Drop a anime based a regex expression"""
    items = remove_completed(mal.find(regex))
    item = select_item(items)
    entry = dict(status=mal.status_codes['dropped'])
    old_status = mal.status_names[item['status']]
    template = {
        'title': color.colorize(item['title'], 'yellow', 'bold'),
        'old-status': color.colorize(old_status, 'green', 'bold'),
        'action': color.colorize('Dropping', 'red', 'bold')
    }

    print(('{action} anime {title} from list '
           '{old-status}'.format_map(template)))
    response = mal.update(item['id'], entry)
    report_if_fails(response)
示例#8
0
文件: core.py 项目: ryukinix/mal
def drop(mal, regex):
    """Drop a anime based a regex expression"""
    items = remove_completed(mal.find(regex))
    item = select_item(items)
    entry = dict(status=mal.status_codes['dropped'])
    old_status = mal.status_names[item['status']]
    template = {
        'title': color.colorize(item['title'], 'yellow', 'bold'),
        'old-status': color.colorize(old_status, 'green', 'bold'),
        'action': color.colorize('Dropping', 'red', 'bold')

    }

    print(('{action} anime {title} from list '
           '{old-status}'.format_map(template)))
    response = mal.update(item['id'], entry)
    report_if_fails(response)
示例#9
0
def select_item(items):
    """Select a single item from a list of results."""
    item = None
    if len(items) > 1:  # ambigious search results
        print(color.colorize('Multiple results:', 'cyan'))
        # show user the results and make them choose one
        for index, title in enumerate(map(itemgetter('title'), items)):
            print('{index}: {title}'.format_map(locals()))
        index = int(input('Which one? '))
        item = items[index]
    elif len(items) == 1:
        item = items[0]
    else:
        print(color.colorize("No matches in list ᕙ(⇀‸↼‶)ᕗ", 'red'))
        sys.exit(1)

    return item
示例#10
0
文件: core.py 项目: ryukinix/mal
def select_item(items):
    """Select a single item from a list of results."""
    item = None
    if len(items) > 1:  # ambigious search results
        print(color.colorize('Multiple results:', 'cyan'))
        # show user the results and make them choose one
        for index, title in enumerate(map(itemgetter('title'), items)):
            print('{index}: {title}'.format_map(locals()))
        index = int(input('Which one? '))
        item = items[index]
    elif len(items) == 1:
        item = items[0]
    else:
        print(color.colorize("No matches in list ᕙ(⇀‸↼‶)ᕗ", 'red'))
        sys.exit(1)

    return item
示例#11
0
def progress_update(mal, regex, inc):
    items = remove_completed(mal.find(regex))
    item = select_item(items)  # also handles ambigious searches
    episode = item['episode'] + inc
    entry = dict(episode=episode, score=item.get('score', 0))
    template = {
        'title': color.colorize(item['title'], 'yellow', 'bold'),
        'episode': color.colorize(episode, 'red' if inc < 1 else 'green'),
        'total_episodes': color.colorize(item['total_episodes'], 'cyan'),
        'procedure': color.procedure_color(inc)
    }

    print(('{procedure} progress for {title} to '
           '{episode}/{total_episodes}'.format_map(template)))

    entry = start_end(entry, episode, item['total_episodes'])
    response = mal.update(item['id'], entry)
    report_if_fails(response)
示例#12
0
文件: core.py 项目: ryukinix/mal
def progress_update(mal, regex, inc):
    items = remove_completed(mal.find(regex))
    item = select_item(items)  # also handles ambigious searches
    episode = item['episode'] + inc
    entry = dict(episode=episode, score=item.get('score', 0))
    template = {
        'title': color.colorize(item['title'], 'yellow', 'bold'),
        'episode': color.colorize(episode, 'red' if inc < 1 else 'green'),
        'total_episodes': color.colorize(item['total_episodes'], 'cyan'),
        'procedure': color.procedure_color(inc)
    }

    print(('{procedure} progress for {title} to '
           '{episode}/{total_episodes}'.format_map(template)))

    entry = start_end(entry, episode, item['total_episodes'])
    response = mal.update(item['id'], entry)
    report_if_fails(response)
示例#13
0
def find(mal, regex, filtering='all', extra=False, user=None):
    """Find all anime in a certain status given a regex."""
    items = mal.find(regex, extra=extra, user=user)
    if len(items) == 0:
        print(color.colorize("No matches in list ᕙ(⇀‸↼‶)ᕗ", 'red'))
        return

    # filter the results if necessary
    if filtering != 'all':
        items = [x for x in items if x['status_name'] == filtering]

    n_items = color.colorize(str(len(items)), 'cyan', 'underline')
    print("Matched {} items:".format(n_items))

    # pretty print all the animes found
    sorted_items = sorted(items, key=itemgetter('status'), reverse=True)
    for index, item in enumerate(sorted_items):
        anime_pprint(index + 1, item, extra=extra)
示例#14
0
文件: core.py 项目: ryukinix/mal
def find(mal, regex, filtering='all', extra=False, user=None):
    """Find all anime in a certain status given a regex."""
    items = mal.find(regex, extra=extra, user=user)
    if len(items) == 0:
        print(color.colorize("No matches in list ᕙ(⇀‸↼‶)ᕗ", 'red'))
        return

    # filter the results if necessary
    if filtering != 'all':
        items = [x for x in items if x['status_name'] == filtering]

    n_items = color.colorize(str(len(items)), 'cyan', 'underline')
    print("Matched {} items:".format(n_items))

    # pretty print all the animes found
    sorted_items = sorted(items, key=itemgetter('status'), reverse=True)
    for index, item in enumerate(sorted_items):
        anime_pprint(index + 1, item, extra=extra)
示例#15
0
def anime_pprint(index, item, extra=False):
    """Pretty print an anime's information."""
    padding = int(math.log10(index)) + 3
    remaining_color = ('blue' if item['episode'] < item['total_episodes'] else
                       'green')
    remaining = '{episode}/{total_episodes}'.format_map(item)
    in_rewatching = ('#in-rewatching-{rewatching}'.format_map(item)
                     if item['rewatching'] else '')
    template = {
        'index': index,
        'padding': ' ' * padding,
        'status': MyAnimeList.status_names[item['status']].capitalize(),
        'title': color.colorize(item['title'], 'red', 'bold'),
        'remaining': color.colorize(remaining, remaining_color, 'bold'),
        'score': color.score_color(item['score']),
        'rewatching': (color.colorize(in_rewatching, 'yellow', 'bold'))
    }
    # add formating options for extra info
    if extra:
        template.update({
            'start':
            item['start_date'] if item['start_date'] != '0000-00-00' else 'NA',
            'finish':
            item['finish_date']
            if item['finish_date'] != '0000-00-00' else 'NA',
            'tags':
            item['tags']
        })

    message_lines = [
        "{index}: {title}".format_map(template),
        ("{padding}{status} at {remaining} episodes "
         "with score {score} {rewatching}".format_map(template))
    ]

    # the extra information lines
    if extra:
        message_lines.extend([
            "{padding}Started: {start} \t Finished: {finish}".format_map(
                template), "{padding}Tags: {tags}".format_map(template)
        ])

    print('\n'.join(message_lines), "\n")
示例#16
0
def add(mal, regex, status="plan to watch"):
    """Add an entry to the user list."""
    results = mal.search(regex)
    selected = select_item(results)

    print("Adding {title} to list as '{status}'".format(title=color.colorize(
        selected["title"], "yellow", "bold"),
                                                        status=status))
    mal.update(selected["id"], {"status": mal.status_codes[status]},
               action="add")
示例#17
0
def spinner(control):
    animation = ''.join(x * 5 for x in animation_diagram)
    if not sys.stdout.isatty():  # not send to pipe/redirection
        return
    anim = zip(cycle(animation), cycle(animation_spinner))
    for n, start_end_anim in enumerate(anim):
        start, end = start_end_anim
        padding = '█' * int(20 * abs(sin(0.05 * (n + control.position))))
        padding_colored = color.colorize(padding, 'cyan')
        banner = '{} {} {}'.format(start, control.message, end)
        banner_colored = color.colorize(banner, 'cyan')
        message = '\r' + padding_colored + banner_colored
        sys.stdout.write(message)
        time.sleep(0.05)
        sys.stdout.write('\r' + len(message) * ' ')
        sys.stdout.write(2 * len(message) * "\010")
        if control.done:
            control.position = n
            break
    sys.stdout.write(len(message) * ' ')
    sys.stdout.write('\r' + 2 * len(message) * "\010")
示例#18
0
文件: core.py 项目: ryukinix/mal
def anime_pprint(index, item, extra=False):
    """Pretty print an anime's information."""
    padding = int(math.log10(index)) + 3
    remaining_color = ('blue' if item['episode'] < item['total_episodes']
                       else 'green')
    remaining = '{episode}/{total_episodes}'.format_map(item)
    in_rewatching = ('#in-rewatching-{rewatching}'.format_map(item)
                     if item['rewatching'] else '')
    template = {
        'index': index,
        'padding': ' ' * padding,
        'status': MyAnimeList.status_names[item['status']].capitalize(),
        'title': color.colorize(item['title'], 'red', 'bold'),
        'remaining': color.colorize(remaining, remaining_color, 'bold'),
        'score': color.score_color(item['score']),
        'rewatching': (color.colorize(in_rewatching, 'yellow', 'bold'))
    }
    # add formating options for extra info
    if extra:
        template.update({
            'start': item['start_date'] if item['start_date'] != '0000-00-00' else 'NA',
            'finish': item['finish_date'] if item['finish_date'] != '0000-00-00' else 'NA',
            'tags': item['tags']
        })

    message_lines = [
        "{index}: {title}".format_map(template),
        ("{padding}{status} at {remaining} episodes "
         "with score {score} {rewatching}".format_map(template))
    ]

    # the extra information lines
    if extra:
        message_lines.extend([
            "{padding}Started: {start} \t Finished: {finish}".format_map(template),
            "{padding}Tags: {tags}".format_map(template)
        ])

    print('\n'.join(message_lines), "\n")
示例#19
0
def start_end(entry, episode, total_episodes):
    """Fill details of anime if user just started it or finished it."""
    if total_episodes == episode:
        entry['status'] = MyAnimeList.status_codes['completed']
        entry['date_finish'] = date.today().strftime('%m%d%Y')
        print(color.colorize('Series completed!', 'green'))

        # set/change score
        user_score = input(
            'Enter new score (leave blank to keep score at {}): '.format(
                entry.get('score', 0))).strip()
        if user_score:  # do nothing if blank answer
            try:
                entry['score'] = int(user_score)
            except ValueError:
                print(color.colorize('Invalid score.', 'red'))

    elif episode == 1:
        entry['status'] = MyAnimeList.status_codes['watching']
        entry['date_start'] = date.today().strftime('%m%d%Y')

    return entry
示例#20
0
文件: login.py 项目: ryukinix/mal
def create_credentials():
    # logging messages
    login_header = color.colorize("-- MAL login", 'cyan')
    successful = color.colorize(':: valid credentials!', 'green')
    invalid = color.colorize(':: invalid credentials! try again', 'red')
    print(login_header)

    config = setup.config()
    if setup.LOGIN_SECTION not in config:
        config.add_section(setup.LOGIN_SECTION)
    config.set(setup.LOGIN_SECTION, 'username', input('Username: '******'password',  getpass())

    # confirm that account credentials are correct by trying to log in
    if MyAnimeList.login(config):
        # account is ok, create a config file
        with open(setup.CONFIG_PATH, 'w') as cfg:
            config.write(cfg)
            print(successful, 'saved in {}'.format(setup.CONFIG_PATH))
    else:
        print(invalid)
        config = create_credentials()
    return config
示例#21
0
文件: core.py 项目: ryukinix/mal
def add(mal, regex, status="plan to watch"):
    """Add an entry to the user list."""
    results = mal.search(regex)
    selected = select_item(results)

    print("Adding {title} to list as '{status}'".format(
        title=color.colorize(selected["title"], "yellow", "bold"),
        status=status)
    )
    mal.update(
        selected["id"],
        {"status": mal.status_codes[status]},
        action="add"
    )
示例#22
0
文件: core.py 项目: ryukinix/mal
def start_end(entry, episode, total_episodes):
    """Fill details of anime if user just started it or finished it."""
    if total_episodes == episode:
        entry['status'] = MyAnimeList.status_codes['completed']
        entry['date_finish'] = date.today().strftime('%m%d%Y')
        print(color.colorize('Series completed!', 'green'))

        # set/change score
        user_score = input(
            'Enter new score (leave blank to keep score at {}): '.format(
            entry.get('score', 0))
        ).strip()
        if user_score: # do nothing if blank answer
            try:
                entry['score'] = int(user_score)
            except ValueError:
                print(color.colorize('Invalid score.', 'red'))

    elif episode == 1:
        entry['status'] = MyAnimeList.status_codes['watching']
        entry['date_start'] = date.today().strftime('%m%d%Y')

    return entry
示例#23
0
def create_credentials():
    # logging messages
    login_header = color.colorize("-- MAL login", 'cyan')
    successful = color.colorize(':: valid credentials!', 'green')
    invalid = color.colorize(':: invalid credentials! try again', 'red')
    print(login_header)

    config = setup.config()
    if setup.LOGIN_SECTION not in config:
        config.add_section(setup.LOGIN_SECTION)
    config.set(setup.LOGIN_SECTION, 'username', input('Username: '******'password', getpass())

    # confirm that account credentials are correct by trying to log in
    if MyAnimeList.login(config):
        # account is ok, create a config file
        with open(setup.CONFIG_PATH, 'w') as cfg:
            config.write(cfg)
            print(successful, 'saved in {}'.format(setup.CONFIG_PATH))
    else:
        print(invalid)
        config = create_credentials()
    return config
示例#24
0
def start_end(entry, episode, total_episodes):
    """Fill details of anime if user just started it or finished it."""
    if total_episodes == episode:
        entry['status'] = MyAnimeList.status_codes['completed']
        entry['date_finish'] = date.today().strftime('%m%d%Y')
        print(color.colorize('Series completed!', 'green'))
        score = int(input('Enter a score (or 0 for no score): '))
        if score != 0:
            entry['score'] = score
    elif episode == 1:
        entry['status'] = MyAnimeList.status_codes['watching']
        entry['date_start'] = date.today().strftime('%m%d%Y')

    return entry
示例#25
0
文件: utils.py 项目: xxami/mal
def killed():
    """Show a message if user terminated the program."""
    message = ("\n ┑( ̄Д  ̄)┍ somebody seems killed me..."
               "\nw a s  Y O U ?! ︵ヽ(`Д´)ノ︵ ")
    print(color.colorize(message, 'red'), file=sys.stderr)
    os._exit(1)
示例#26
0
文件: core.py 项目: ryukinix/mal
 def point_color(color_name):
     return color.colorize("● ", color_name, "bold")
示例#27
0
文件: core.py 项目: ryukinix/mal
def stats(mal, username=None):
    """Print user anime stats."""
    # get all the info
    animes = mal.list(stats=True, user=username)
    if not animes:
        print_error("Empty query", "username not found",
                    "could not fetch list for user '{}'".format(username),
                    kill=True)
    user_info = animes.pop("stats")  # remove stats from anime list

    # gather all the numbers
    total_entries = len(animes)
    rewatched, episodes, mean_score, scored = 0, 0, 0, 0
    for anime in animes.values():
        episodes += anime["episode"]  # this is watched episodes
        if anime["rewatching"] != 0:
            rewatched += anime["rewatching"]
            # take into account episodes seen in previous watchings
            episodes += anime["rewatching"] * anime["total_episodes"]

        if anime["score"] != 0:
            scored += 1
        mean_score += anime["score"]

    if scored != 0:
        mean_score /= scored
    # added two for circle colored + space on each list
    line_size = 44 + 2
    # ↑ code for calculating this was so messy I hardcoded instead
    # it's 20 spaces for each of the 'sides' and 4 spaces in between them

    # colored bar. borrowed the bar char from neofetch
    bar = "█"
    colors = ["green", "blue", "yellow", "red", "gray"]
    lists = ["watching", "completed", "onhold", "dropped", "plantowatch"]
    colored = str()
    if total_entries != 0:  # to prevent division by zero
        for i, status in enumerate(lists):
            entries = int(user_info[status])
            bars = round(line_size * (entries / total_entries))
            colored += color.colorize(bar * bars, colors[i])
    else:
        colored = color.colorize(bar * line_size, "white")

    # format the lines to print more easily afterwards
    template = {
        "days": user_info["days_spent_watching"],
        "mean_score": "{:.2f}".format(mean_score),
        "watching": user_info["watching"],
        "completed": user_info["completed"],
        "hold": user_info["onhold"],
        "plan": user_info["plantowatch"],
        "dropped": user_info["dropped"],
        "total_entries": str(total_entries),
        "episodes": str(episodes),
        "rewatched": str(rewatched),
        "padd": "{p}"  # needed to format with padding afterwards
    }

    def point_color(color_name):
        return color.colorize("● ", color_name, "bold")

    lines = [
        "Days: {days}{padd}Mean Score: {mean_score}",
        colored,
        (point_color("green"),
            ["Watching:{padd}{watching}", "Total Entries:{padd}{total_entries}"]),
        (point_color("blue"),
            ["Completed:{padd}{completed}", "Rewatched:{padd}{rewatched}"]),
        (point_color("yellow"),
            ["On-Hold:{padd}{hold}", "Episodes:{padd}{episodes}"]),
        (point_color("red"), ["Dropped:{padd}{dropped}"]),
        (point_color("gray"), ["Plan to Watch:{padd}{plan}"])
    ]
    # add info to lines and format them to look nice
    def padd_str(string, final_size):
        return string.replace("{p}", " " * (final_size - len(string) + len("{p}")))

    lines = [
        padd_str(line.format_map(template), line_size) if not isinstance(line, tuple) else
        # first format each side, then add padding then join with the tab
        line[0] + (" " * 4).join(padd_str(side.format_map(template), 20) for side in line[1])
        for line in lines
    ]

    print(color.colorize("Anime Stats", "white", "underline"))
    print("\n".join(lines))
示例#28
0
def killed():
    message = ("\n ┑( ̄Д  ̄)┍ somebody seems killed me..."
               "\nw a s  Y O U ?! ︵ヽ(`Д´)ノ︵ ")
    print(color.colorize(message, 'red'), file=sys.stderr)
    os._exit(1)
示例#29
0
文件: core.py 项目: ryukinix/mal
def report_if_fails(response):
    if response != 200:
        print(color.colorize("Failed with HTTP: {}".format(response), 'red'))
示例#30
0
def report_if_fails(response):
    if response != 200:
        print(color.colorize("Failed with HTTP: {}".format(response), 'red'))
示例#31
0
 def point_color(color_name):
     return color.colorize("● ", color_name, "bold")
示例#32
0
def stats(mal, username=None):
    """Print user anime stats."""
    # get all the info
    animes = mal.list(stats=True, user=username)
    if not animes:
        print_error("Empty query",
                    "username not found",
                    "could not fetch list for user '{}'".format(username),
                    kill=True)
    user_info = animes.pop("stats")  # remove stats from anime list

    # gather all the numbers
    total_entries = len(animes)
    rewatched, episodes, mean_score, scored = 0, 0, 0, 0
    for anime in animes.values():
        episodes += anime["episode"]  # this is watched episodes
        if anime["rewatching"] != 0:
            rewatched += anime["rewatching"]
            # take into account episodes seen in previous watchings
            episodes += anime["rewatching"] * anime["total_episodes"]

        if anime["score"] != 0:
            scored += 1
        mean_score += anime["score"]

    if scored != 0:
        mean_score /= scored
    # added two for circle colored + space on each list
    line_size = 44 + 2
    # ↑ code for calculating this was so messy I hardcoded instead
    # it's 20 spaces for each of the 'sides' and 4 spaces in between them

    # colored bar. borrowed the bar char from neofetch
    bar = "█"
    colors = ["green", "blue", "yellow", "red", "gray"]
    lists = ["watching", "completed", "onhold", "dropped", "plantowatch"]
    colored = str()
    if total_entries != 0:  # to prevent division by zero
        for i, status in enumerate(lists):
            entries = int(user_info[status])
            bars = round(line_size * (entries / total_entries))
            colored += color.colorize(bar * bars, colors[i])
    else:
        colored = color.colorize(bar * line_size, "white")

    # format the lines to print more easily afterwards
    template = {
        "days": user_info["days_spent_watching"],
        "mean_score": "{:.2f}".format(mean_score),
        "watching": user_info["watching"],
        "completed": user_info["completed"],
        "hold": user_info["onhold"],
        "plan": user_info["plantowatch"],
        "dropped": user_info["dropped"],
        "total_entries": str(total_entries),
        "episodes": str(episodes),
        "rewatched": str(rewatched),
        "padd": "{p}"  # needed to format with padding afterwards
    }

    def point_color(color_name):
        return color.colorize("● ", color_name, "bold")

    lines = [
        "Days: {days}{padd}Mean Score: {mean_score}", colored,
        (point_color("green"),
         ["Watching:{padd}{watching}", "Total Entries:{padd}{total_entries}"]),
        (point_color("blue"),
         ["Completed:{padd}{completed}", "Rewatched:{padd}{rewatched}"]),
        (point_color("yellow"),
         ["On-Hold:{padd}{hold}", "Episodes:{padd}{episodes}"]),
        (point_color("red"), ["Dropped:{padd}{dropped}"]),
        (point_color("gray"), ["Plan to Watch:{padd}{plan}"])
    ]

    # add info to lines and format them to look nice
    def padd_str(string, final_size):
        return string.replace("{p}",
                              " " * (final_size - len(string) + len("{p}")))

    lines = [
        padd_str(line.format_map(template), line_size)
        if not isinstance(line, tuple) else
        # first format each side, then add padding then join with the tab
        line[0] + (" " * 4).join(
            padd_str(side.format_map(template), 20) for side in line[1])
        for line in lines
    ]

    print(color.colorize("Anime Stats", "white", "underline"))
    print("\n".join(lines))
示例#33
0
#
#   Copyright © Manoel Vilela
#
#

import os
from configparser import ConfigParser
from getpass import getpass
from mal.api import MyAnimeList
from mal import color

DEFAULT_FILE = '~/.myanimelist.init'
DEFAULT_SECTION = 'mal'
DEFAULT_PATH = os.path.expanduser(DEFAULT_FILE)

LOGIN_HEADER = color.colorize("-- MAL login", 'cyan')
SUCCESSFUL = color.colorize(':: valid credentials!', 'green')
INVALID = color.colorize(':: invalid credentials! try again', 'red')


def get_credentials():
    config = ConfigParser()
    config.read(DEFAULT_PATH)
    if DEFAULT_SECTION not in config:
        config = create_credentials()

    return config[DEFAULT_SECTION]


def create_credentials():
    print(LOGIN_HEADER)
示例#34
0
文件: utils.py 项目: ryukinix/mal
def killed():
    """Show a message if user terminated the program."""
    message = ("\n ┑( ̄Д  ̄)┍ somebody seems killed me..."
               "\nw a s  Y O U ?! ︵ヽ(`Д´)ノ︵ ")
    print(color.colorize(message, 'red'), file=sys.stderr)
    os._exit(1)