In a previous post I discussed the script for automatically parsing contest submissions. At the end of the month a post is created to allow users to vote on their favorite maps. In the past this has been a tedious process and prone to mistakes. So I decided to automate this with Python.
A Blank Template
Most of the posts will be the same every month. I created a blank template as a text file. This text includes the rules, contact information and a description of the contest.
There are a few wildcards for variables that will be dynamically inserted into the post by Python. Once those are inserted the text it becomes the self-text of the post.
Posting to Reddit
The submissions have all been nicely parsed and stored in a CSV. Each row is a different submission and each field in that row is indexed by it’s type of data.
First we need to count how many entries there are:
numbersubmitted = sum(1 for line in open('submissions.csv'))
Now change the wildcards in the text file:
VotingText = VotingText.replace('%NUMBERSUBMITTED%', str(numbersubmitted)) VotingText = VotingText.replace('%ENDDATE%', str(next_sunday)) VotingText = VotingText.replace('%MYREDDITID%', my_reddit_ID) VotingText = VotingText.replace('%LASTMONTH%', last_month_url)
Next, post to Reddit:
post_message = 'Vote Now for the ' + str(contest_month) + ' ' + str(contest_year) + ' Map Contest!' submission = r.subreddit('mapporn').submit(post_message, selftext=VotingText) # Submits the post to Reddit submission.mod.contest_mode() submission.mod.distinguish() shortlink = submission.shortlink
We have a post now with the rules and description of the contest, now we have to post the submissions.
Looping through the CSV
The submissions are all posted as comments to the post. The post is in contest-mode, meaning that the users cannot see the vote counts. Users up-vote the comment of the maps they like. No other parent level comments are allowed. A general discussion comment will be posted to give users a place to comment in the post.
The code for the loop is thus:
for row in reader: submission.reply('[' + row + '](' + row + ') \n' + row + '\n\n----\n\n^^^^' + row)
As you can see there are brackets and parentheses for wrapping the comment using markup language. It looks better to hyperlink the map name instead of having a separate URL.
Also, notice that in the script the last variable – row is added in small type underneath a line. That is the unique identifier that was added in the submissions check script. Later on, another script will iterate through all the comments and make a list of the highest upvoted maps. The unique identifier will be used to match the map with the entry in the CSV.
Letting the User Know that the Contest is Live
As we loop thru the CSV, we can send a message to each submitter to tell them the contest has started:
try: r.redditor(row).message('The monthly map contest is live!', 'Thank you for contributing a map. ' '[The voting on the monthly contest is ' 'open now at this link.](' + shortlink + ') \n' + botDisclaimerText) except: print('Could not send message to ' + row)
We use a try/except method because in a few cases the user has deleted their profile. This has resulted in the script stopping mid-loop, and required running the script again and making a completely new post.
Finalizing the Post
Add a general comment thread:
generalcomment = submission.reply('General Comment Thread') generalcomment.mod.distinguish(sticky=True)
Also we need to save the id of the post. When we run a script to count the votes later we need to know which post we’re counting. A small text file is created with the raw_id of the post.
raw_id = submission.id_from_url(shortlink) file = open('data/votingpostdata.txt', 'w') file.write(raw_id) file.close()
Also, occasionally we get new submissions while the contest is ongoing. We cannot add those to the CSV the users are voting on, that would mess everything up. So we rename it:
The script that counts the votes will read the submissions_current.csv. Which reminds me, that’s kind of a bad name for that CSV, anybody got a recommendation of what a better name would be?
Post to Social Media
Now that the post is live, it’s time to advertise it on social media. I’ve created a script to simultaneously post to Facebook, Twitter and Tumblr. I will discuss that script in another post. But for now, we need to pass an image and a message to that script.
Occasionally I like to create images on Illustrator to advertise the different parts of the MapPorn empire. I’ve created about a dozen images that advertise the map contest. They are stored in their own folder and have the file name format of: 01.png, 02.png…etc. I created a script to randomly pick an image to post to social media:
imagecount = len([name for name in os.listdir('voteimages/')]) randraw = random.randint(1, imagecount) image_file_name = str(randraw).zfill(2) image_file_name = fnmatch.filter(os.listdir('voteimages/'), image_file_name + '.*') image_file_name = image_file_name
Now that we have an image chosen, we can post to social media with the generic_post() function:
post_message_url = (post_message + '\n' + shortlink + '\n#MapPorn #Cartography #Contest') image_file_name = ('voteimages/' + image_file_name) social_media_post = generic_post(image_file_name, post_message_url)
Lastly we send a message to my reddit username with a summary of the social media post:
send_reddit_message_to_self('New Voting Post Posted', 'A new votingpost.py has been run. Check the post to make sure the bot did it right.' ' \nHere\'s the link to the post: ' + shortlink + ' \nHere\'s the social media ' 'links: \n' + social_media_post)
Next time we’ll go over the script that counts the votes and congratulates the winner.
This script is part of the /r/MapPorn GitHub Repository