From 5297430483c328579d664cd92e9726a311880c97 Mon Sep 17 00:00:00 2001 From: Ivan Habunek Date: Thu, 13 Apr 2017 13:14:01 +0200 Subject: [PATCH] Add a simple timeline command --- setup.py | 3 ++- toot/__init__.py | 30 ++++++++++++++++++---- toot/console.py | 66 +++++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 90 insertions(+), 9 deletions(-) diff --git a/setup.py b/setup.py index e50f805..4e6a8af 100644 --- a/setup.py +++ b/setup.py @@ -30,7 +30,8 @@ setup( packages=['toot'], install_requires=[ 'requests ~= 2.13', - 'future' + 'beautifulsoup4 ~= 4.5.3', + 'future', ], entry_points={ 'console_scripts': [ diff --git a/toot/__init__.py b/toot/__init__.py index 50fdec8..06ef87f 100644 --- a/toot/__init__.py +++ b/toot/__init__.py @@ -9,6 +9,26 @@ APP_NAME = 'toot' DEFAULT_INSTANCE = 'mastodon.social' +def _get(app, user, url, params=None): + url = app.base_url + url + headers = {"Authorization": "Bearer " + user.access_token} + + response = requests.get(url, params, headers=headers) + response.raise_for_status() + + return response.json() + + +def _post(app, user, url, data=None): + url = app.base_url + url + headers = {"Authorization": "Bearer " + user.access_token} + + response = requests.post(url, data, headers=headers) + response.raise_for_status() + + return response.json() + + def create_app(base_url): url = base_url + '/api/v1/apps' @@ -49,10 +69,10 @@ def login(app, username, password): def post_status(app, user, status): - url = app.base_url + '/api/v1/statuses' - headers = {"Authorization": "Bearer " + user.access_token} + return _post(app, user, '/api/v1/statuses', { + 'status': status + }) - response = requests.post(url, {'status': status}, headers=headers) - response.raise_for_status() - return response.json() +def timeline_home(app, user): + return _get(app, user, '/api/v1/timelines/home') diff --git a/toot/console.py b/toot/console.py index 6281a33..35f9236 100644 --- a/toot/console.py +++ b/toot/console.py @@ -1,11 +1,16 @@ import os import sys +from bs4 import BeautifulSoup from builtins import input +from datetime import datetime from getpass import getpass +from itertools import chain +from textwrap import TextWrapper +from future.moves.itertools import zip_longest from .config import save_user, load_user, load_app, save_app, CONFIG_APP_FILE, CONFIG_USER_FILE -from . import create_app, login, post_status, DEFAULT_INSTANCE +from . import create_app, login, post_status, timeline_home, DEFAULT_INSTANCE def green(text): @@ -51,10 +56,62 @@ def print_usage(): print("") print("Usage:") print(" toot post \"All your base are belong to us\"") + print(" toot timeline") print("") print("https://github.com/ihabunek/toot") +def print_timeline(item): + def wrap_text(text, width): + wrapper = TextWrapper(width=width, break_long_words=False, break_on_hyphens=False) + return chain(*[wrapper.wrap(l) for l in text.split("\n")]) + + def timeline_rows(item): + name = item['name'] + time = item['time'].strftime('%Y-%m-%d %H:%M%Z') + + left_column = [name, time] + if 'reblogged' in item: + left_column.append(item['reblogged']) + + text = item['text'] + + right_column = wrap_text(text, 80) + + return zip_longest(left_column, right_column, fillvalue="") + + for left, right in timeline_rows(item): + print("{:30} │ {}".format(left, right)) + + +def parse_timeline(item): + content = item['reblog']['content'] if item['reblog'] else item['content'] + reblogged = item['reblog']['account']['username'] if item['reblog'] else "" + + name = item['account']['display_name'] + " @" + item['account']['username'] + soup = BeautifulSoup(content, "html.parser") + text = soup.get_text().replace(''', "'") + time = datetime.strptime(item['created_at'], "%Y-%m-%dT%H:%M:%S.%fZ") + + return { + # "username": item['account']['username'], + "name": name, + "text": text, + "time": time, + "reblogged": reblogged, + } + + +def cmd_timeline(app, user): + items = timeline_home(app, user) + parsed_items = [parse_timeline(t) for t in items] + + print("─" * 31 + "┬" + "─" * 88) + for item in parsed_items: + print_timeline(item) + print("─" * 31 + "┼" + "─" * 88) + + def cmd_post_status(app, user): if len(sys.argv) < 3: print(red("No status text given")) @@ -67,9 +124,10 @@ def cmd_post_status(app, user): def cmd_auth(app, user): if app and user: - print("You are logged in") - print("Mastodon instance: " + green(app.base_url)) + print("You are logged in to " + green(app.base_url)) print("Username: " + green(user.username)) + print("App data: " + green(CONFIG_APP_FILE)) + print("User data: " + green(CONFIG_USER_FILE)) else: print("You are not logged in") @@ -88,5 +146,7 @@ def main(): cmd_post_status(app, user) elif command == 'auth': cmd_auth(app, user) + elif command == 'timeline': + cmd_timeline(app, user) else: print_usage()