From 35e03a13b1f31baadbf56ed0f3378e42bd79aa01 Mon Sep 17 00:00:00 2001 From: Ivan Habunek Date: Sun, 22 Sep 2019 12:13:40 +0200 Subject: [PATCH] Simplify access to reblogged status data Adds two properties to `Status` entity: * `reblog` - contains the reblogged Status or None if not a reblog * `original`- contains the reblogged Status or self if not a reblog Anywhere where you wish to show a reblogged status's property when it's a reblog, or the base status proprety if not a reblog, use `status.original.`. --- toot/tui/app.py | 4 +-- toot/tui/entities.py | 72 +++++++++++++++++++++++++++++++------------- toot/tui/timeline.py | 34 +++++++++++++-------- 3 files changed, 75 insertions(+), 35 deletions(-) diff --git a/toot/tui/app.py b/toot/tui/app.py index d7aa3a2..74d34a2 100644 --- a/toot/tui/app.py +++ b/toot/tui/app.py @@ -226,7 +226,7 @@ class TUI(urwid.Frame): # This is pretty fast, so it's probably ok to block while context is # loaded, can be made async later if needed - context = api.context(self.app, self.user, status.id) + context = api.context(self.app, self.user, status.original.id) ancestors = [self.make_status(s) for s in context["ancestors"]] descendants = [self.make_status(s) for s in context["descendants"]] statuses = ancestors + [status] + descendants @@ -337,7 +337,7 @@ class TUI(urwid.Frame): promise.add_done_callback(lambda *args: self.close_overlay()) def show_media(self, status): - urls = [m["url"] for m in status.data["media_attachments"]] + urls = [m["url"] for m in status.original.data["media_attachments"]] if urls: show_media(urls) diff --git a/toot/tui/entities.py b/toot/tui/entities.py index 688ba65..207a7b3 100644 --- a/toot/tui/entities.py +++ b/toot/tui/entities.py @@ -2,7 +2,6 @@ from collections import namedtuple from .utils import parse_datetime - Author = namedtuple("Author", ["account", "display_name"]) @@ -11,8 +10,33 @@ class Status: A wrapper around the Status entity data fetched from Mastodon. https://github.com/tootsuite/documentation/blob/master/Using-the-API/API.md#status + + Attributes + ---------- + reblog : Status or None + The reblogged status if it exists. + + original : Status + If a reblog, the reblogged status, otherwise self. """ + def __init__(self, data, is_mine, default_instance): + """ + Parameters + ---------- + data : dict + Status data as received from Mastodon. + https://docs.joinmastodon.org/api/entities/#status + + is_mine : bool + Whether the status was created by the logged in user. + + default_instance : str + The domain of the instance into which the user is logged in. Used to + create fully qualified account names for users on the same instance. + Mastodon only populates the name, not the domain. + """ + self.data = data self.is_mine = is_mine self.default_instance = default_instance @@ -20,34 +44,40 @@ class Status: # This can be toggled by the user self.show_sensitive = False - # TODO: make Status immutable? - + # TODO: clean up self.id = self.data["id"] - self.display_name = self.data["account"]["display_name"] - self.account = self.get_account() + self.account = self._get_account() self.created_at = parse_datetime(data["created_at"]) - self.author = self.get_author() + self.author = self._get_author() self.favourited = data.get("favourited", False) self.reblogged = data.get("reblogged", False) self.in_reply_to = data.get("in_reply_to_id") + self.url = data.get("url") + self.mentions = data.get("mentions") + self.reblog = self._get_reblog() - self.reblog = reblog = data.get("reblog") - self.url = reblog.get("url") if reblog else data.get("url") + @property + def original(self): + return self.reblog or self - self.mentions = data["mentions"] - - def get_author(self): - # Show the author, not the persopn who reblogged - data = self.data["reblog"] or self.data - acct = data['account']['acct'] - acct = acct if "@" in acct else "{}@{}".format(acct, self.default_instance) - return Author(acct, data['account']['display_name']) - - def get_account(self): + def _get_reblog(self): reblog = self.data.get("reblog") - account = reblog['account'] if reblog else self.data['account'] - acct = account['acct'] + if not reblog: + return None + + reblog_is_mine = self.is_mine and ( + self.data["account"]["acct"] == reblog["account"]["acct"] + ) + return Status(reblog, reblog_is_mine, self.default_instance) + + def _get_author(self): + acct = self.data['account']['acct'] + acct = acct if "@" in acct else "{}@{}".format(acct, self.default_instance) + return Author(acct, self.data['account']['display_name']) + + def _get_account(self): + acct = self.data['account']['acct'] return acct if "@" in acct else "{}@{}".format(acct, self.default_instance) def __repr__(self): - return "".format(self.id) + return "".format(self.id, self.account) diff --git a/toot/tui/timeline.py b/toot/tui/timeline.py index 5595150..2ad1051 100644 --- a/toot/tui/timeline.py +++ b/toot/tui/timeline.py @@ -136,7 +136,7 @@ class Timeline(urwid.Columns): return if key in ("s", "S"): - status.show_sensitive = True + status.original.show_sensitive = True self.refresh_status_details() return @@ -149,8 +149,8 @@ class Timeline(urwid.Columns): return if key in ("v", "V"): - if status.url: - webbrowser.open(status.url) + if status.original.url: + webbrowser.open(status.original.url) return return super().keypress(size, key) @@ -204,14 +204,24 @@ class Timeline(urwid.Columns): class StatusDetails(urwid.Pile): def __init__(self, status, in_thread): + """ + Parameters + ---------- + status : Status + The status to render. + + in_thread : bool + Whether the status is rendered from a thread status list. + """ self.in_thread = in_thread - widget_list = list(self.content_generator(status)) + reblogged_by = status.author if status.reblog else None + widget_list = list(self.content_generator(status.original, reblogged_by)) return super().__init__(widget_list) - def content_generator(self, status): - if status.data["reblog"]: - boosted_by = status.data["account"]["display_name"] - yield ("pack", urwid.Text(("gray", "♺ {} boosted".format(boosted_by)))) + def content_generator(self, status, reblogged_by): + if reblogged_by: + text = "♺ {} boosted".format(reblogged_by.display_name) + yield ("pack", urwid.Text(("gray", text))) yield ("pack", urwid.AttrMap(urwid.Divider("-"), "gray")) if status.author.display_name: @@ -315,10 +325,10 @@ class StatusDetails(urwid.Pile): class StatusListItem(SelectableColumns): def __init__(self, status): created_at = status.created_at.strftime("%Y-%m-%d %H:%M") - favourited = ("yellow", "★") if status.favourited else " " - reblogged = ("yellow", "♺") if status.reblogged else " " + favourited = ("yellow", "★") if status.original.favourited else " " + reblogged = ("yellow", "♺") if status.original.reblogged else " " is_reblog = ("cyan", "♺") if status.reblog else " " - is_reply = ("cyan", "⤶") if status.in_reply_to else " " + is_reply = ("cyan", "⤶") if status.original.in_reply_to else " " return super().__init__([ ("pack", SelectableText(("blue", created_at), wrap="clip")), @@ -327,7 +337,7 @@ class StatusListItem(SelectableColumns): ("pack", urwid.Text(" ")), ("pack", urwid.Text(reblogged)), ("pack", urwid.Text(" ")), - urwid.Text(("green", status.account), wrap="clip"), + urwid.Text(("green", status.original.account), wrap="clip"), ("pack", urwid.Text(is_reply)), ("pack", urwid.Text(is_reblog)), ("pack", urwid.Text(" ")),