wiki.tcl 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. #
  2. # Mar 30 2010
  3. # by horgh
  4. #
  5. # Requires Tcl 8.5+ and tcllib
  6. #
  7. # Wikipedia.org fetcher
  8. #
  9. # To enable you must .chanset #channel +wiki
  10. #
  11. package require http
  12. package require htmlparse
  13. namespace eval wiki {
  14. variable max_lines 1
  15. variable output_cmd "putserv"
  16. variable url "http://en.wikipedia.org/wiki/"
  17. bind pub -|- "!w" wiki::search
  18. bind pub -|- "!wiki" wiki::search
  19. # variable parse_regexp {(<table class.*?<p>.*?</p>.*?</table>)??.*?<p>(.*?)</p>\n<table id="toc"}
  20. variable parse_regexp {</table>.*?<p>(.*)</p>.*?<table id="toc"}
  21. setudef flag wiki
  22. }
  23. proc wiki::fetch {term {url {}}} {
  24. if {$url != ""} {
  25. set token [http::geturl $url -timeout 10000]
  26. } else {
  27. set query [http::formatQuery $term]
  28. set token [http::geturl ${wiki::url}${query} -timeout 10000]
  29. }
  30. set data [http::data $token]
  31. set ncode [http::ncode $token]
  32. set meta [http::meta $token]
  33. upvar #0 $token state
  34. set fetched_url $state(url)
  35. http::cleanup $token
  36. # debug
  37. putlog "Fetch! term: $term url: $url fetched: $fetched_url"
  38. set fid [open "w-debug.txt" w]
  39. puts $fid $data
  40. close $fid
  41. # Follow redirects
  42. if {[regexp -- {^3\d{2}$} $ncode]} {
  43. return [wiki::fetch $term [dict get $meta Location]]
  44. }
  45. if {$ncode != 200} {
  46. error "HTTP query failed ($ncode): $data: $meta"
  47. }
  48. # If page returns list of results, choose the first one and fetch that
  49. if {[regexp -- {<p>.*?may refer to:</p>} $data]} {
  50. regexp -- {<ul>.*?<li>.*? title="(.*?)">.*?</li>} $data -> new_query
  51. return [wiki::fetch $new_query]
  52. }
  53. if {![regexp -- $wiki::parse_regexp $data -> out]} {
  54. error "Parse error"
  55. }
  56. return [list url $fetched_url result [wiki::sanitise $out]]
  57. }
  58. proc wiki::sanitise {raw} {
  59. set raw [htmlparse::mapEscapes $raw]
  60. # Remove pronunciation stuff
  61. set raw [regsub -- {<span.*? class="IPA">.*?</span>} $raw ""]
  62. # Remove some help links
  63. set raw [regsub -- {<small class="metadata">.*?</small>} $raw ""]
  64. set raw [regsub -all -- {<(.*?)>} $raw ""]
  65. set raw [regsub -all -- {\[.*?\]} $raw ""]
  66. set raw [regsub -all -- {\n} $raw " "]
  67. return $raw
  68. }
  69. proc wiki::search {nick uhost hand chan argv} {
  70. if {![channel get $chan wiki]} { return }
  71. if {[string length $argv] == 0} {
  72. $wiki::output_cmd "PRIVMSG $chan :Please provide a term."
  73. return
  74. }
  75. set argv [string trim $argv]
  76. if {[catch {wiki::fetch $argv} data]} {
  77. $wiki::output_cmd "PRIVMSG $chan :Error: $data"
  78. return
  79. }
  80. foreach line [wiki::split_line 400 [dict get $data result]] {
  81. if {[incr count] > $wiki::max_lines} {
  82. $wiki::output_cmd "PRIVMSG $chan :Output truncuated. [dict get $data url]"
  83. break
  84. }
  85. $wiki::output_cmd "PRIVMSG $chan :$line"
  86. }
  87. }
  88. # by fedex
  89. proc wiki::split_line {max str} {
  90. set last [expr {[string length $str] -1}]
  91. set start 0
  92. set end [expr {$max -1}]
  93. set lines []
  94. while {$start <= $last} {
  95. if {$last >= $end} {
  96. set end [string last { } $str $end]
  97. }
  98. lappend lines [string trim [string range $str $start $end]]
  99. set start $end
  100. set end [expr {$start + $max}]
  101. }
  102. return $lines
  103. }
  104. putlog "wiki.tcl loaded"