Commits

firefly  committed 691bcb6

Fixed redirections for the wikipedia lookup module, and also fixed a bunch of
other things.

  • Participants
  • Parent commits d67ad4e

Comments (0)

Files changed (4)

File modules/01-command-trigger.coffee

 		(getPrefix line)?
 
 	call: (conn, msg) ->
-		console.log "Calling commandTrigger for #{msg}"
+		console.log "Calling commandTrigger for", msg
 
 		prefix = getPrefix msg.message
 		# TODO: fetch rest of line here as well...

File modules/05-commands.coffee

 				
 				supDigitsMap = ("\u2070\u00b9\u00b2\u00b3\u2074\u2075\u2076" +
 							    "\u2077\u2078\u2079").split ""
-				supDigitsMap["-"] = "\207b"
+				supDigitsMap["-"] = "\u207b"
 				
 				beautify = (str) ->
 					str = str.replace /<sup>([^<]+)<\/sup>/g, (_, value) ->

File modules/05-wikipedia/index.js

 bot.triggers.command.add('w', {
   help: "Fetches information from Wikipedia.",
   exec: function(data) {
-    var self = this
+    var self  = this
+      , ident = parseIdent(data.line)
 
-    var title = data.line
-      , subdomain
-
-    // Handle interwiki prefixes; either two- or three-char language code or
-    // one of a number of special prefixes.
-    if (match = title.match(/^([a-z]{2,3}|simple):(.*)/i)) {
-        subdomain= match[1].toLowerCase()
-        title     = match[2]
-    } else {
-        subdomain = 'en'
-    }
+    var title     = ident.title
+      , subdomain = ident.namespace
 
     var encodedTitle = encodeURIComponent(title).replace(/%20/g, '_')
 
     console.log("Fetching %s from %s...", encodedTitle, subdomain)
 
+    // Responds with the given article.
+    function respondWith(tree) {
+      var content  = tree.headings[0].content
+        , result   = stringifier.stringifyArr(content, substitutor)
+        , match    = result.match(/^(?:[^.]|\.(?! ))+\./)
+        , response = match ? match[0] : result
+
+      // We don't want any newlines in the IRC output...
+      response = response.replace(/\n/g, " ")
+
+      // Make sure that the response isn't too long...
+      if (response.length > 200) {
+        response = response.slice(0, 199) + "\u2026" // Ellipsis
+      }
+
+      // Add the wikipedia URL to the response
+      var niceURL = "<http://en.wikipedia.org/wiki/" + encodedTitle + ">"
+      if (niceURL.length > 130) {
+        niceURL = "[URL too long]"
+      }
+      response += "  " + niceURL
+
+      // ...and reply!
+      self.reply("\x03" + response)
+    }
+
     backend.net.get(subdomain + ".wikipedia.org/w/index.php",
       { "action" : "raw"
       , "title"  : encodedTitle
         if (!done) return
         if (err) throw err
 
+        // Check that we actually got data from the server--otherwise, the
+        // article wasn't found.
         if (data.length == 0) {
           self.reply("Article not found.")
           return
         }
 
+        // Parse the data, and make sure that we actually got correct data back
+        // from the parser.  Just a sanity check to catch & report parser bugs.
         var tree = wikiParser.parse(data, true)
         if (!tree.headings || !tree.headings[0]) {
           self.error(new Error("Couldn't parse article! Parser bug?"))
           return
         }
 
-        var content  = tree.headings[0].content
-          , result   = stringifier.stringifyArr(content, substitutor)
-          , match    = result.match(/^(?:[^.]|\.(?! ))+\./)
-          , response = match ? match[0] : result
+        // Check for redirection
+        var redirTarget = getRedirection(tree)
 
-        // Replace newlines
-        response = response.replace(/\n/g, " ")
+        if (redirTarget != null) {
+          var redirEncoded = encodeURIComponent(redirTarget).replace(/%20/g, '_')
 
-        // Make sure that the response isn't too long...
-        if (response.length > 200) {
-          response = response.slice(0, 199) + "\u2026" // Ellipsis
+          backend.net.get(subdomain + ".wikipedia.org/w/index.php",
+            { "action" : "raw"
+            , "title"  : redirEncoded
+            }, function(err, data, done) {
+              if (!done) return
+              if (err) throw err
+
+              // Check that we actually got data from the server--otherwise, the
+              // article wasn't found.
+              if (data.length == 0) {
+                self.reply("Article not found.")
+                return
+              }
+
+              // Parse the data, and make sure that we actually got correct data back
+              // from the parser.  Just a sanity check to catch & report parser bugs.
+              var tree = wikiParser.parse(data, true)
+              if (!tree.headings || !tree.headings[0]) {
+                self.error(new Error("Couldn't parse article! Parser bug?"))
+                return
+              }
+
+              // Check for redirection
+              var redirTarget = getRedirection(tree)
+
+              if (redirTarget != null) {
+                self.error(new Error("Double redirection!"))
+                return
+              }
+
+              // Respond
+              respondWith(tree)
+            })
+
+        } else {
+          // No redirection
+          respondWith(tree)
         }
-
-        // Add the wikipedia URL to the response
-        var niceURL = "<http://en.wikipedia.org/wiki/" + encodedTitle + ">"
-        if (niceURL.length > 130) {
-          niceURL = "[URL too long]"
-        }
-        response += "  " + niceURL
-
-        self.reply("\x03" + response)
       })
 
+    // Parses an ident (either just title, or namespace:title) into its separate
+    // components.  The default namespace is "en".
+    //   For Wikipedia this is useful for interwiki prefixes--two- or three-char
+    // langauge codes or a number of special prefixes.
+    function parseIdent(ident) {
+      var matches
+        , identPat = /^([a-z]{2,3}|simple):(.*)/i
+
+      if (matches = ident.match(identPat)) {
+        return { namespace : matches[1].toLowerCase()
+               , title     : matches[2] }
+
+      } else {
+        return { namespace : "en"
+               , title     : ident }
+      }
+    }
+
+    // Gets the target article of a redirection from a parse tree.
+    function getRedirection(tree) {
+      if ( tree.name == 'root'
+
+        // First child has to be a '#' list
+        && tree.content[0]
+        && tree.content[0].name == 'list'
+        && tree.content[0].type == '#'
+
+        // First child of *that* node has to be a list-node
+        && tree.content[0].content[0]
+        && tree.content[0].content[0].name == 'list-node'
+
+        // First child of *that* node has to be a string "REDIRECT",
+        // followed by a wikilink which points to the redirection target.
+        && tree.content[0].content[0].content[0].match(/^\s*REDIRECT\s*$/i)
+        && tree.content[0].content[0].content[1].name == 'wikilink'
+         ) {
+        var target = tree.content[0].content[0].content[1].target
+        return target
+
+      } else {
+        // No redirection found--signal this by returning null
+        return null
+      }
+    }
+
+    // Encodes a title to be part of a mediawiki URL
     function encodeTitle(str) {
       return encodeURIComponent(str).replace(/%20/g, '_')
-                               .replace(/[()]/g, urlEscape)
+                                    .replace(/[()]/g, urlEscape)
 
       function urlEscape(chr) {
         var hex = chr.charCodeAt().toString(16)

File src/eldis4.js

-
 var util   = require('util')
   , vm     = require('vm')
   , fs     = require('fs')
   , events = require('events')
-
-  , fomatto = require('fomatto')
-  , bot     = require('./bot')
-
-//{EventEmitter} = require 'events'
-//{Formatter}    = require 'fomatto'
-//{Bot, backend} = require '../lib/bot'
+  , bot    = require('./bot')
 
 // Shared string formatter
-var format = new fomatto.Formatter()
 
 function Eldis4() {
 	bot.Bot.call(this)
 			, bot        : eldis4
 			, module     : moduleObj
 			, backend    : bot.backend
-			, format     : format
 			}
 		
 		eldis4.modules.contexts[name] = ctx
 			if (matches = filename.match(/^(.*)\.js$/)) {
 				eldis4.modules.load(matches[1], false)
 
-			} else if (filename.match(/^[^.]+$/)) {
+			} else if (filename.match(/^[^.]*[^.~]$/)) {
 				eldis4.modules.load(filename, true)
 			}
 		})