Add a simple timeline command - toot - Unnamed repository; edit this file 'desc… | |
Log | |
Files | |
Refs | |
LICENSE | |
--- | |
commit 5297430483c328579d664cd92e9726a311880c97 | |
parent 61a12d31babc8c67987a38bfbe6bb487a867288e | |
Author: Ivan Habunek <[email protected]> | |
Date: Thu, 13 Apr 2017 13:14:01 +0200 | |
Add a simple timeline command | |
Diffstat: | |
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 | |
@@ -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 | |
@@ -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 | |
@@ -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,… | |
-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_hy… | |
+ 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() |