Rendering comments from Google+ related to a post (or URL!)

In my previous post on retrieving Google+ activity and comment data, I looked into aggregating comments from posts using the Google+ REST API. As useful as that is for specific posts, I was interested in pulling in “related” comments and posts. To do this, I took a look at the REST API for Google+ search. The general process for retrieving related comments and posts would then be as follows:

  • Search for activities and related content to a page
  • Retrieve comments for the search results
  • Render the results and comments

Refactoring the existing code…

Before I went into the process for performing these actions, I refactored my code from before to simplify the XHR calls.  The following code shows the simplified XHR calls with the same code used from before for comments and activity retrieval.

    // globals used for auth, showing debugging
    var debug = true;
    var key   = "somekey...";

    function performXHR(URL){
      var objReturn = "";      
      var request = new XMLHttpRequest();
      request.open('GET', URL, false);
      request.send(); // because of "false" above, will block until the request is done 
                      // and status is available. Not recommended, however it works for simple cases.

      if (request.status === 200) {
        if (debug) console.log(request.responseText);
        var objReturn = jQuery.parseJSON(request.responseText).items;

        if (debug){
          for (value in objReturn){
            console.log(value);
          }
        } 
      }else{
        handleRequestIssue(request);
      }
      return objReturn;
    }

    // Gets the activities for a profile
    function getActivities(profileID){
      var activities = null;      
      var URL        = "https://www.googleapis.com/plus/v1/people/" + profileID + "/activities/public?alt=json&key=" + key;
      activities     = performXHR(URL);
      console.log(activities.length);
      return activities;
    }

    function getCommentsForActivity(activityID){
      var comments = "";      
      var URL      = "https://www.googleapis.com/plus/v1/activities/" + activityID + "/comments?alt=json&key=" + key;
      comments     = performXHR(URL);
      return comments;
    }

    function handleRequestIssue(request){
        // For now, just can cry about it..
        console.log("khhhhaaaaann!!!, status:" + request.status + " /  response:" + request.responseText);
    }

At this point, adding additional endpoints and retrieving the JSON response from JavaScript is trivial. The activities search API uses such a pattern, so let’s just see how easy it is!

Searching using the API

Now that we have the ability to generically access the RESTful API, let’s add a new function for searching.  The pattern is nearly identical to the activity pattern:

https://www.googleaplis.com/plus/v1/activities?query=[yourquery]&key=[yourkey]

Because I will want to perform generic queries, it makes sense to just fill in that portion of the RESTful call and then pretty much have the rest of the function call fixed.  The following code shows what I ended up with:

    function searchForActivities(searchPhrase){
      var activities = "";
      var URL        = "https://www.googleapis.com/plus/v1/activities?query=" + searchPhrase + "&key=" + key;
      activities = performXHR(URL);
      return activities;
    }

Performing calls to the function searchForActivities with a reasonable query will now return content from Google+.

Finding related posts…

I experimented with the Google+ API a bit and determined that querying for my post by URL was insufficient. So, instead, I broadened my search by splitting up terms specific to the post: the post domain combined with the post’s end URL seems to be fairly effective at gathering related comments.  To test this out, I created an example page for search to comments that takes in a URL value in the form and will then try and gather all the comments it can from Google+. The following code shows how the query is formed and sent to the search function I created in the last step:

    function urlToQuery(url){
      var base = url.match(/\/\/[^\/]*/).toString().replace(/\//g,"");
      var name = url.match(/\/[^\/]*\/?$/).toString().replace(/\//g,"");

      return searchForActivities(base + " " + name);
    }

So now at this point, I will not only get my specific shares but also additional shares that happen on Google+. I can now render the posts using the same code that was used in my previous post for rendering activities and comments.

Rendering the posts and filtering SPAM

Aggregating comments like this is probably not the best idea. It would be really easy for someone to troll my blog by referencing it, similar to trackback spam.  However, it’s possible to implement a solution that prevents this kind of abuse by looking closely at the content that is being shared and to restrict aggregation from unknown activities.

The following code shows one more revision to the aforementioned code that will instead restrict the aggregation to a user (profileID):

    function renderActsComments(activities, identifier, filter){
        var renderMe = "";
        console.log("activities retrieved: " + activities.length);

        for (var i=0; i < activities.length; i++) {
          var render = true;
          console.log("trying to do something with an activity: " + i);
          var activity = activities[i];
          if (typeof(filter) != undefined){
            if (activity.crosspostSource.indexOf(filter) < 0){
              render = false;
            }
          }

          if (render){
            renderMe += "<br/><div class=\"article\"><p>" + activity.title + "</p>";
            console.log(activity.id);

            // get comments
            var comments = getCommentsForActivity(activity.id);
            var left = true;
            for (var j=0; j<comments.length; j++){
              if (left){
                left = false;
                renderMe += "<br/><p class=\"speech\">" + comments[j].object.content + "</p>";
                renderMe += "<a href=\"" + comments[j].actor.url + "\">" + comments[j].actor.displayName + "</a>";
                renderMe += "<a href=\"" + comments[j].actor.image.url.replace(/\?.*/, "") + "\">";
                renderMe += " <img border=0 src=\"" + comments[j].actor.image.url + "\"/></a>";
                renderMe += "</p>";
              }else{
                renderMe += "<br/><p class=\"speechAlt\">" + comments[j].object.content + "</p>";
                left = true;
                renderMe += "<p class=\"profileAlt\">";
                renderMe += "<a href=\"" + comments[j].actor.image.url.replace(/\?.*/, "") + "\">";
                renderMe += "<img border=0 src=\"" + comments[j].actor.image.url + "\"/></a>";
                renderMe += "<a href=\"" + comments[j].actor.url + "\"> " + comments[j].actor.displayName + "</a>";
                renderMe += "</p>";
              }
            }
            renderMe += "</div>";
          }
        }
        console.log("I'm done");

        document.getElementById(identifier).innerHTML = renderMe;
    }

In practice, this works to filter content by profile by performing calls to the function as:

renderActsComments(activities, "ac", "109716647623830091721");

(With the profileID passed in as the final string). Unfiltered rendering is performed by passing an empty string as the profileID:

renderActsComments(activities, "ac", "");

Thoughts and conclusions

Normally at this point I would say “kids, don’t try this at home”.  I mean, what I’ve thrown out here is a script that, given a URL, will pull sentiment around the web backed by Google+.  For your blog or business this could be pretty bad. However,  it’s  interesting to think about the possibilities. For example, what if you had a chrome extension that would gather sentiment for the sites you’re browsing? Or what about an auto-aggregating content sidebar for WordPress?  I think there’s a lot of cool things that you could potentially do built around the platform and infrastructure there is there to explore. Feel free to comment on the blog… or directly to my G+ account 🙂 Maybe I will make a sidebar gadget.