Module: post¶
The post command actually uses your credentials to post a few toots of the stats we gathered. It threads them. The first one goes out with root visibility, and all the others are replies to it with the thread visibility. It will post a general summary, followed by all the top n posts, and then finally the 2 graphs with their alt text.
The JSON files from analyse need to exist.
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
|
the posts. |
Source code in mastoscore/post.py
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.
"""
logger = get_logger(config, __name__)
top_n = config.getint("mastoscore", "top_n")
tag_users = config.getboolean("post", "tag_users")
gallery_url = config.get("post", "galleryurl", fallback=None)
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. Posts text analysis first, then histogram and wordcloud as threaded replies.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
config
|
ConfigParser
|
ConfigParser object with all configuration |
required |
Returns:
| Type | Description |
|---|---|
int
|
Number of toots posted (text + graphs) |
Source code in mastoscore/post.py
def post_all(config:ConfigParser) -> int:
"""
Post analysis results and graphs to Mastodon.
Posts text analysis first, then histogram and wordcloud as threaded replies.
Args:
config: ConfigParser object with all configuration
Returns:
Number of toots posted (text + graphs)
"""
logger = get_logger(config, __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
# Get the last post ID to thread graphs from
analysis = read_json(config, "analysis")
reply_to_id = None
if analysis and "tootlist" in analysis and analysis["tootlist"]:
reply_to_id = analysis["tootlist"][-1]
logger.info(f"Will thread graphs from post ID: {reply_to_id}")
# Post graphs
try:
graph_count = _post_graphs(config, reply_to_id)
logger.info(f"Posted {graph_count} graph posts")
except Exception as e:
logger.error(f"Failed to post graphs: {e}")
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. |
mastoscore:api_base_url |
Implicitly used when we create our Tooter |
mastoscore: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]
|
Number of toots tooted. |
TODO¶
Take the maximum post size into account and break into multiple toots.
Source code in mastoscore/post.py
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. |
| `mastoscore:api_base_url` | Implicitly used when we create our [Tooter](module-tooter.md) |
| `mastoscore: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.
"""
logger = get_logger(config, __name__)
root_visibility = config.get("post", "root_visibility")
thread_visibility = config.get("post", "thread_visibility")
hashtag = config.get("mastoscore", "hashtag")
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 = []
logger.debug(f"{len(tootlist)} toots")
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}"
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