Making an auto-updating Twitter banner in Python
I used to use blackmagic.so’s auto-banner updater, but I realised that it’s pretty common nowadays and making one on my own would be soo much cooler. Also, the real-time banner provided by Blackmagic
didn’t really look good
By the way, you should follow this guy. He’s a great dev with amazing content
As opposed to:
You should also follow this guy. His followers has been decreasing since quite a long time
Jokes aside, determined to make this on my own with basically 0 knowledge of the Twitter API, this wasn’t gonna be easy. but it kinda was
Starting out - the twitter api
Oh boi, don’t even get me started on the Twitter API. it’s a complete mess. There are 2 versions, both are completely different. Getting authentication keys is a mess, all links lead to the same article, and the articles don’t even give the solution, they only give the meaning of the problem. there are like 5 different keys you need to authenticate a user
Anyways, I made the API keys by creating an app on the dashboard and dumped them into a .env
file. I didn’t even know what the keys did yet
I knew of a python module for twitter - tweepy
that’s quite easy to use, with good documentation
Then there was the login part, which was honestly quite easy to do.
One thing, I didn’t have the Write
access in my Oauth yet, and this caused a lot of headache later on
class ProfileBanner:
def __init__(self):
self.client = self.__login()
def __login(self):
"""Logins and sets access tokens"""
auth = tweepy.OAuthHandler(env["CONSUMER_KEY"], env["CONSUMER_SECRET"])
auth.set_access_token(env["ACCESS_TOKEN"], env["ACCESS_TOKEN_SECRET"])
api = tweepy.API(auth)
api.verify_credentials()
return api
I decided to use twitter API V1 because I tried V2 and it was a pain to set up
Getting latest followers
I only need the 5 latest followers, just their profile pictures. So I wrote this function that gets the profile pictures as bytes and stores them in a list
def __get_latest_followers_images(self) -> list[io.BytesIO]:
"""Gets all the latest follower images"""
latest_followers = self.client.get_followers(
user_id=env.get("USER_ID"), count=5
)
images = []
for follower in latest_followers:
response = requests.get(follower.profile_image_url)
images.append(io.BytesIO(response.content))
return images
The
__
(double underscore) before function makes it inaccessible outside the class, basically a private function. This is good because we don't wanna make many functions public and keep the API as simple as possible (https://twitter.com/DhravyaShah/status/1500911400486531072)
Creating the image
Now is the kinda easy part. Making the image. I already have the follower’s profile pics and just had to paste it onto the template
I created this template on canva, really cool design isn’t it
Now, by getting the coordinates of the first image and the diameter of each image in pixels, I could easily just paste all the images one by one. This is what I ended up with:
def __image_factory(self, savepath: str = None) -> Image:
"""
Pastes the image onto the template
"""
template = Image.open("template.png")
images = self.__get_latest_followers_images()
for i, image in enumerate(images):
image = Image.open(image)
image = image.resize((self.IMAGE_DIA, self.IMAGE_DIA))
# Make image circle
mask = Image.new("L", (self.IMAGE_DIA, self.IMAGE_DIA), 0)
draw = ImageDraw.Draw(mask)
draw.ellipse((0, 0, self.IMAGE_DIA, self.IMAGE_DIA), fill=255)
image.putalpha(mask)
# Paste the image onto the template
template.paste(
image,
(
self.FIRST_IMAGE_COORDS[0] + (i * self.IMAGE_DIA),
self.FIRST_IMAGE_COORDS[1],
),
image,
)
if savepath:
template.save(savepath)
return template
Updating the banner
Now all I have to do is update the banner. Here’s the simple script that does that
def __update_banner(self) -> None:
"""Updates the banner"""
self.__image_factory(savepath="banner.png")
self.client.update_profile_banner("banner.png")
def update_every_few_minutes(self, minutes:int = 2):
"""Starts the update loop"""
while True:
self.__update_banner()
print("Updated banner")
time.sleep(60*minutes)
AAAAAAAAAAAAAAANDDDD BOOM! Done!
if __name__ == "__main__":
banner = ProfileBanner()
banner.update_every_few_minutes()
Deploying
I deployed the project on pm2
on a VPS I bought from Epikhost.
pm2 start main.py --interpreter python3.9 --name twitter-banner
Thanks for reading!
Thanks for reading my boring blog.