1
0

bash.tcl 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  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. variable random_quotes []
  23. variable search_quotes []
  24. }
  25. proc ::bash::quote_output {chan quote} {
  26. if {$quote == ""} {
  27. $::bash::output_cmd "PRIVMSG $chan :No result!"
  28. return
  29. }
  30. set number [dict get $quote number]
  31. set rating [dict get $quote rating]
  32. set quote [::htmlparse::mapEscapes [dict get $quote quote]]
  33. set quote [regsub -all -- {<br />} $quote ""]
  34. $::bash::output_cmd "PRIVMSG $chan :#\002${number}\002 (Rating: ${rating})"
  35. foreach line [split $quote \n] {
  36. if {[incr count] > $::bash::max_lines} {
  37. $::bash::output_cmd "PRIVMSG $chan :Output truncated. ${::bash::url}${number}"
  38. break
  39. }
  40. foreach subline [::bash::split_line $::bash::line_length $line] {
  41. $::bash::output_cmd "PRIVMSG $chan : $subline"
  42. }
  43. }
  44. }
  45. proc ::bash::handler {nick uhost hand chan argv} {
  46. if {![channel get $chan bash]} { return }
  47. if {$argv == ""} {
  48. if {[catch {::bash::random $chan} result]} {
  49. $::bash::output_cmd "PRIVMSG $chan :Error: $result"
  50. return
  51. }
  52. ::bash::quote_output $chan $result
  53. } else {
  54. if {[catch {::bash::search $argv $chan} result]} {
  55. $::bash::output_cmd "PRIVMSG $chan :Error: $result"
  56. return
  57. }
  58. ::bash::quote_output $chan $result
  59. }
  60. }
  61. proc ::bash::random {chan} {
  62. if {![llength $::bash::random_quotes]} {
  63. $::bash::output_cmd "PRIVMSG $chan :Fetching new random quotes..."
  64. set ::bash::random_quotes [::bash::fetch ${::bash::url}random1]
  65. }
  66. set quote [lindex $::bash::random_quotes 0]
  67. set ::bash::random_quotes [lreplace $::bash::random_quotes 0 0]
  68. return $quote
  69. }
  70. proc ::bash::search {query chan} {
  71. if {![dict exists $::bash::search_quotes $query]} {
  72. $::bash::output_cmd "PRIVMSG $chan :Fetching results..."
  73. set url ${::bash::url}[::http::formatQuery search $query sort 0 show 25]
  74. dict set ::bash::search_quotes $query [::bash::fetch $url]
  75. }
  76. set quotes [dict get $::bash::search_quotes $query]
  77. set quote [lindex $quotes 0]
  78. set quotes [lreplace $quotes 0 0]
  79. # Remove key if no more quotes after removal of one, else set quotes to remaining
  80. if {![llength $quotes]} {
  81. dict unset ::bash::search_quotes $query
  82. } else {
  83. dict set ::bash::search_quotes $query $quotes
  84. }
  85. return $quote
  86. }
  87. proc ::bash::fetch {url} {
  88. ::http::config -useragent $::bash::useragent
  89. set token [::http::geturl $url -timeout 10000]
  90. set data [::http::data $token]
  91. set ncode [::http::ncode $token]
  92. ::http::cleanup $token
  93. if {$ncode != 200} {
  94. error "HTTP fetch error $ncode: $data"
  95. }
  96. return [::bash::parse $data]
  97. }
  98. proc ::bash::parse {html} {
  99. set quotes []
  100. foreach raw_quote [regexp -all -inline -- $::bash::list_regexp $html] {
  101. if {![regexp $::bash::quote_regexp $raw_quote -> number rating quote]} {
  102. error "Parse error"
  103. }
  104. # Strip <font color=green|red> from rating
  105. regsub -all {<font.*?>} $rating {} rating
  106. regsub -all {</font>} $rating {} rating
  107. lappend quotes [list number $number rating $rating quote $quote]
  108. }
  109. return $quotes
  110. }
  111. # by fedex
  112. proc ::bash::split_line {max str} {
  113. set last [expr {[string length $str] -1}]
  114. set start 0
  115. set end [expr {$max -1}]
  116. set lines []
  117. while {$start <= $last} {
  118. if {$last >= $end} {
  119. set end [string last { } $str $end]
  120. }
  121. lappend lines [string trim [string range $str $start $end]]
  122. set start $end
  123. set end [expr {$start + $max}]
  124. }
  125. return $lines
  126. }
  127. putlog "bash.tcl loaded"