Created
April 20, 2012 15:36
-
-
Save ianpreston/2429681 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var sys = require("sys"), | |
http = require("http"), | |
querystring = require("querystring"), | |
htmlparser = require("htmlparser"), | |
soupselect = require("soupselect"), | |
irc = require("irc"); | |
/** | |
* Wrapper for making an HTTP request, reading the data, instantiating a htmlparser.Parser | |
* and parsing the page. htmlparserHandlerFunction will be passed to htmlparser.DefualtHandler. | |
*/ | |
var fetchAndParsePage = function(host, path, htmlparserHandlerFunction) { | |
var request = http.createClient(80, host).request("GET", path, {"host": host}); | |
request.on("response", function(response) { | |
response.setEncoding("utf8"); | |
var body = ""; | |
response.on("data", function(chunk) { | |
body += chunk; | |
}); | |
response.on("end", function() { | |
var handler = new htmlparser.DefaultHandler(htmlparserHandlerFunction); | |
var parser = new htmlparser.Parser(handler); | |
parser.parseComplete(body); | |
}); | |
}); | |
request.end(); | |
}; | |
/** | |
* Search CalorieKing's database and call a function with the path to the food that | |
* is the result of the search. Path is in the format '/foo/bar' relative to www.calorieking.com | |
* | |
* arg:searchString = The name of the food to search for | |
* arg:pathCallback = pathCallback(error, path) will be called when the URL is parsed from the page | |
*/ | |
var getNutritionFactsPath = function(searchString, pathCallback) { | |
fetchAndParsePage("www.calorieking.com", | |
"http://www.calorieking.com/foods/search.php?" + querystring.stringify({"keywords": searchString, "go": "Search", "showresults": "yes"}), | |
function(error, dom) { | |
if (error) { | |
console.log("Error! " + error); | |
} else { | |
var foodLinks = soupselect.select(dom, ".food-search-result-name"); | |
if (foodLinks[0]) | |
{ | |
pathCallback(null, foodLinks[0].attribs.href); | |
} else { | |
pathCallback("No results for food search '" + searchString + "'", null); | |
} | |
} | |
}); | |
}; | |
/** | |
* Parses a CalorieKing nutrition facts page and returns relevant information. | |
* | |
* arg:nutritionFactsPath = the result of getNutritionFactsPath | |
* arg:factsCallback = factsCallback(object) will be called with the parsed nutrition facts | |
*/ | |
var parseFacts = function(nutritionFactsPath, factsCallback) { | |
fetchAndParsePage("www.calorieking.com", | |
nutritionFactsPath, | |
function(error, dom) { | |
if (error) { | |
console.log("Error!:" + error); | |
} else { | |
var foodNameSpan = soupselect.select(dom, "#heading-food-cat-desc")[0]; | |
factsCallback({"carbs": soupselect.select(dom, "#total_carbohydrate")[0].children[0].raw.replace(""", "'").replace("&", "&"), | |
"servingSize": soupselect.select(dom, "#units option")[0].children[0].raw.replace(""", "'").replace("&", "&"), | |
"foodName": foodNameSpan.children[foodNameSpan.children.length-1].raw.replace(""", "'").replace("&", "&").trim()}); | |
} | |
}); | |
}; | |
/** | |
* Now we just join an IRC channel and wait for !carbs messages | |
*/ | |
var main = function() { | |
var client = new irc.Client("localhost", "carbs-bot", { | |
"userName": "carbs", | |
"realName": "carbs-bot", | |
"channels": ["#carbs-bot"], | |
"autoRejoin": false}); | |
client.addListener("message", function(from, to, msg) { | |
if (msg.indexOf("!carbs") == 0) | |
{ | |
var searchString = msg.substr("!carbs ".length); | |
getNutritionFactsPath(searchString, function(error, path) { | |
if (error) | |
{ | |
client.say(to, "Error: " + error); | |
} else { | |
parseFacts(path, function(facts) { | |
client.say(to, "Nutrition facts for " + facts.foodName); | |
client.say(to, facts.carbs + " carbs in one serving of " + facts.servingSize); | |
client.say(to, "Details: " + path); | |
}); | |
} | |
}); | |
} | |
}); | |
}; | |
main(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment