# -*- coding: utf-8 -*- import sys import re from datetime import datetime from textwrap import wrap from wcwidth import wcswidth from toot.utils import format_content, get_text, parse_html from toot.wcstring import wc_wrap START_CODES = { 'red': '\033[31m', 'green': '\033[32m', 'yellow': '\033[33m', 'blue': '\033[34m', 'magenta': '\033[35m', 'cyan': '\033[36m', } END_CODE = '\033[0m' START_PATTERN = "<(" + "|".join(START_CODES.keys()) + ")>" END_PATTERN = "" def start_code(match): name = match.group(1) return START_CODES[name] def colorize(text): text = re.sub(START_PATTERN, start_code, text) text = re.sub(END_PATTERN, END_CODE, text) return text def strip_tags(text): text = re.sub(START_PATTERN, '', text) text = re.sub(END_PATTERN, '', text) return text USE_ANSI_COLOR = "--no-color" not in sys.argv QUIET = "--quiet" in sys.argv def print_out(*args, **kwargs): if not QUIET: args = [colorize(a) if USE_ANSI_COLOR else strip_tags(a) for a in args] print(*args, **kwargs) def print_err(*args, **kwargs): args = ["{}".format(a) for a in args] args = [colorize(a) if USE_ANSI_COLOR else strip_tags(a) for a in args] print(*args, file=sys.stderr, **kwargs) def print_instance(instance): print_out("{}".format(instance['title'])) print_out("{}".format(instance['uri'])) print_out("running Mastodon {}".format(instance['version'])) print_out("") description = instance['description'].strip() if not description: return lines = [line.strip() for line in format_content(description) if line.strip()] for line in lines: for l in wrap(line.strip()): print_out(l) print_out() def print_account(account): print_out("@{} {}".format(account['acct'], account['display_name'])) note = get_text(account['note']) if note: print_out("") print_out("\n".join(wrap(note))) print_out("") print_out("ID: {}".format(account['id'])) print_out("Since: {}".format(account['created_at'][:19].replace('T', ' @ '))) print_out("") print_out("Followers: {}".format(account['followers_count'])) print_out("Following: {}".format(account['following_count'])) print_out("Statuses: {}".format(account['statuses_count'])) print_out("") print_out(account['url']) HASHTAG_PATTERN = re.compile(r'(?\\1', line) def print_search_results(results): accounts = results['accounts'] hashtags = results['hashtags'] if accounts: print_out("\nAccounts:") for account in accounts: print_out("* @{} {}".format( account['acct'], account['display_name'] )) if hashtags: print_out("\nHashtags:") print_out(", ".join(["#{}".format(t) for t in hashtags])) if not accounts and not hashtags: print_out("Nothing found") def print_status(status, width): reblog = status['reblog'] content = reblog['content'] if reblog else status['content'] media_attachments = reblog['media_attachments'] if reblog else status['media_attachments'] in_reply_to = status['in_reply_to_id'] time = status['created_at'] time = datetime.strptime(time, "%Y-%m-%dT%H:%M:%S.%fZ") time = time.strftime('%Y-%m-%d %H:%M%z') username = "@" + status['account']['acct'] spacing = width - wcswidth(username) - wcswidth(time) display_name = status['account']['display_name'] if display_name: spacing -= wcswidth(display_name) + 1 print_out("{}{}{}{}".format( "{} ".format(display_name) if display_name else "", "{}".format(username), " " * spacing, "{}".format(time), )) for paragraph in parse_html(content): print_out("") for line in paragraph: for subline in wc_wrap(line, width): print_out(highlight_hashtags(subline)) if media_attachments: print_out("\nMedia:") for attachment in media_attachments: url = attachment['text_url'] or attachment['url'] for line in wc_wrap(url, width): print_out(line) print_out("\n{}{}{}".format( "ID {} ".format(status['id']), "↲ In reply to {} ".format(in_reply_to) if in_reply_to else "", "↻ Reblogged @{} ".format(reblog['account']['acct']) if reblog else "", )) def print_timeline(items, width=100): print_out("─" * width) for item in items: print_status(item, width) print_out("─" * width)