⭐Introduction
I've always wanted to build a bot that posts something independently with the data.
In this case, I've included data from a few subreddits where people post cat images, like r/Catswithjobs, r/catpictures, and r/SupermodelCats.
Now, using the data from the above subreddits, I've built this bot that posts to Twitter through a cron-job service and also returns an API where the posted data by the bot can be retrieved.
👨🏻💻 Tech Stack
I've used the following tech stack to build this bot and API:
Ktor - for building the bot, API, and posting respective data to the database.
Ktor-Client - for retrieving JSON data from subreddits(s).
MongoDB - for storing previous posts that are posted by the bot, which can be retrieved by the API.
KMongo - for chit-chatting with MongoDB.
Twitter4j - for interacting with the Twitter API so that the bot can post the data to Twitter.
Apache Commons IO - converts the URL into a file (so that the bot can tweet the image URL as an image that was retrieved from the subreddit).
Zeplo - for triggering the bot endpoint automatically every third hour; In other words, zeplo is used as a cron-job(s) service(if that makes sense in this context).
Ktor Plugins:ktor-api-key - It is a simple authentication provider for Ktor that verifies the presence of the API key from the header.
🤖Building The Bot
This is what the visual of the bot looks like:
The implementation of this bot was pretty simple and clear to me. As I don't want to get the data only from a specific subreddit from the above-mentioned.
I've added the URLs of these subreddits to the database(MongoDB) so that I can retrieve any random subreddit's URL for further usage:
val kMongo = KMongo.createClient(System.getenv("MONGODB_URL"))
val collectionData = kMongo.getDatabase(System.getenv("DB_NAME")).getCollection(System.getenv("SUBREDDIT_URLS"))
val listOfSubredditURLs = mutableListOf<String>()
collectionData.find("""{url:{${MongoOperator.regex}:/www.reddit.com/i}}""").toList().forEach { document ->
listOfSubredditURLs.add(document.getString("url"))
}
val pickedSubredditURL = listOfSubredditURLs.random()
🧐Filtering the data retrieved from the random subreddit
- As I only wanted to post an image with a respective title to it, which will be retrieved from the above code, I don't want to make posts that contain videos or others that could interpret the bot. So I've filtered the random data which I'll get from the above code:
val fetchDataFromURL = ktorClient.get(pickedSubredditURL).body<RedditData>()
val fetchedDataFromURL = mutableListOf<Children>()
for(children in fetchDataFromURL.data.children){
if(!children.data.is_video && children.data.url.contains(regex = Regex("/i.redd.it")) && !children.data.over_18){
fetchedDataFromURL.add(children)
}
}
return fetchedDataFromURL.random()
🐤Posting the filtered data to Twitter and the database(MongoDB)
I've used a library known as Twitter4j, which will post the given data to Twitter using the Twitter API.
Now, here's where the problem arrives(it has a solution😎🤝🏻). The image of the random post, which is retrieved from the subreddit, changes every time, and upon that, the image file is allocated to Reddit's database, which can be retrieved only using HTTP/HTTPS. But the library that I'm using takes media input from local storage using the
File
API.The solution for this was simply to use the
Apache Commons IO
library in which one of the classes/objects can convert any URL into a file
val refFile = File("/src/main/assets/ref.jpg")
val refURL = Url(fetchedTweetData.data.url).toURI().toURL()
FileUtils.copyURLToFile(refURL, refFile)
If you actually notice the refFile
variable, I haven't added the correct path; which simply replaces the image URL into a temporary file (which doesn't even exist)🤭
- Now that I have converted the URL into a file, I've passed the
refFile
which contains theFile
that will be converted into the respective image's file:
val statusUpdate = StatusUpdate.of(tweetTitle).media(refFile)
twitterBuilder.v1().tweets().updateStatus(statusUpdate)
Now the above code will post the respective data to Twitter.
As I mentioned, I also want to save the posted data in a database that can be retrieved by the API.
I've created a function called
addNewPostToDB()
that will post the respective data to the database.addNewPostToDB()
function is placed in thepostNewTweet()
function so that both adding the data to the database as well as posting to Twitter happens with a single trigger.
🚀 Automating the Bot
Now that I have to automate things, I've used Zeplo which will trigger the endpoint of the bot
postNewTweet()
function every third hour.The best part about Zeplo is that it tries to connect to the server if it fails due to timeout.
Well, that's all. The bot is live now on Twitter🥳
🌐Building The API
This is what the visual of the API looks like:
Building the API was pretty simple compared to the bot, as the data will be automatically added to the database when the bot posts data from a subreddit.
When the endpoint of the API gets triggered, it will collect the data from the database and return it in the JSON format. It's as simple as that.
Endpoints:
- I've added two endpoints for accessing the API.
- /previousPosts will return the previously posted data from the database.
- /previousPosts/{DATE} will return data based on the date provided in the URL parameter.
📃You can checkout API docs from here.
The source code of this project is public and open-source under MIT License:
sakethpathike / catktorbot
An automated bot that posts cat pictures from selected subreddits every third hour. Besides that, you can fetch the previously posted data through the API.
API Docs :- https://documenter.getpostman.com/view/24098668/2s8YCjBr9o
How it works?
Bot
This is what the visual of the bot looks like:
- When the endpoint of the bot gets triggered by the cron-job, the postNewTweet() function in PostNewTweet.kt will trigger the Twitter endpoint through the Twitter4J library, which will post the data that is fetched from fetchRandomPost().
- fetchRandomPost() retrieves random data from a randomly selected subreddit.
- The same data that is sent to Twitter via bot will be added to a database using addNewPostToDB(), which you can retrieve through the API.
API
This is what the visual of the API looks like:
- When the previousPosts endpoint gets triggered, data that is posted by the bot will be retrieved from the database.
- When the previous post with a date filter added in the parameter gets triggered, the API will return filtered data from the database.
API Docs :- https://documenter.getpostman.com/view/24098668/2s8YCjBr9o
Tech Stack
- Ktor…
Top comments (0)