Stream, Search, Invert, Upload & Reply



How To Write A Reddit Bot

You've probably seen bots in the wild on Reddit yourself. Here's how to create one yourself.

First create a script app on Reddit and get your id and secret: https://old.reddit.com/prefs/apps/

Then we'll connect to the Reddit API with PRAW and define which subreddit to target along with a keyword we want the bot to pick up and use as a trigger (!nvert).

import praw

client_id = 'XXXX'
client_secret = 'XXXX'
reddit_user = 'XXXX'
reddit_pass = 'XXXX'
user_agent = '!nvert bot (by u/impshum)'

target_sub = 'XXXX'
target_word = '!nvert'

reddit = praw.Reddit(client_id=client_id,
                     client_secret=client_secret,
                     user_agent=user_agent,
                     username=reddit_user,
                     password=reddit_pass)

print(f'Read only: {reddit.read_only}')

If the output of the above code is Read only: False we're good to go.

Next up is to get a stream of comments from our target_sub and check for our target_word. Go post a comment with the target_word. I normally test on my own subreddit so I can spam all I need to (I suggest you do the same).

for comment in reddit.subreddit(target_sub).stream.comments():
    body = comment.body
    if target_word in body:
        print(body)

Streaming picks up the last 100 posts. We don't want them. Let's fix that!

import time

for comment in reddit.subreddit(target_sub).stream.comments():
    if start_time < int(comment.created_utc):
        body = comment.body
        if target_word in body:
            print(body)

What we'll do here is get the id of the parent submission and check if it's an image or not. Let's add a function to get the parent.id and another to download the image. We'll have to change the stream code again also.

from requests import get

def get_parent_id(comment):
    parent = comment.parent()
    return parent.id

def download_image(url):
    fname = url.rsplit('/', 1)[-1]
    img_data = get(url).content
    with open(fname, 'wb') as f:
        f.write(img_data)
    return fname
for comment in reddit.subreddit(target_sub).stream.comments():
    if start_time < int(comment.created_utc):
        body = comment.body
        if target_word in body:
            parent_id = get_parent_id(comment)
            submission = reddit.submission(id=parent_id)

            url = submission.url
            if url.startswith(('http://i.imgur.com', 'https://i.imgur.com', 'http://i.redd.it', 'https://i.redd.it')) and url.endswith(('.jpg', '.png', '.jpeg')):
                print(f'FOUND AN IMAGE: {url}')
                download_image(url)

Now that we can download the image let's mess it up by inverting the colours with PIL.

from PIL import Image
import PIL.ImageOps

def invert_image(file):
    image = Image.open(file)
    inverted_image = PIL.ImageOps.invert(image)
    inverted_image.save(file)
for comment in reddit.subreddit(target_sub).stream.comments():
    if start_time < int(comment.created_utc):
        body = comment.body
        if target_word in body:
            parent_id = get_parent_id(comment)
            submission = reddit.submission(id=parent_id)

            url = submission.url
            if url.startswith(('http://i.imgur.com', 'https://i.imgur.com', 'http://i.redd.it', 'https://i.redd.it')) and url.endswith(('.jpg', '.png', '.jpeg')):
                print(f'FOUND AN IMAGE: {url}')
                fname = download_image(url)
                invert_image(fname)

What now? Get that image back onto the tubes of the internet of course. We'll also delete the image once uploaded as we don't need it for anything special. Create an anonymous app with Imgur and grab the app id: https://api.imgur.com/oauth2/addclient

import pyimgur
import os

imgurid = 'XXXX'

def upload(file_upload, title):
    im = pyimgur.Imgur(imgurid)
    uploaded_image = im.upload_image(file_upload, title=title)
    img_link = uploaded_image.link
    os.remove(file_upload)
    return img_link
for comment in reddit.subreddit(target_sub).stream.comments():
    if start_time < int(comment.created_utc):
        body = comment.body
        if target_word in body:
            print(body)
            parent_id = get_parent_id(comment)
            submission = reddit.submission(id=parent_id)

            url = submission.url
            if url.startswith(('http://i.imgur.com', 'https://i.imgur.com', 'http://i.redd.it', 'https://i.redd.it')) and url.endswith(('.jpg', '.png', '.jpeg')):
                print(f'FOUND AN IMAGE: {url}')
                fname = download_image(url)
                invert_image(fname)
                upload(fname, 'Inverted')

The only thing left to do now is to reply to the comment with the link to the inverted image.

for comment in reddit.subreddit(target_sub).stream.comments():
    if start_time < int(comment.created_utc):
        if target_word in comment.body:
            parent_id = get_parent_id(comment)
            submission = reddit.submission(id=parent_id)

            url = submission.url
            if url.startswith(('http://i.imgur.com', 'https://i.imgur.com', 'http://i.redd.it', 'https://i.redd.it')) and url.endswith(('.jpg', '.png', '.jpeg')):
                fname = download_image(url)
                invert_image(fname)
                image_link = upload(fname, 'Inverted')
                comment.reply(f'Here is your inverted image: [link]({image_link})')
                print(image_link)

Great stuff. If we put it all together we get this terrific pile of garbage...

import praw
import time
from requests import get
from PIL import Image
import PIL.ImageOps
import pyimgur
import os

client_id = 'XXXX'
client_secret = 'XXXX'
reddit_user = 'XXXX'
reddit_pass = 'XXXX'
user_agent = '!nvert bot (by u/impshum)'
imgurid = 'XXXX'
target_sub = 'XXXX'
target_word = '!nvert'

reddit = praw.Reddit(client_id=client_id,
                     client_secret=client_secret,
                     user_agent=user_agent,
                     username=reddit_user,
                     password=reddit_pass)

print(f'Read only: {reddit.read_only}')

def get_parent_id(comment):
    parent = comment.parent()
    return parent.id

def download_image(url):
    fname = url.rsplit('/', 1)[-1]
    img_data = get(url).content

    with open(fname, 'wb') as f:
        f.write(img_data)

    return fname

def invert_image(file):
    image = Image.open(file)
    inverted_image = PIL.ImageOps.invert(image)
    inverted_image.save(file)

def upload(file_upload, title):
    im = pyimgur.Imgur(imgurid)
    uploaded_image = im.upload_image(file_upload, title=title)
    img_link = uploaded_image.link
    img_link = img_link.replace('https://i.imgur.com/', '')
    img_link = 'https://recycledrobot.co.uk/imgee/?i={}'.format(img_link)
    os.remove(file_upload)
    return img_link

start_time = int(time.time())

for comment in reddit.subreddit(target_sub).stream.comments():
    if start_time > int(comment.created_utc):
        if target_word in comment.body:
            parent_id = get_parent_id(comment)
            submission = reddit.submission(id=parent_id)

            url = submission.url
            if url.startswith(('http://i.imgur.com', 'https://i.imgur.com', 'http://i.redd.it', 'https://i.redd.it')) and url.endswith(('.jpg', '.png', '.jpeg')):
                fname = download_image(url)
                invert_image(fname)
                image_link = upload(fname, 'Inverted')
                comment.reply(f'Here is your inverted image: [link]({image_link})')
                print(image_link)

I made a small website that displays the image on my own domain because it seemed like the right thing to do. Here's all that...

<!DOCTYPE html>
<html>

<head>
  <meta charset='utf-8'>
  <meta name='viewport' content='width=device-width, initial-scale=1'>
  <title>!nvert</title>
  <link rel='stylesheet' href='https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.4/css/bulma.min.css'>
  <style>
    html {
      background: #000;
    }
    body {
      background: url(bg.jpg) no-repeat center center fixed;
      -webkit-background-size: cover;
      -moz-background-size: cover;
      -o-background-size: cover;
      background-size: cover;
    }
    #insert {
      width: 100%;
      display: block;
      margin: 0 auto;
    }
  </style>
</head>

<body>

  <section class='hero is-fullheight'>
    <div class='hero-body'>
      <div class='container'>
        <div class='columns is-mobile is-centered'>
          <div class='column is-6-desktop is-12-touch'>
            <img id='insert' src='celery.png'>
          </div>
        </div>
      </div>
    </div>
  </section>

  <script>
    var query = window.location.search
    var imgur_id = query.replace('?i=', '');
    document.getElementById('insert').src=`https://i.imgur.com/${imgur_id}`;
  </script>

</body>

</html>

Thanks for reading. x

Resources