social media crossposting tool. 3rd time's the charm
mastodon
misskey
crossposting
bluesky
1from typing import Any, override
2import cross.fragments as f
3from util.splitter import FragmentSplitter, canonical_label
4
5LINK = 'app.bsky.richtext.facet#link'
6TAG = 'app.bsky.richtext.facet#tag'
7MENTION = "app.bsky.richtext.facet#mention"
8
9class BskySplitter(FragmentSplitter):
10 def __init__(self):
11 super().__init__(300, 30)
12
13 @override
14 def normalize_link(self, label: str, url: str) -> str:
15 if canonical_label(label, url):
16 nlabel = url.split("://", 1)[1]
17 if len(nlabel) <= self.urllen:
18 return nlabel
19 return nlabel[: self.urllen - 1] + "…"
20 return label
21
22# TODO handle extending overlapping fragments somehow
23def parse_facets(
24 text: str,
25 facets: list[dict[str, Any]] | None
26) -> tuple[str, list[f.Fragment]]:
27 if not facets:
28 return text, []
29
30 btext = text.encode("utf-8")
31 nbytes = bytearray()
32 last_original_byte_index = 0
33 fragments: list[f.Fragment] = []
34
35 for facet in facets:
36 original_start: int = facet['index']['byteStart']
37 original_end: int = facet['index']['byteEnd']
38
39 if last_original_byte_index < original_start:
40 nbytes.extend(btext[last_original_byte_index:original_start])
41
42 fdict = {feat['$type']: feat for feat in facet.get('features', [])}
43
44 original_label_bytes = btext[original_start:original_end]
45 original_label_str = original_label_bytes.decode("utf-8")
46
47 nlabel_bytes = original_label_bytes
48
49 if LINK in fdict:
50 url: str = fdict.pop(LINK)['uri']
51 label = original_label_str
52
53 split = url.split("://", 1)
54 full_url = False
55 if len(split) > 1:
56 if split[1].startswith(label):
57 full_url = True
58 if label.endswith("...") and split[1].startswith(label[:-3]):
59 full_url = True
60
61 if full_url:
62 nlabel_bytes = url.encode("utf-8")
63
64 nstart = len(nbytes)
65 nbytes.extend(nlabel_bytes)
66 nend = len(nbytes)
67
68 fragments.append(f.LinkFragment(start=nstart, end=nend, url=url))
69 else:
70 nstart = len(nbytes)
71 nbytes.extend(nlabel_bytes)
72 nend = len(nbytes)
73
74 if TAG in fdict:
75 tag: str = fdict.pop(TAG)['tag']
76 fragments.append(f.TagFragment(start=nstart, end=nend, tag=tag))
77
78 if MENTION in fdict:
79 did: str = fdict.pop(MENTION)['did']
80 fragments.append(f.MentionFragment(start=nstart, end=nend, uri=did))
81
82 last_original_byte_index = original_end
83
84 if last_original_byte_index < len(btext):
85 nbytes.extend(btext[last_original_byte_index:])
86
87 return nbytes.decode("utf-8"), fragments