| 1 | #!/usr/bin/env ruby |
|---|
| 2 | # estraier-search.rb $Revision: 1.1.2.12 $ |
|---|
| 3 | # |
|---|
| 4 | # Copyright (C) 2007 Kazuhiko <kazuhiko@fdiary.net> |
|---|
| 5 | # You can redistribute it and/or modify it under GPL2. |
|---|
| 6 | # |
|---|
| 7 | $KCODE= 'u' |
|---|
| 8 | BEGIN { $stdout.binmode } |
|---|
| 9 | |
|---|
| 10 | require "estraierpure" |
|---|
| 11 | require "enumerator" |
|---|
| 12 | require "date" |
|---|
| 13 | |
|---|
| 14 | if FileTest::symlink?( __FILE__ ) then |
|---|
| 15 | org_path = File::dirname( File::readlink( __FILE__ ) ) |
|---|
| 16 | else |
|---|
| 17 | org_path = File::dirname( __FILE__ ) |
|---|
| 18 | end |
|---|
| 19 | $:.unshift( org_path.untaint ) |
|---|
| 20 | require 'tdiary' |
|---|
| 21 | |
|---|
| 22 | # |
|---|
| 23 | # class TDiaryEstraier |
|---|
| 24 | # |
|---|
| 25 | module TDiary |
|---|
| 26 | class TDiaryEstraier < ::TDiary::TDiaryBase |
|---|
| 27 | MAX_PAGES = 20 |
|---|
| 28 | SORT_OPTIONS = [ |
|---|
| 29 | ["score", "スコア順"], |
|---|
| 30 | ["date", "日付順"], |
|---|
| 31 | ] |
|---|
| 32 | ORDER_OPTIONS = [ |
|---|
| 33 | ["asc", "昇順"], |
|---|
| 34 | ["desc", "降順"], |
|---|
| 35 | ] |
|---|
| 36 | FORM_OPTIONS = [ |
|---|
| 37 | ["simple", "簡便書式"], |
|---|
| 38 | ["normal", "通常書式"], |
|---|
| 39 | ] |
|---|
| 40 | NUM_OPTIONS = [10, 20, 30, 50, 100] |
|---|
| 41 | |
|---|
| 42 | def initialize( cgi, rhtml, conf ) |
|---|
| 43 | super |
|---|
| 44 | @host = @conf["estraier.host"] || "localhost" |
|---|
| 45 | @port = @conf["estraier.port"] || 1978 |
|---|
| 46 | @path = @conf["estraier.path"] || "/node/" |
|---|
| 47 | @node = @conf["estraier.node"] || "tdiary" |
|---|
| 48 | parse_args |
|---|
| 49 | format_form |
|---|
| 50 | if @query.empty? |
|---|
| 51 | @msg = '検索条件を入力して、「検索」ボタンを押してください' |
|---|
| 52 | else |
|---|
| 53 | search |
|---|
| 54 | end |
|---|
| 55 | end |
|---|
| 56 | |
|---|
| 57 | def load_plugins |
|---|
| 58 | super |
|---|
| 59 | # add a opensearch rss link |
|---|
| 60 | @plugin.instance_variable_get('@header_procs').unshift Proc.new { |
|---|
| 61 | cgi_url = @conf.base_url.sub(%r|/[^/]*$|, '/') + (@cgi.script_name ? _(File.basename(@cgi.script_name)) : '') |
|---|
| 62 | %Q|\t<link rel="alternate" type="application/rss+xml" title="Search Result RSS" href="#{cgi_url}#{format_anchor(@start, @num)};type=rss">\n| |
|---|
| 63 | } |
|---|
| 64 | # override some plugins |
|---|
| 65 | def @plugin.sn(number = nil); ''; end |
|---|
| 66 | def @plugin.whats_new; ''; end |
|---|
| 67 | end |
|---|
| 68 | |
|---|
| 69 | def eval_rxml |
|---|
| 70 | require 'time' |
|---|
| 71 | load_plugins |
|---|
| 72 | ERB::new( File::open( "#{PATH}/skel/estraier.rxml" ){|f| f.read }.untaint ).result( binding ) |
|---|
| 73 | end |
|---|
| 74 | |
|---|
| 75 | private |
|---|
| 76 | |
|---|
| 77 | def parse_args |
|---|
| 78 | @query = @cgi["query"].strip |
|---|
| 79 | @start = @cgi["start"].to_i |
|---|
| 80 | @num = @cgi["num"].to_i |
|---|
| 81 | if @num < 1 |
|---|
| 82 | @num = 10 |
|---|
| 83 | elsif @num > 100 |
|---|
| 84 | @num = 100 |
|---|
| 85 | end |
|---|
| 86 | @sort = @cgi["sort"].empty? ? "score" : @cgi["sort"] |
|---|
| 87 | @order = @cgi["order"].empty? ? "desc" : @cgi["order"] |
|---|
| 88 | @form = @cgi["form"].empty? ? "simple" : @cgi["form"] |
|---|
| 89 | end |
|---|
| 90 | |
|---|
| 91 | def search |
|---|
| 92 | @db = EstraierPure::Node.new |
|---|
| 93 | @db.set_url("http://#{@host}:#{@port}#{@path}#{@node}") |
|---|
| 94 | begin |
|---|
| 95 | t = Time.now |
|---|
| 96 | cond = create_search_options |
|---|
| 97 | cond.set_phrase(convert(@query)) |
|---|
| 98 | @result = @db.search(cond, 0) |
|---|
| 99 | @secs = Time.now - t |
|---|
| 100 | rescue |
|---|
| 101 | @msg = "エラー: #{_($!.to_s + $@.join)}</p>" |
|---|
| 102 | end |
|---|
| 103 | end |
|---|
| 104 | |
|---|
| 105 | def format_result_item(item) |
|---|
| 106 | @date = item.attr('@uri') |
|---|
| 107 | if @conf["estraier.with_user_name"] |
|---|
| 108 | @date.gsub!(/.*:/, "") |
|---|
| 109 | end |
|---|
| 110 | @date_str = Date.parse(@date).strftime(@conf.date_format) |
|---|
| 111 | @last_modified = item.attr('@mdate') |
|---|
| 112 | @title = _(item.attr('@title')) |
|---|
| 113 | @summary = _(item.snippet).gsub(/\t.*/, "").gsub(/\n\n/, " ... ").gsub(/\n/, "") |
|---|
| 114 | for term in @query.split |
|---|
| 115 | @title.gsub!(Regexp.new(Regexp.quote(CGI.escapeHTML(term)), true, @encoding), "<strong>\\&</strong>") |
|---|
| 116 | @summary.gsub!(Regexp.new(Regexp.quote(CGI.escapeHTML(term)), true, @encoding), "<strong>\\&</strong>") |
|---|
| 117 | end |
|---|
| 118 | query = "[SIMILAR]" |
|---|
| 119 | item.keywords.split(/\t/).enum_slice(2).collect do |k, s| |
|---|
| 120 | query << " WITH #{s} #{k}" |
|---|
| 121 | end |
|---|
| 122 | @similar = "%s?query=%s" % |
|---|
| 123 | [_(@cgi.script_name || ""), CGI::escape(query)] |
|---|
| 124 | end |
|---|
| 125 | |
|---|
| 126 | def format_links(result) |
|---|
| 127 | page_count = (result.doc_num - 1) / @num + 1 |
|---|
| 128 | current_page = @start / @num + 1 |
|---|
| 129 | first_page = current_page - (MAX_PAGES / 2 - 1) |
|---|
| 130 | if first_page < 1 |
|---|
| 131 | first_page = 1 |
|---|
| 132 | end |
|---|
| 133 | last_page = first_page + MAX_PAGES - 1 |
|---|
| 134 | if last_page > page_count |
|---|
| 135 | last_page = page_count |
|---|
| 136 | end |
|---|
| 137 | buf = "<p class=\"infobar\">\n" |
|---|
| 138 | if current_page > 1 |
|---|
| 139 | buf.concat(format_link("前へ", @start - @num, @num)) |
|---|
| 140 | end |
|---|
| 141 | if first_page > 1 |
|---|
| 142 | buf.concat("... ") |
|---|
| 143 | end |
|---|
| 144 | for i in first_page..last_page |
|---|
| 145 | if i == current_page |
|---|
| 146 | buf.concat("#{i} ") |
|---|
| 147 | else |
|---|
| 148 | buf.concat(format_link(i.to_s, (i - 1) * @num, @num)) |
|---|
| 149 | end |
|---|
| 150 | end |
|---|
| 151 | if last_page < page_count |
|---|
| 152 | buf.concat("... ") |
|---|
| 153 | end |
|---|
| 154 | if current_page < page_count |
|---|
| 155 | buf.concat(format_link("次へ", @start + @num, @num)) |
|---|
| 156 | end |
|---|
| 157 | buf.concat("</p>\n") |
|---|
| 158 | return buf |
|---|
| 159 | end |
|---|
| 160 | |
|---|
| 161 | def format_anchor(start, num) |
|---|
| 162 | return format('?query=%s;start=%d;num=%d;sort=%s;order=%s', CGI::escape(@query), start, num, _(@sort), _(@order)) |
|---|
| 163 | end |
|---|
| 164 | |
|---|
| 165 | def format_link(label, start, num) |
|---|
| 166 | return format('<a href="%s%s">%s</a> ', _(@cgi.script_name ? @cgi.script_name : ""), format_anchor(start, num), _(label)) |
|---|
| 167 | end |
|---|
| 168 | |
|---|
| 169 | def create_search_options |
|---|
| 170 | cond = EstraierPure::Condition.new |
|---|
| 171 | if @conf["estraier.with_user_name"] |
|---|
| 172 | cond.add_attr("@uri STRBW #{@conf.user_name}:") |
|---|
| 173 | end |
|---|
| 174 | if @sort == "date" |
|---|
| 175 | order = "@uri" |
|---|
| 176 | else |
|---|
| 177 | order = "" |
|---|
| 178 | end |
|---|
| 179 | if @order == "asc" |
|---|
| 180 | order = "[SCA]" if order.empty? |
|---|
| 181 | else |
|---|
| 182 | unless order.empty? |
|---|
| 183 | order << " STRD" |
|---|
| 184 | end |
|---|
| 185 | end |
|---|
| 186 | if @form == "simple" |
|---|
| 187 | cond.set_options(EstraierPure::Condition::SIMPLE) |
|---|
| 188 | end |
|---|
| 189 | cond.set_order(order) |
|---|
| 190 | return cond |
|---|
| 191 | end |
|---|
| 192 | |
|---|
| 193 | def format_options(options, value) |
|---|
| 194 | return options.collect { |val, label| |
|---|
| 195 | if val == value |
|---|
| 196 | "<option value=\"#{_(val)}\" selected>#{_(label)}</option>" |
|---|
| 197 | else |
|---|
| 198 | "<option value=\"#{_(val)}\">#{_(label)}</option>" |
|---|
| 199 | end |
|---|
| 200 | }.join("\n") |
|---|
| 201 | end |
|---|
| 202 | |
|---|
| 203 | def format_form |
|---|
| 204 | @num_options = NUM_OPTIONS.collect { |n| |
|---|
| 205 | if n == @num |
|---|
| 206 | "<option value=\"#{n}\" selected>#{n}件ずつ</option>" |
|---|
| 207 | else |
|---|
| 208 | "<option value=\"#{n}\">#{n}件ずつ</option>" |
|---|
| 209 | end |
|---|
| 210 | }.join("\n") |
|---|
| 211 | @sort_options = format_options(SORT_OPTIONS, @sort) |
|---|
| 212 | @order_options = format_options(ORDER_OPTIONS, @order) |
|---|
| 213 | @form_options = format_options(FORM_OPTIONS, @form) |
|---|
| 214 | end |
|---|
| 215 | |
|---|
| 216 | def _(str) |
|---|
| 217 | CGI::escapeHTML(str) |
|---|
| 218 | end |
|---|
| 219 | |
|---|
| 220 | def convert(str) |
|---|
| 221 | @conf.to_native(str) |
|---|
| 222 | end |
|---|
| 223 | end |
|---|
| 224 | end |
|---|
| 225 | |
|---|
| 226 | begin |
|---|
| 227 | @cgi = CGI::new |
|---|
| 228 | if ::TDiary::Config.instance_method(:initialize).arity > 0 |
|---|
| 229 | # for tDiary 2.1 or later |
|---|
| 230 | conf = ::TDiary::Config::new(@cgi) |
|---|
| 231 | else |
|---|
| 232 | # for tDiary 2.0 or earlier |
|---|
| 233 | conf = ::TDiary::Config::new |
|---|
| 234 | end |
|---|
| 235 | tdiary = TDiary::TDiaryEstraier::new( @cgi, 'estraier.rhtml', conf ) |
|---|
| 236 | |
|---|
| 237 | head = { |
|---|
| 238 | 'type' => 'text/html', |
|---|
| 239 | 'Vary' => 'User-Agent' |
|---|
| 240 | } |
|---|
| 241 | if @cgi.mobile_agent? then |
|---|
| 242 | body = conf.to_mobile( tdiary.eval_rhtml( 'i.' ) ) |
|---|
| 243 | head['charset'] = conf.mobile_encoding |
|---|
| 244 | head['Content-Length'] = body.size.to_s |
|---|
| 245 | else |
|---|
| 246 | if @cgi['type'] == 'rss' |
|---|
| 247 | head['type'] = "application/xml; charset=#{conf.encoding}" |
|---|
| 248 | body = tdiary.eval_rxml |
|---|
| 249 | else |
|---|
| 250 | body = tdiary.eval_rhtml |
|---|
| 251 | end |
|---|
| 252 | head['charset'] = conf.encoding |
|---|
| 253 | head['Content-Length'] = body.size.to_s |
|---|
| 254 | head['Pragma'] = 'no-cache' |
|---|
| 255 | head['Cache-Control'] = 'no-cache' |
|---|
| 256 | end |
|---|
| 257 | print @cgi.header( head ) |
|---|
| 258 | print body |
|---|
| 259 | rescue Exception |
|---|
| 260 | if @cgi then |
|---|
| 261 | print @cgi.header( 'type' => 'text/plain' ) |
|---|
| 262 | else |
|---|
| 263 | print "Content-Type: text/plain\n\n" |
|---|
| 264 | end |
|---|
| 265 | puts "#$! (#{$!.class})" |
|---|
| 266 | puts "" |
|---|
| 267 | puts $@.join( "\n" ) |
|---|
| 268 | end |
|---|