Module: postgraphs¶
This module finds the graph and wordcloud images and alt text files that were created by graph and wordcloud, and it creates a Mastodon post with these images attached. It assigns the alt text to each image and also uses that alt text as the body of the post.

Configuration¶
The postgraphs module is controlled by the [postgraphs] section of the configuration file:
[postgraphs]
debug = 20
dry_run = false
visibility = public
message = Here are the graphs!
Configuration Options¶
| Option | Description |
|---|---|
dry_run |
If true, don't actually post (default: false) |
visibility |
Post visibility: public, unlisted, private, or direct (default: public) |
message |
Custom message to include with the post |
It will pull the standard Mastodon authentication parameters. But you can include different
parameters in the [postgraphs] section of the config file.
[postgraphs]
api_base_url = https://example.social
cred_file = /path/to/your/access_token.secret
botusername = yourbotname
Usage¶
To post graphs to Mastodon:
mastoscore --debug=info ini/yourevent.ini graph
mastoscore --debug=info ini/yourevent.ini wordcloud
mastoscore --debug=info ini/yourevent.ini postgraphs
Code Reference¶
Module for posting graph and wordcloud images to Mastodon with their alt text.
This module finds the graph and wordcloud images along with their corresponding alt text files, and creates a post with these images attached.
find_graph_files(config)
¶
Find the graph image and its corresponding alt text file.
Parameters¶
- config: A ConfigParser object from the config module
Returns¶
A tuple containing (graph_image_path, graph_alt_text) or (None, None) if not found
Source code in mastoscore/postgraphs.py
def find_graph_files(config):
"""
Find the graph image and its corresponding alt text file.
# Parameters
- **config**: A ConfigParser object from the [config](module-config.md) module
# Returns
A tuple containing (graph_image_path, graph_alt_text) or (None, None) if not found
"""
hashtag = config.get('mastoscore', 'hashtag')
year = config.get('mastoscore', 'event_year')
month = config.get('mastoscore', 'event_month')
day = config.get('mastoscore', 'event_day')
date_str = f"{year}{month}{day}"
# Define paths
graphs_dir = create_journal_directory(config)
graph_pattern = os.path.join(graphs_dir, f"{hashtag}-{date_str}.png")
alt_text_pattern = os.path.join(graphs_dir, f"{hashtag}-{date_str}.txt")
# Find files
graph_files = glob.glob(graph_pattern)
alt_text_files = glob.glob(alt_text_pattern)
if graph_files and os.path.exists(graph_files[0]):
graph_image_path = graph_files[0]
# Read alt text if available
if alt_text_files and os.path.exists(alt_text_files[0]):
with open(alt_text_files[0], 'r') as f:
graph_alt_text = f.read()
else:
graph_alt_text = f"Graph of #{hashtag} activity on {date_str}"
return graph_image_path, graph_alt_text
return None, None
find_wordcloud_files(config)
¶
Find the wordcloud image and its corresponding alt text file.
Parameters¶
- config: A ConfigParser object from the config module
Returns¶
A tuple containing (wordcloud_image_path, wordcloud_alt_text) or (None, None) if not found
Source code in mastoscore/postgraphs.py
def find_wordcloud_files(config):
"""
Find the wordcloud image and its corresponding alt text file.
# Parameters
- **config**: A ConfigParser object from the [config](module-config.md) module
# Returns
A tuple containing (wordcloud_image_path, wordcloud_alt_text) or (None, None) if not found
"""
hashtag = config.get('mastoscore', 'hashtag')
year = config.get('mastoscore', 'event_year')
month = config.get('mastoscore', 'event_month')
day = config.get('mastoscore', 'event_day')
date_str = f"{year}{month}{day}"
# Get hashtag_fix value, default to 'as-is'
hashtag_fix = config.get('wordcloud', 'hashtag_fix', fallback='as-is')
# Define paths
wordcloud_dir = create_journal_directory(config)
wordcloud_pattern = os.path.join(wordcloud_dir, f"wordcloud-{hashtag}-{date_str}-{hashtag_fix}.png")
alt_text_pattern = os.path.join(wordcloud_dir, f"wordcloud-{hashtag}-{date_str}-{hashtag_fix}.txt")
# Find files
wordcloud_files = glob.glob(wordcloud_pattern)
alt_text_files = glob.glob(alt_text_pattern)
if wordcloud_files and os.path.exists(wordcloud_files[0]):
wordcloud_image_path = wordcloud_files[0]
# Read alt text if available
if alt_text_files and os.path.exists(alt_text_files[0]):
with open(alt_text_files[0], 'r') as f:
wordcloud_alt_text = f.read()
else:
wordcloud_alt_text = f"Word cloud for #{hashtag} on {date_str}"
return wordcloud_image_path, wordcloud_alt_text
return None, None
post_graphs(config)
¶
Find graph and wordcloud images with their alt text and post them to Mastodon.
Parameters¶
- config: A ConfigParser object from the config module
Config Parameters Used¶
| Option | Description |
|---|---|
postgraphs:debug |
Debug level for logging |
postgraphs:dry_run |
Boolean. If True, don't actually post. |
postgraphs:visibility |
Post visibility (public, unlisted, private, direct) |
postgraphs:message |
Custom message to include with the post |
mastoscore:hashtag |
Hashtag used for the analysis |
mastoscore:event_year |
Year of the event (YYYY) |
mastoscore:event_month |
Month of the event (MM) |
mastoscore:event_day |
Day of the event (DD) |
Returns¶
Boolean indicating success or failure
Source code in mastoscore/postgraphs.py
def post_graphs(config):
"""
Find graph and wordcloud images with their alt text and post them to Mastodon.
# Parameters
- **config**: A ConfigParser object from the [config](module-config.md) module
# Config Parameters Used
| Option | Description |
| ------- | ------- |
| `postgraphs:debug` | Debug level for logging |
| `postgraphs:dry_run` | Boolean. If True, don't actually post. |
| `postgraphs:visibility` | Post visibility (public, unlisted, private, direct) |
| `postgraphs:message` | Custom message to include with the post |
| `mastoscore:hashtag` | Hashtag used for the analysis |
| `mastoscore:event_year` | Year of the event (YYYY) |
| `mastoscore:event_month` | Month of the event (MM) |
| `mastoscore:event_day` | Day of the event (DD) |
# Returns
Boolean indicating success or failure
"""
# Get configuration values
debug = config.getint('postgraphs', 'debug', fallback=20)
dry_run = config.getboolean('postgraphs', 'dry_run', fallback=False)
visibility = config.get('postgraphs', 'visibility', fallback='public')
custom_message = config.get('postgraphs', 'message', fallback='')
hashtag = config.get('mastoscore', 'hashtag')
# Set up logging
logger = logging.getLogger(__name__)
logging.basicConfig(format='%(levelname)s\t%(message)s')
logger.setLevel(debug)
# Find graph and wordcloud files
graph_image_path, graph_alt_text = find_graph_files(config)
wordcloud_image_path, wordcloud_alt_text = find_wordcloud_files(config)
if not graph_image_path and not wordcloud_image_path:
logger.error("No graph or wordcloud images found")
return False
# Prepare media list
media_ids = []
media_files = []
# Create message text
if custom_message:
# get rid of any embedded new lines
message = " ".join(custom_message.splitlines())
else:
message = f"Visualizations for #{hashtag}"
message += f"\n\n{graph_alt_text}\n\n"
message += f"{wordcloud_alt_text}\n\n"
# Add hashtag to the message
message += f"#{hashtag}"
if dry_run:
logger.info("DRY RUN - Would post the following:")
logger.info(f"Message: {message}")
if graph_image_path:
logger.info(f"Graph image: {graph_image_path}")
logger.info(f"Graph alt text: {graph_alt_text}")
if wordcloud_image_path:
logger.info(f"Wordcloud image: {wordcloud_image_path}")
logger.info(f"Wordcloud alt text: {wordcloud_alt_text}")
return True
# Create Tooter object
try:
tooter = Tooter(config, 'postgraphs')
except Exception as e:
logger.critical("Failed to create Tooter object")
logger.critical(e)
return False
# Upload media files
if graph_image_path:
try:
media = tooter.media_post(
graph_image_path,
description=graph_alt_text
)
media_ids.append(media['id'])
media_files.append(graph_image_path)
logger.info(f"Uploaded graph image: {graph_image_path}")
except Exception as e:
logger.error(f"Failed to upload graph image: {e}")
if wordcloud_image_path:
try:
media = tooter.media_post(
wordcloud_image_path,
description=wordcloud_alt_text
)
media_ids.append(media['id'])
media_files.append(wordcloud_image_path)
logger.info(f"Uploaded wordcloud image: {wordcloud_image_path}")
except Exception as e:
logger.error(f"Failed to upload wordcloud image: {e}")
# Post status with media
if media_ids:
try:
status = tooter.status_post(
message,
media_ids=media_ids,
visibility=visibility
)
logger.info(f"Posted status with {len(media_ids)} images: {status['url']}")
return True
except Exception as e:
logger.error(f"Failed to post status: {e}")
return False
else:
logger.error("No media files were successfully uploaded")
return False