Mastadon Bot with AWS Lambda, S3, CloudWatch, and SSM
Taha Yağız Güler
Posted on March 23, 2023
In this post I show you how I set up the MastadonBot to share random frames from the movie Taxi Driver.
This bot was created by taking inspiration from Cameron Ezell.
I also created this bot using Terraform. You can browse Github MastadonBot_AWS.
How I got the frames?
Python script "ExtractImagesFromVideoFile" I wrote for capturing screenshots at specified intervals from a video file using ffmpeg. This Python script captures screenshots from a video file at specified intervals (e.g., 1 second) using ffmpeg.
Uploading frames!
First of all, I created an S3 bucket and uploaded the screenshots I wanted to share to this bucket and used the following path while uploading the screenshots.
After saving about 7000 screenshots it would take quite a while to upload them to the S3 bucket so I created an EC2 instance and uploaded the files via FTP then copied the S3 bucket via the aws cli > aws s3 cp ./ s3://your-bucket/ --recursive
.
Create your Application
For anyone interested in building a Mastodon bot, make sure the instance you create your bot on is fine with automated accounts.
After signing up, create an app from Preferences > Development.
(botsin.space)
Enter a name for your application and default values for now.
I keep the access token as SecureString type using the AWS Systems Manager Parameter Store. This is an important step for security.
Lambda Function
Boto3(AWS Lambda) script for randomly selects screenshots stored in S3 and enables sharing.
import mastodon
from mastodon import Mastodon
import boto3
import os
import random
import re
def lambda_handler(event, context):
BASE_URL = "https://botsin.space"
BUCKET_NAME = "movieframebucket" # XXXXXXX
keyArray = []
ssm = boto3.client("ssm")
auth_keys = ssm.get_parameters(
Names=["my_consumer_key"], WithDecryption=True) # XXXXXXX
access_token = auth_keys["Parameters"][0]["Value"]
m = Mastodon(access_token=access_token, api_base_url=BASE_URL)
s3 = boto3.resource("s3")
s3bucket = s3.Bucket(BUCKET_NAME)
try:
for obj in s3bucket.objects.filter(Prefix="taxi_driver_frames/"): # XXXXXXX
# add all frame key values from episode to an array
keyArray.append("{0}".format(obj.key))
except Exception as e:
# If there is an error, raise the exception and stop the function
raise e
numFrames = len(keyArray)
randomFrame = random.randint(0, numFrames)
KEY = keyArray[randomFrame]
print("frame from second # " + str(randomFrame))
s3.Bucket(BUCKET_NAME).download_file(KEY, "/tmp/local.jpg")
random_objectNumber = re.search(r'\d+', KEY).group()
time_in_seconds = int(random_objectNumber)
minutes, seconds = divmod(time_in_seconds, 60)
hours, minutes = divmod(minutes, 60)
time_format = "{:02d}:{:02d}:{:02d}".format(hours, minutes, seconds)
frameInfo = "Taxi Driver | {:02d}:{:02d}:{:02d}".format(hours, minutes, seconds)
# We have to first create a media ID when uploading an image
media = m.media_post("/tmp/local.jpg")
# Then we can reference this media ID in our status post
m.status_post(status=frameInfo, media_ids=media)
os.remove("/tmp/local.jpg")
return None
I installed the Mastadon package locally and zipped it with this code I wrote then uploaded it to Lambda.
CloudWatch Event for Lambda
I created a CloudWatch Event for Lambda to publish a post every 30 minutes.
And here is our Mastadon bot ready!
I may have missed a few parts, don't hesitate to reach out to me if you need help. I would like to help you as much as I can!
Posted on March 23, 2023
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.