bash.tcl 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. # bash.org quote fetcher
  2. # Must .chanset #channel +bash
  3. #
  4. # Usage: !bash [optional search terms]
  5. # If search terms are not provided, fetch random quotes.
  6. #
  7. # Keeps fetched quotes in memory until displayed, including all results per
  8. # search term
  9. package require http
  10. package require htmlparse
  11. namespace eval ::bash {
  12. variable trigger !bash
  13. variable line_length 399
  14. variable max_lines 10
  15. variable useragent "Mozilla/5.0 (compatible; Y!J; for robot study; keyoshid)"
  16. variable output_cmd putserv
  17. setudef flag bash
  18. bind pub -|- $::bash::trigger ::bash::handler
  19. variable url http://bash.org/?
  20. variable list_regexp {<p class="quote">.*?<p class="qt">.*?</p>}
  21. variable quote_regexp {<p class="quote">.*?<b>#(.*?)</b>.*?class="qa".*?</a>\((.*?)\)<a.*?<p class="qt">(.*?)</p>}
  22. if {![info exists random_quotes]} {
  23. variable random_quotes []
  24. }
  25. if {![info exists search_quotes]} {
  26. variable search_quotes []
  27. }
  28. }
  29. proc ::bash::quote_output {chan quote} {
  30. if {$quote == ""} {
  31. $::bash::output_cmd "PRIVMSG $chan :No result!"
  32. return
  33. }
  34. set number [dict get $quote number]
  35. set rating [dict get $quote rating]
  36. set quote [::htmlparse::mapEscapes [dict get $quote quote]]
  37. set quote [regsub -all -- {<br />} $quote ""]
  38. $::bash::output_cmd "PRIVMSG $chan :#\002${number}\002 (Rating: ${rating})"
  39. foreach line [split $quote \n] {
  40. if {[incr count] > $::bash::max_lines} {
  41. $::bash::output_cmd "PRIVMSG $chan :Output truncated. ${::bash::url}${number}"
  42. break
  43. }
  44. foreach subline [::bash::split_line $::bash::line_length $line] {
  45. $::bash::output_cmd "PRIVMSG $chan : $subline"
  46. }
  47. }
  48. }
  49. proc ::bash::handler {nick uhost hand chan argv} {
  50. if {![channel get $chan bash]} { return }
  51. if {$argv == ""} {
  52. if {[catch {::bash::random $chan} result]} {
  53. $::bash::output_cmd "PRIVMSG $chan :Error: $result"
  54. return
  55. }
  56. ::bash::quote_output $chan $result
  57. } else {
  58. if {[catch {::bash::search $argv $chan} result]} {
  59. $::bash::output_cmd "PRIVMSG $chan :Error: $result"
  60. return
  61. }
  62. ::bash::quote_output $chan $result
  63. }
  64. }
  65. proc ::bash::random {chan} {
  66. if {![llength $::bash::random_quotes]} {
  67. $::bash::output_cmd "PRIVMSG $chan :Fetching new random quotes..."
  68. set ::bash::random_quotes [::bash::fetch ${::bash::url}random1]
  69. }
  70. set quote [lindex $::bash::random_quotes 0]
  71. set ::bash::random_quotes [lreplace $::bash::random_quotes 0 0]
  72. return $quote
  73. }
  74. proc ::bash::search {query chan} {
  75. if {![dict exists $::bash::search_quotes $query]} {
  76. $::bash::output_cmd "PRIVMSG $chan :Fetching results..."
  77. set url ${::bash::url}[::http::formatQuery search $query sort 0 show 25]
  78. dict set ::bash::search_quotes $query [::bash::fetch $url]
  79. }
  80. set quotes [dict get $::bash::search_quotes $query]
  81. set quote [lindex $quotes 0]
  82. set quotes [lreplace $quotes 0 0]
  83. # Remove key if no more quotes after removal of one, else set quotes to remaining
  84. if {![llength $quotes]} {
  85. dict unset ::bash::search_quotes $query
  86. } else {
  87. dict set ::bash::search_quotes $query $quotes
  88. }
  89. return $quote
  90. }
  91. proc ::bash::fetch {url} {
  92. ::http::config -useragent $::bash::useragent
  93. set token [::http::geturl $url -timeout 10000]
  94. set data [::http::data $token]
  95. set ncode [::http::ncode $token]
  96. ::http::cleanup $token
  97. if {$ncode != 200} {
  98. error "HTTP fetch error $ncode: $data"
  99. }
  100. return [::bash::parse $data]
  101. }
  102. proc ::bash::parse {html} {
  103. set quotes []
  104. foreach raw_quote [regexp -all -inline -- $::bash::list_regexp $html] {
  105. if {[regexp $::bash::quote_regexp $raw_quote -> number rating quote]} {
  106. lappend quotes [list number $number rating $rating quote $quote]
  107. } else {
  108. error "Parse error"
  109. }
  110. }
  111. return $quotes
  112. }
  113. # by fedex
  114. proc ::bash::split_line {max str} {
  115. set last [expr {[string length $str] -1}]
  116. set start 0
  117. set end [expr {$max -1}]
  118. set lines []
  119. while {$start <= $last} {
  120. if {$last >= $end} {
  121. set end [string last { } $str $end]
  122. }
  123. lappend lines [string trim [string range $str $start $end]]
  124. set start $end
  125. set end [expr {$start + $max}]
  126. }
  127. return $lines
  128. }
  129. putlog "bash.tcl loaded"