Module: post

The post command actually uses your credentials to post a few toots of the stats we gathered. I find it very useful to set dry_run to True in the [post] part of the config and see what it's going to post before I actually post.

Dry Run

Running a dry run will spit out the toots in HTML format on stdout. I like to use w3m to display it on the terminal.

mastoscore inifile.ini post | w3m -T text/html

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.

If post:dry_run is set to True, then it only posts the toots on stdout, it doesn't actually toot them.

post(config, analysis)

Expects the config options for the program and the output dictionary from the analyse() method. Connects to the target server and posts the various summaries. Calls post_toots() to actually post (or display) the toots.

Parameters

  • config: A ConfigParser object from the config module
  • tootlist: A list of strings which are the toots to be tooted. This module doesn't change them.

Config Parameters Used

NOTE: This method is very unusual in that it pulls config values from many sections of the config file. Most other methods restrict themselves to only their own section.

Option Description
graph:start_time Start time of the event we're looking at. ISO8601 formatted date string.
graph:end_time End time of the event we're looking at. ISO8601 formatted date string.
analyse:top_n How many top toots we will be reporting
analyse:tag_users Whether we tag users with an @ or not

Returns

Number of toots tooted.

Source code in mastoscore/post.py
108
109
110
111
112
113
114
115
116
117
118
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
def post(config, analysis: dict):
    """ 
    Expects the config options for the program and the output dictionary from the analyse()
    method. Connects to the target server and posts the various summaries. Calls
    [`post_toots()`](module-post.md#mastoscore.post.post_toots) to actually post (or display) the toots.

    # Parameters
    - **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.

    # Config Parameters Used

    **NOTE**: This method is very unusual in that it pulls config values from many sections
    of the config file. Most other methods restrict themselves to only their own section.

    | Option | Description |
    | ------- | ------- |
    | `graph:start_time` | Start time of the event we're looking at. ISO8601 formatted date string.
    | `graph:end_time` | End time of the event we're looking at. ISO8601 formatted date string.
    | `analyse:top_n` | How many top toots we will be reporting
    | `analyse:tag_users` | Whether we tag users with an @ or not |

    # Returns

    Number of toots tooted.

    """
    debug = config.getint('post', 'debug')
    # I don't like having 'post' read from 'analyse' but I'm too lazy to do better
    top_n = config.getint('analyse', 'top_n')
    tag_users = config.getboolean('post', 'tag_users')

    logger = logging.getLogger(__name__)
    logging.basicConfig(format='%(levelname)s\t%(message)s')
    logger.setLevel(debug)

    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.</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 idx in top.index:
        text = text + f"<li><a href=\"{top['url'][idx]}\">This toot</a> from "\
            f"<a href=\"{top['account.url'][idx]}\">{top['account.display_name'][idx]} "\
            f"({tag}{top['userid'][idx]})</a>" \
            f" had {top['reblogs_count'][idx]} 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 idx in top.index:
        text = text + f"<li><a href=\"{top['url'][idx]}\">This toot</a> from "\
            f"<a href=\"{top['account.url'][idx]}\">{top['account.display_name'][idx]} "\
            f"({tag}{top['userid'][idx]})</a>" \
            f" had {top['favourites_count'][idx]} 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 idx in top.index:
        text = text + f"<li><a href=\"{top['url'][idx]}\">This toot</a> from "\
            f"<a href=\"{top['account.url'][idx]}\">{top['account.display_name'][idx]} "\
            f"({tag}{top['userid'][idx]})</a>" \
            f" had {top['replies_count'][idx]} replies.</li>\n"
    text = text + "</ol>"
    tootlist.append(text)

    post_toots(config, tootlist)
    return len(tootlist)

post_toots(config, tootlist)

Given the config and list of toots, create a Tooter and toot them.

Parameters

  • config: A ConfigParser object from the config module
  • tootlist: A list of strings which are the toots to be tooted. This module doesn't change them.

Config Parameters Used

Option Description
post:dry_run Boolean. If True, print HTML on stdout. If False, really post toots.
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

Returns

Number of toots tooted.

TODO

  • Take the maximum post size into account and break into multiple toots.
Source code in mastoscore/post.py
 30
 31
 32
 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
def post_toots(config, tootlist) -> int:
    """
    Given the config and list of toots, create a [Tooter](module-tooter.md) and toot them.

    # Parameters
    - **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.

    # Config Parameters Used
    | Option | Description |
    | ------- | ------- |
    | `post:dry_run` | Boolean. If True, print HTML on stdout. If False, really post toots. |
    | `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 &rarr; first &rarr; 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) |

    # Returns

    Number of toots tooted.

    # TODO
    - Take the maximum post size into account and break into multiple toots.
    """

    debug = config.getint('post', 'debug')
    dry_run = config.getboolean('post', 'dry_run')
    root_visibility = config.get('post', 'root_visibility')
    thread_visibility = config.get('post', 'thread_visibility')
    hashtag = config.get('post', 'hashtag')

    logger = logging.getLogger(__name__)
    logging.basicConfig(format='%(levelname)s\t%(message)s')
    logger.setLevel(debug)

    if dry_run:
        logger.warn(f"dry_run is true. Not actually tooting")
    else:
        try:
            t = Tooter(config, 'post')
        except Exception as e:
            logger.critical("Failed to create 'post' Tooter")
            logger.critical(e)
            return 0

    reply = None
    next_status = {}
    n = 1
    # if we're a dry run, put HTML header and footer so we can pipe it 
    # to `w3m -T text/html` for pretty viewing
    if dry_run:
        print(HTML_HEAD)
    # First an anchor post with some details
    for toot in tootlist:
        visibility = root_visibility if n == 1 else thread_visibility
        text = toot + f"<p>#{hashtag} {n}/{len(tootlist)+1}</p>"

        if dry_run:
            print(f"{text}\nVisibility: {visibility}")
            next_status['id'] = n
        else:
            try:
                next_status = t.status_post(text, visibility=visibility, language='en',
                                            in_reply_to_id=reply, content_type="text/html")
                logger.info(f"anchor: {n}")
            except Exception as e:
                logger.error(f"anchor post")
                logger.error(e)
                return n    # Now boost about boosts
        n = n+1
        reply = next_status
    logger.info(f"Posted {n} toots")
    if dry_run:
        print(HTML_TAIL)
    return n