This commit is contained in:
cyisfor 2020-06-01 06:05:19 +00:00 committed by GitHub
commit efd0bab0c3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 157 additions and 65 deletions

View File

@ -255,3 +255,10 @@ div.poll {
{
margin-top: 0;
}
li {
margin-top: 0.1vh;
}
ul {
padding-left: 2vw;
}

View File

@ -18,14 +18,20 @@ mastodon.status_context(<numerical id>)
<h1 id="title" class="title">
Thread
</h1>
{% include "main/toot_partial.html" with toot=root %}
{% for descendant in descendants %}
{% if descendant == toot %}
{% include "main/toot_partial.html" with toot=toot active=True %}
{% else %}
{% include "main/toot_partial.html" with toot=descendant %}
{% endif %}
<hr class="is-hidden">
{% for op in toots %}
{% if op == IN %}
<ul>
{% elif op == OUT %}
</ul>
{% else %}
<li>
{% if op.toot == toot %}
{% include "main/toot_partial.html" with toot=op.toot active=True %}
{% else %}
{% include "main/toot_partial.html" with toot=op.toot %}
{% endif %}
</li>
{% endif %}
{% endfor %}
{% if not preferences.no_javascript %}

77
brutaldon/threadtree.py Normal file
View File

@ -0,0 +1,77 @@
from pprint import pprint
def maketree(mastodon, root, descendants):
lookup = dict((descendant.id, descendant) for descendant in descendants)
lookup[root.id] = root
replies = {}
roots = set([root.id])
def lookup_or_fetch(id):
if not id in lookup:
lookup[id] = mastodon.status(id)
return lookup[id]
def getreps(id):
if id in replies:
reps = replies[id]
else:
reps = set()
replies[id] = reps
return reps
for descendant in descendants:
if not descendant.in_reply_to_id:
roots.add(descendant.id)
print("ROOT", descendant.id, descendant.account.id, descendant.account.acct)
else:
reps = getreps(descendant.in_reply_to_id)
reps.add(descendant.id)
reps = getreps(descendant.in_reply_to_account_id)
reps.add(descendant.id)
print("REPLY", descendant.id,
descendant.in_reply_to_id,
descendant.in_reply_to_account_id)
seen = set()
def onelevel(reps):
for rep in sorted(reps):
if rep in seen: continue
seen.add(rep)
subreps = replies.get(rep)
if subreps:
yield lookup_or_fetch(rep), onelevel(subreps)
else:
yield lookup_or_fetch(rep), ()
def leftovers():
for leftover in set(lookup.keys()) - seen:
yield lookup_or_fetch(leftover)
return onelevel(roots), leftovers
# returns (status, gen[(status, gen[(status, ...), (status, ())]), ...])
# django can't do recursion well so we'll turn the tree
# ((A, (B, C)))
# into
# (in, in, A, in, B, C, out, out, out)
IN = 0
OUT = 1
class TOOT:
toot = None
def __init__(self, toot):
self.toot = toot
def unmaketree(tree):
for toot, children in tree:
yield TOOT(toot)
if children:
yield IN
yield from unmaketree(children)
yield OUT
def build(mastodon, root, descendants):
tree, leftover = maketree(mastodon, root, descendants)
yield IN
yield from unmaketree(tree)
yield OUT
yield IN
leftover = tuple(leftover())
for toot in leftover:
yield TOOT(toot)
yield OUT

View File

@ -16,6 +16,7 @@ from brutaldon.forms import (
from brutaldon.models import Client, Account, Preference, Theme
from mastodon import (
Mastodon,
MastodonIllegalArgumentError,
AttribAccessDict,
MastodonError,
MastodonAPIError,
@ -71,7 +72,7 @@ def get_session(domain):
return s
def get_usercontext(request):
def get_usercontext(request, feature_set="mainline"):
if is_logged_in(request):
try:
client = Client.objects.get(api_base_id=request.session["active_instance"])
@ -90,6 +91,7 @@ def get_usercontext(request):
api_base_url=client.api_base_id,
session=get_session(client.api_base_id),
ratelimit_method="throw",
feature_set=feature_set
)
return user, mastodon
else:
@ -669,6 +671,7 @@ def note(request, next=None, prev=None):
},
)
from . import threadtree
@br_login_required
def thread(request, id):
@ -685,22 +688,23 @@ def thread(request, id):
notifications = _notes_count(account, mastodon)
filters = get_filters(mastodon, context="thread")
# Apply filters
descendants = [
x for x in context.descendants if not toot_matches_filters(x, filters)
]
# # Apply filters
# descendants = [
# x for x in context.descendants if not toot_matches_filters(x, filters)
# ]
toots = tuple(threadtree.build(mastodon, root, context.descendants))
return render(
request,
"main/thread.html",
{
"context": context,
"toot": toot,
"root": root,
"descendants": descendants,
"toots": toots,
"own_acct": request.session["active_user"],
"notifications": notifications,
"preferences": account.preferences,
"IN": threadtree.IN,
"OUT": threadtree.OUT,
},
)
@ -808,6 +812,27 @@ def settings(request):
{"form": form, "account": account, "preferences": account.preferences},
)
def status_post(account, request, mastodon, **kw):
while True:
try:
mastodon.status_post(**kw)
except MastodonIllegalArgumentError as e:
if not 'is only available with feature set' in e.args[0]:
raise
feature_set = e.args[0].rsplit(" ",1)[-1]
account, mastodon = get_usercontext(request,
feature_set=feature_set)
continue
except TypeError:
# not sure why, but the old code retried status_post without a
# content_type keyword, if there was a TypeError
kw.pop("content_type")
continue
else:
break
return account, mastodon
@never_cache
@br_login_required
@ -864,26 +889,19 @@ def toot(request, mention=None):
),
)
)
if form.cleaned_data["visibility"] == "":
form.cleaned_data["visibility"] = request.session[
"active_user"
].source.privacy
try:
try:
mastodon.status_post(
status=form.cleaned_data["status"],
visibility=form.cleaned_data["visibility"],
spoiler_text=form.cleaned_data["spoiler_text"],
media_ids=media_objects,
content_type="text/markdown",
)
except TypeError:
mastodon.status_post(
status=form.cleaned_data["status"],
visibility=form.cleaned_data["visibility"],
spoiler_text=form.cleaned_data["spoiler_text"],
media_ids=media_objects,
)
status_post(
account, request, mastodon,
status=form.cleaned_data["status"],
visibility=form.cleaned_data["visibility"],
spoiler_text=form.cleaned_data["spoiler_text"],
media_ids=media_objects,
content_type="text/markdown")
except MastodonAPIError as error:
form.add_error(
"",
@ -977,23 +995,15 @@ def redraft(request, id):
"active_user"
].source.privacy
try:
try:
mastodon.status_post(
status=form.cleaned_data["status"],
visibility=form.cleaned_data["visibility"],
spoiler_text=form.cleaned_data["spoiler_text"],
media_ids=media_objects,
in_reply_to_id=toot.in_reply_to_id,
content_type="text/markdown",
)
except TypeError:
mastodon.status_post(
status=form.cleaned_data["status"],
visibility=form.cleaned_data["visibility"],
spoiler_text=form.cleaned_data["spoiler_text"],
media_ids=media_objects,
in_reply_to_id=toot.in_reply_to_id,
)
status_post(
account, request, mastodon,
status=form.cleaned_data["status"],
visibility=form.cleaned_data["visibility"],
spoiler_text=form.cleaned_data["spoiler_text"],
media_ids=media_objects,
in_reply_to_id=toot.in_reply_to_id,
content_type="text/markdown",
)
mastodon.status_delete(id)
except MastodonAPIError as error:
form.add_error(
@ -1107,23 +1117,15 @@ def reply(request, id):
)
)
try:
try:
mastodon.status_post(
status=form.cleaned_data["status"],
visibility=form.cleaned_data["visibility"],
spoiler_text=form.cleaned_data["spoiler_text"],
media_ids=media_objects,
in_reply_to_id=id,
content_type="text/markdown",
)
except TypeError:
mastodon.status_post(
status=form.cleaned_data["status"],
visibility=form.cleaned_data["visibility"],
spoiler_text=form.cleaned_data["spoiler_text"],
media_ids=media_objects,
in_reply_to_id=id,
)
status_post(
account, request, mastodon,
status=form.cleaned_data["status"],
visibility=form.cleaned_data["visibility"],
spoiler_text=form.cleaned_data["spoiler_text"],
media_ids=media_objects,
in_reply_to_id=id,
content_type="text/markdown",
)
except MastodonAPIError as error:
form.add_error(
"",