How to subscribe to a subreddit using Snoo

This post piggybacks on my prior post where I wrote about the difficulty I was having interfacing with Reddit’s API. That problem has now been solved.

Relevant Links

The subscribe method in Snoo’s master repo is unfortunately outdated and will return in a 404 error.


def subscribe subreddit, action = "sub"
  logged_in?
  post('/api/subscribe', body: {action: action, sr: subreddit, uh: @modhash, api_type: 'json'})
end

The reason it returns a 404 error is because the API now requires you to pass the subreddit’s formatted id instead of it’s name. Where do you get this formatted id? Let’s use the r/nba subreddit for our example.

Navigate your browser to http://www.reddit.com/r/nba/about.json. Below is the relevant excerpt.

{

    "kind": "t5",
    "data": {
        "submit_text_html": null,
        "user_is_banned": false,
        "id": "2qo4s",
        "submit_text": "",
        "display_name": "nba",
...
...
}

Per the API docs the formatted id should be “kind” + _ + “id”, which would be “t5_2q04s”. This is what needs to be passed as the subreddit name, not “r/nba”.

Let’s start rewriting the method:


def subscribe(subreddit)
  subreddit_json = self.subreddit_info(subreddit)
  subreddit_id = subreddit_json['kind'] + "_" + subreddit_json['data']['id']
end

In Snoo there is a method named #subreddit_info located in subreddits.rb. It returns the json hash that you saw earlier when you visited http://www.reddit.com/r/nba/about.json. The subreddit_id variable builds the “t5_2q04s” formatted id.


def subscribe(subreddit)
  ...
  ...
  server_response = self.class.post('/api/subscribe.json',
    body:{uh:@modhash, action:'sub', sr: subreddit_id, api_type:'json'})
end

The server_response variable will contain the response from Reddit’s server after we send the request. The self.class.post method comes from the HTTParty gem that is bundled with Snoo. The first parameter is the URL we want to send the post request to. The second parameter is the body of our post request. For what exactly needs to be sent in the body you can see this specific entry in the API docs.

And finally let’s bring it all together with the final method:


def subscribe(subreddit)
  subreddit_json = self.subreddit_info(subreddit)
  subreddit_id = subreddit_json['kind'] + "_" + subreddit_json['data']['id']
  server_response = self.class.post('/api/subscribe.json',
    body:{uh:@modhash, action:'sub', sr: subreddit_id, api_type:'json'})
  return "Successfully subscribed to r/#{subreddit}" if server_response.code == 200
  return "Error code: #{server_response.code}" unless server_response == 200
end

You get notified either way if the request was successful or not. If the request was unsuccessful you are notified of the HTTP error code.

I hope this helps!

Trying to get a Reddit Bot up and running

I browse Reddit a lot and I thought it would be good programming practice to try and automate some of the more frequent tasks I do, namely searching for “Kobe Bryant” in the r/nba subreddit.

My first instinct was to write a bot from scratch, but writing a bot really isn’t my goal. My goal is to get a bot to do my searching for me. Writing an entire bot from scratch to accomplish one task seems like a case of “reinventing the wheel”, especially when there are tried-and-tested bots that exist.

I did some searching and found a stable bot framework called Snoo that is written in Ruby. It’s not as feature-rich as PRAW, which is written in Python, but it does the job and the code is easy to understand.

I can login fine. I can get my account settings fine. The problem comes when I try to add functionality. The problem isn’t with the bot itself, but with trying to interface with Reddit’s API.

My first task was to add a method to subscribe to a forum.

def subscribe(subreddit)
	logged_in?
	HTTParty.post('http://www.reddit.com/api/subscribe.json',body:{uh: @modhash, action:'sub', sr: subreddit, api_type: 'json'})
end

Instead of success I get this response back

pry(main)> reddit.subscribe('/r/nba')
=> {"json"=>{"errors"=>[["USER_REQUIRED", "please login to do that", nil]]}}

It was suggested that I try passing my session cookie or my user name and I’ve tried those and no success…YET. So until then I’ll keep on pushing…

Fibonacci Sequence

I used my instincts to write this fibonacci sequence generator using an array. I’m aware there are simpler solutions not using an array. I used an array because originally I wanted to output the entire array (e.g., [0,1,1,2,3]).

Using Iteration
—————

def fibonacci(input)

  return input if input == 0 || input == 1

  array_of_results = [0,1]
  i = 1
  
  until i == input
    next_node = array_of_results[-1] + array_of_results[-2]
    array_of_results.push(next_node)
    i += 1
  end

  return array_of_results.last
end

p fibonacci(11) #=> returns 89

Recursive
———

def fibonacci_recursive(input)
return input if input == 0 || input == 1
fibonacci_recursive(input-1) + fibonacci_recursive(input-2) if input > 1
end

p fibonacci_recursive(11) #=> returns 89

New Project – Order Management

This project has taken a good amount of effort to complete.

oie_8238463ZK2XRBY

ORDER MANAGEMENT – hosted on Heroku

The purpose of this application is to track client orders and ‘widgets’ (shippable product).

Customer Database

  • CRUD actions available to user

Order Database

  • CRUD actions
  • User can assign widgets to open orders
  • User can track order status

As I add features in the future this post will be updated.

Link to github repository

Parsing URLs

I wanted to parse a URL and remove any ‘www’ type prefixes and just get the raw domain name.

RUBY

require 'uri'
 
def domain_name(url)
  #remove the http:// with URI.parse
  base_url = URI.parse(url).host
 
  #base_url.split returns an array, ex. ["www", "cnet", "com"]
  url_array = base_url.split('.')
 
  #url may be www.example.com or example.com
  if url_array.count == 3
    url_array.shift
    url_array.join('.')
  elsif url_array.count == 2
    base_url
  end 
end
 
p domain_name('http://www.cnet.com')    #=> "cnet.com"
p domain_name('http://httpbin.org')     #=> "httpbin.org"
p domain_name('http://mail.google.com') #=> "google.com"

JAVASCRIPT

function domainName(str){
  var baseURL = str.split("http://")[1];
  var urlArray = baseURL.split('.');
 
  if (urlArray.length == 3){
    urlArray.shift();
    return urlArray.join('.');
  }
  else{
    return baseURL;
  }
}
 
domainName("http://www.cnet.com");    // "cnet.com"
domainName("http://httpbin.org");     // "httpbin.org"
domainName("http://mail.google.com"); // "google.com"