Module for posting toots that summarise what's happening.
NOTE: You can have values like api_base_url, username, or cred_file
in the [post] section of the config file and they will
override the general options. I use that for testing, where I will fetch()
from one server, but post() to another so I don't muck-up people's timelines
with test toots.
post(config)
Expects the config. Uses that to infer where the analysis file and all
the other data is. Builds up the HTML for all the stuff we will post, then
calls post_toots() to do the posting.
Config Parameters Used
| Option |
Description |
post:galleryurl |
URL for the gallery to link in the output. |
mastoscore:top_n |
How many top toots we will be reporting |
post:tag_users |
Whether we tag users with an @ or not |
Parameters:
| Name |
Type |
Description |
Default |
config
|
ConfigParser
|
A ConfigParser object from the config module
|
required
|
Returns:
| Type |
Description |
int
|
Number of toots tooted. Also updates the analysis file with the URLs for
|
int
|
|
Source code in mastoscore/post.py
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224 | def post(config:ConfigParser) -> int:
"""
Expects the config. Uses that to infer where the analysis file and all
the other data is. Builds up the HTML for all the stuff we will post, then
calls post_toots() to do the posting.
## Config Parameters Used
| Option | Description |
| ------- | ------- |
| `post:galleryurl` | URL for the gallery to link in the output.
| `mastoscore:top_n` | How many top toots we will be reporting
| `post:tag_users` | Whether we tag users with an @ or not |
Args:
config: A ConfigParser object from the [config](module-config.md) module
Returns:
Number of toots tooted. Also updates the analysis file with the URLs for
the posts.
"""
debug = get_debug_level(config, "mastoscore")
top_n = config.getint("mastoscore", "top_n")
tag_users = config.getboolean("post", "tag_users")
gallery_url = config.get("post", "galleryurl", fallback=None)
logger = logging.getLogger(__name__)
logging.basicConfig(
format="%(asctime)s %(levelname)-8s %(message)s",
level=logging.ERROR,
datefmt="%H:%M:%S",
)
logger.setLevel(debug)
analysis = read_json(config, "analysis")
if not analysis:
logger.error("Couldn't open JSON file")
return 0
tootlist = []
text = analysis["preamble"]
text = (
text + "<ul>"
f"<li>{analysis['num_toots']}</li>"
f"<li>{analysis['most_toots']}</li>"
"</ul><p>Additional details are replies to this toot."
)
# Add gallery link if URL is configured
if gallery_url:
text += f' For stats from past watch parties, <a href="{gallery_url}">visit the gallery.</a>'
text += "</p>"
tootlist.append(text)
top = analysis["max_boosts"]
tag = "@" if tag_users else ""
text = f"<p>The top {top_n} boosted toots:</p><ol>"
for post in top:
text = (
text + f'<li><a href="{post["url"]}">This toot</a> from '
f'<a href="{post["account.url"]}">{post["account.display_name"]} '
f"({tag}{post['userid']})</a>"
f" had {post['reblogs_count']} boosts.</li>\n"
)
text = text + "</ol>"
tootlist.append(text)
# Now post about faves
top = analysis["max_faves"]
text = f"<p>The top {top_n} favourited toots:</p><ol>"
for post in top:
text = (
text + f'<li><a href="{post["url"]}">This toot</a> from '
f'<a href="{post["account.url"]}">{post["account.display_name"]} '
f"({tag}{post['userid']})</a>"
f" had {post['favourites_count']} favourites.</li>\n"
)
text = text + "</ol>"
tootlist.append(text)
# Now post about replies
top = analysis["max_replies"]
text = f"<p>The top {top_n} most-replied-to toots:</p><ol>"
for post in top:
text = (
text + f'<li><a href="{post["url"]}">This toot</a> from '
f'<a href="{post["account.url"]}">{post["account.display_name"]} '
f"({tag}{post['userid']})</a>"
f" had {post['replies_count']} replies.</li>\n"
)
text = text + "</ol>"
tootlist.append(text)
tootids = {}
tootids["tootlist"], post_urls = post_toots(config, tootlist)
# Save post URLs to data-{hashtag}-posts.json
# Use write_json to create new file (overwrites if exists)
write_json(config, "posts", {"text_posts": post_urls})
# This will open up the hashtag-results.json file and insert all the IDs for all
# the toots into it. That will be used in the blog and in the graph posting.
update_json(config, "analysis", tootids)
return len(tootlist)
|
post_all(config)
Post analysis results and graphs to Mastodon.
Combines post() and post_graphs() functionality.
Parameters:
| Name |
Type |
Description |
Default |
config
|
ConfigParser
|
ConfigParser object with all configuration
|
required
|
Returns:
Number of toots posted (text + graphs)
Source code in mastoscore/post.py
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257 | def post_all(config:ConfigParser) -> int:
"""
Post analysis results and graphs to Mastodon.
Combines post() and post_graphs() functionality.
Args:
config: ConfigParser object with all configuration
Returns:
Number of toots posted (text + graphs)
"""
logger = logging.getLogger(__name__)
# First post the analysis text
try:
text_count = post(config)
logger.info(f"Posted {text_count} text posts")
except Exception as e:
logger.error(f"Failed to post text: {e}")
raise
# Then post the graphs
try:
graph_count = post_graphs(config)
logger.info(f"Posted {graph_count} graph posts")
except Exception as e:
logger.error(f"Failed to post graphs: {e}")
# Don't raise - text posts already succeeded
graph_count = 0
return text_count + graph_count
|
post_toots(config, tootlist)
Given the config and list of toots, create a Tooter and toot them.
Config Parameters Used
| Option |
Description |
post:root_visibility |
The very first post in the thread will be set to this visibility. Usually 'public'. Must be a valid string for mastodon statuses which currently are: public, unlisted, private, and direct. |
post:thread_visibility |
All toots are tooted as replies to each other. root → first → second, etc. All posts other than the root will have thread_visibility visibility. |
post:hashtag |
We tag all the toots with the hashtag. |
post:api_base_url |
Implicitly used when we create our Tooter |
post:cred_file |
Implicitly used when we create our Tooter |
Parameters:
| Name |
Type |
Description |
Default |
config
|
ConfigParser
|
A ConfigParser object from the config module
|
required
|
tootlist
|
List[str]
|
A list of strings which are the toots to be tooted. This module doesn't change them.
|
required
|
Returns:
| Type |
Description |
List[str]
|
|
TODO
Take the maximum post size into account and break into multiple toots.
Source code in mastoscore/post.py
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116 | def post_toots(config:ConfigParser, tootlist:List[str]) -> List[str]:
"""
Given the config and list of toots, create a [Tooter](module-tooter.md) and toot them.
## Config Parameters Used
| Option | Description |
| ------- | ------- |
| `post:root_visibility` | The very first post in the thread will be set to this visibility. Usually 'public'. Must be a valid string for [mastodon statuses](https://docs.joinmastodon.org/methods/statuses/#form-data-parameters) which currently are: `public`, `unlisted`, `private`, and `direct`. |
| `post:thread_visibility` | All toots are tooted as replies to each other. root → first → second, etc. All posts other than the root will have `thread_visibility` visibility. |
| `post:hashtag` | We tag all the toots with the hashtag. |
| `post:api_base_url` | Implicitly used when we create our [Tooter](module-tooter.md) |
| `post:cred_file` | Implicitly used when we create our [Tooter](module-tooter.md) |
Args:
config: A ConfigParser object from the [config](module-config.md) module
tootlist: A list of strings which are the toots to be tooted. This module doesn't change them.
Returns:
Number of toots tooted.
## TODO
Take the maximum post size into account and break into multiple toots.
"""
debug = get_debug_level(config, "mastoscore")
root_visibility = config.get("post", "root_visibility")
thread_visibility = config.get("post", "thread_visibility")
hashtag = config.get("mastoscore", "hashtag")
logger = logging.getLogger(__name__)
logging.basicConfig(
format="%(asctime)s %(levelname)-8s %(message)s",
level=logging.ERROR,
datefmt="%H:%M:%S",
)
logger.setLevel(debug)
try:
t = Tooter(config, "post")
except Exception as e:
logger.critical("Failed to create 'post' Tooter")
logger.critical(e)
return []
reply = None
next_status = {}
n = 1
# First an anchor post with some details
uidlist = []
post_urls = []
for toot in tootlist:
visibility = root_visibility if n == 1 else thread_visibility
text = toot + f"<p>#{hashtag} {n}/{len(tootlist) + 1}</p>"
post_name = "root post" if n == 1 else f"text post {n}"
if t is None:
print(f"{text}\nVisibility: {visibility}")
next_status["id"] = n
next_status["url"] = f"http://example.com/status/{n}"
uidlist.append(str(n))
post_urls.append({"name": post_name, "url": next_status["url"]})
else:
try:
next_status = t.status_post(
text,
visibility=visibility,
language="en",
in_reply_to_id=reply,
content_type="text/html",
)
uidlist.append(str(next_status["id"]))
post_urls.append({"name": post_name, "url": next_status["url"]})
logger.info(f"anchor: {n}")
except Exception as e:
logger.error("anchor post")
logger.error(e)
return uidlist, post_urls
n = n + 1
reply = next_status["id"]
logger.info(f"Posted {n} toots")
return uidlist, post_urls
|