-
Notifications
You must be signed in to change notification settings - Fork 21
/
google.tcl
205 lines (165 loc) · 5.02 KB
/
google.tcl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
#
# 0.3 - ?
# - switch from decode_html to htmlparse::mapEscape
# - fix issue with encoding getting ascii
# - add !g1 for one result
# - strip remaining html from api result
#
# 0.2 - May 10 2010
# - fix for garbled utf chars in api queries
# - added +google channel flag to enable
# - strip html from !convert as some formatting may be present
# - fix decode_html to convert html utf to hex
# - convert <sup></sup> to exponent
#
# 0.1 - Some time in April 2010
# - Initial release
#
# Created Feb 28 2010
#
# License: Public domain
#
# Requires Tcl 8.5+
# Requires tcllib for json
#
package require http
package require json
package require htmlparse
namespace eval google {
#variable output_cmd "cd::putnow"
variable output_cmd "putserv"
# Not enforced for API queries
variable useragent "Lynx/2.8.8dev.2 libwww-FM/2.14 SSL-MM/1.4.1"
variable convert_url "http://www.google.ca/search"
variable convert_regexp {<table class=std>.*?<b>(.*?)</b>.*?</table>}
variable api_url "http://ajax.googleapis.com/ajax/services/search/"
variable api_referer "http://www.nyit-nyit.net"
bind pub -|- "!g" google::search
bind pub -|- "!google" google::search
bind pub -|- "!g1" google::search1
bind pub -|- "!news" google::news
bind pub -|- "!images" google::images
bind pub -|- "!convert" google::convert
setudef flag google
}
proc google::convert_fetch {terms} {
http::config -useragent $google::useragent
set query [http::formatQuery q $terms]
set token [http::geturl ${google::convert_url}?${query}]
set data [http::data $token]
set ncode [http::ncode $token]
http::cleanup $token
# debug
#set fid [open "g-debug.txt" w]
#puts $fid $data
#close $fid
if {$ncode != 200} {
error "HTTP query failed: $ncode"
}
return $data
}
proc google::convert_parse {html} {
if {![regexp -- $google::convert_regexp $html -> result]} {
error "Parse error or no result"
}
set result [htmlparse::mapEscapes $result]
# change <sup>num</sup> to ^num (exponent)
set result [regsub -all -- {<sup>(.*?)</sup>} $result {^\1}]
# strip rest of html code
return [regsub -all -- {<.*?>} $result ""]
}
# Query normal html for conversions
proc google::convert {nick uhost hand chan argv} {
if {![channel get $chan google]} { return }
if {[string length $argv] == 0} {
$google::output_cmd "PRIVMSG $chan :Please provide a query."
return
}
if {[catch {google::convert_fetch $argv} data]} {
$google::output_cmd "PRIVMSG $chan :Error fetching results: $data."
return
}
if {[catch {google::convert_parse $data} result]} {
$google::output_cmd "PRIVMSG $chan :Error: $result."
return
}
$google::output_cmd "PRIVMSG $chan :\002$result\002"
}
# Output for results from api query
proc google::output {chan url title content} {
regsub -all -- {(?:<b>|</b>)} $title "\002" title
regsub -all -- {<.*?>} $title "" title
set output "$title @ $url"
$google::output_cmd "PRIVMSG $chan :[htmlparse::mapEscapes $output]"
}
# Return results from API query of $url
proc google::api_fetch {terms url} {
set query [http::formatQuery v "1.0" q $terms safe off]
set headers [list Referer $google::api_referer]
set token [http::geturl ${url}?${query} -headers $headers -method GET]
set data [http::data $token]
set ncode [http::ncode $token]
http::cleanup $token
# debug
#set fid [open "g-debug.txt" w]
#fconfigure $fid -translation binary -encoding binary
#puts $fid $data
#close $fid
if {$ncode != 200} {
error "HTTP query failed: $ncode"
}
return [json::json2dict $data]
}
# Validate input and then return list of results
proc google::api_validate {argv url} {
if {[string length $argv] == 0} {
error "Please supply search terms."
}
if {[catch {google::api_fetch $argv $url} data]} {
error "Error fetching results: $data."
}
set response [dict get $data responseData]
set results [dict get $response results]
if {[llength $results] == 0} {
error "No results."
}
return $results
}
# Query api
proc google::api_handler {chan argv url {num {}}} {
if {[catch {google::api_validate $argv $url} results]} {
$google::output_cmd "PRIVMSG $chan :$results"
return
}
foreach result $results {
if {$num != "" && [incr count] > $num} {
return
}
dict with result {
# $language holds lang in news results, doesn't exist in web results
if {![info exists language] || $language == "en"} {
google::output $chan $unescapedUrl $title $content
}
}
}
}
# Regular API search
proc google::search {nick uhost hand chan argv} {
if {![channel get $chan google]} { return }
google::api_handler $chan $argv ${google::api_url}web
}
# Regular API search, 1 result
proc google::search1 {nick uhost hand chan argv} {
if {![channel get $chan google]} { return }
google::api_handler $chan $argv ${google::api_url}web 1
}
# News from API
proc google::news {nick uhost hand chan argv} {
if {![channel get $chan google]} { return }
google::api_handler $chan $argv ${google::api_url}news
}
# Images from API
proc google::images {nick uhost hand chan argv} {
if {![channel get $chan google]} { return }
google::api_handler $chan $argv ${google::api_url}images
}