As discussed in a previous post, Reddit has a great API for interacting with bots and scripts. Part of the workflow for the /r/MapPorn map contest is receiving custom maps and preparing them for the voting post.
Routing Messages to the Bot
On the main contest page is a link to Submit a map. This is the only place where the users can submit their maps. This link is pre-populated with the ‘to’ marked as the bot’s username, the subject as “Map Contest Submission” and a message area with several lines that the user will replace.
This is all very important as the bot will parse this when it receives the new maps. If the user changes the subject name or doesn’t put the items in the right order, then the Python script will not execute correctly.
Fortunately you can pre-populate these fields by manipulating the URL.
In this case the url is as follows:
Parsing the Messages
There are five fields that every entry must have:
- Map Name
- URL Link
- Unique Identifier
The first four are self-explanatory, but the last one is a unique identifier that we will cover later.
When the Python script is executed it checks the inbox.
import praw r = praw.Reddit('bot1') # Initialize PRAW for message in r.inbox.unread(): if message.subject == "Map Contest Submission":
Check each message if it’s a submission. If so it continues:
submission = message.body submission = os.linesep.join([s for s in submission.splitlines() if s]) # removes extraneous line breaks submission = submission.splitlines() # Turn submission into a list submission = [w.replace('Link: ', '') for w in submission] # Replace the text 'Link: ' with blankspace. submission.append(message) # Add unique value for the message. This is important for indexing later on.
The script takes the body of the message and splits it into a list. The “Link: ” is removed. Finally a unique value is added to the end of the list. This is a unique value that Reddit uses for indexing messages. Since it’s conveniently unique we can use that to identify the map data later on.
Replying to the User
Now that we’ve received the submission, it’s a good idea to send a confirmation message:
MessageReply = 'Your map has been received. ' + '\n' + 'Look for the voting post for the contest soon.'
Store in a CSV
Now we need to take this information and store it. A CSV is simple and convenient. If we get dozens of maps each entry in the CSV will have the same column for the same types of values. This is the code to insert it into a CSV:
with open('submissions.csv', 'a') as submitFile: reader = csv.reader(submitFile) wr = csv.writer(submitFile) wr.writerow(submission)
This takes the list and for each index of the list it puts that value in one column. But what if the user didn’t format the message properly? That’s where I come in and do a human check. At the end of the script the bot will send me a message on Reddit:
r.redditor(my_reddit_ID).message('New Map added to CSV', 'A new map has been submitted. ' 'Check the CSV for formatting')
This way I can quickly check the CSV. It’s much easier than the old system of going thru each submission and separating all the fields by hand.
But what if the bot gets a message that isn’t a map submission? As the bot is a moderator, this happens occasionally. I created an else statement to handle these messages:
else: msg = message.body author = str(message.author) subject = message.subject r.redditor(my_reddit_ID).message('Message sent to Bot, Please check on it \n', '*/u/' + author + '* sent this message to the bot. Please check on it. \n' + '**Subject:** ' + subject + ' \n' + '**Message:** \n' + msg)
Again, the bot sends me a message to alert me.
Scheduling Script Execution
The next task is to have a workflow for executing the script. There are several options to have a scheduled Python script and some uses might be different. I considered Heroku as an option but settled on using my Raspberry Pi. I have a CronTab scheduler set to run the script hourly.
If I set it too infrequently users sometimes worry that we didn’t receive the submission. This ensures that we can process the submissions and make sure they conform to the rules in a timely manner.