Weather_ver='$Id: weather.rb,v 1.19 2004-09-25 23:20:04+09 waka Exp waka $'.split(" ")[2] # http://www.double-red.net/ =begin nDiary filter 日記中に Tenki:郵便番号 (郵便番号は nnn-nnnn という形式) という文があると、 http://www.e-tenki.net/ にアクセスして日記をコンパイルした時点 http://weather.yahoo.co.jp/ にアクセスして日記をコンパイルした時点 (つまり ruby diary ndiaryconfdir/ndiary.conf した時点) の天気・降水量・気温・風向き・風力を表示します。 *仕様----------------------------------------------------------- ruby 1.8.x 以上推奨 ※ ruby 1.6.x で利用する際には ※ yaml.rb(http://yaml4r.sourceforge.net/)をインストールしてください。 http://prdownloads.sourceforge.net/yaml4r/syck-0.42.tar.gz?download が最新のようです(2004-01-27現在) *設定 -キャッシュディレクトリ設定(必須) ndiary.conf の LOG_DIRECTORY で指定したディレクトリに weather というディレクトリを作成する。 -プロキシ越え(必要に応じて) ndiary.conf に PROXY = 'proxy.hoge.com:8080' などと設定するとプロキシを越えます。たぶん。 -天気画像(任意) ndiary.conf に WEATHER_IMG_URL = '../img/weather' などと設定し、以下のような画像を上記のディレクトリ(web上から見えるとこ)におくと 晴れ: sunny.png 曇り: croudy.png 雨: rainy.png 雪: snow.png 晴れなどの文字のかわりに画像が表示されるようになります。 inlineimage フィルタを利用していれば利用します。 -日付ごえ(任意) ndiary.conf に WEATHER_ALLOW_SPAN = n と設定すると(nは数字)、コンパイルしている時点の日付と編集最中の日記の日付とが 1 日だけ違う場合、 日付が変更してから n 時間の間は天気を取得しにいく。 デフォルトは 0。 -最新天気のみ表示する(任意、デフォルトはコンパイルした時点で取得した天気の数だけ表示する) ndiary.conf に WEATHER_ONCE_DISP = true と設定する、もしくは日記内表記を Tenki:nnn-nnnntrue とする -表示項目のカスタマイズ WEATHER_TEMPLATE = true を設定し、 キャッシュディレクトリ(LOG_DIRECTORY/weather)に、 template というファイルを作成し以下を参考にテンプレートを作成してください。
<-w_天気画像>(<-w_降水量> mm) <-w_気温>℃ <-w_風> <-取得時間>
Sanjose 95111 #http://weather.yahoo.com/rss/ #http://weather.yahoo.com/forecast/USCA0987.html #http://xml.weather.yahoo.com/forecastrss?p=94115 =end class Weather begin require 'yaml' rescue LoadError raise NDiaryFatalError, "Can't load yaml. please install 'yaml' or use ruby 1.8.x(fortune.rb)" end attr_accessor :postal attr_accessor :cache_dir attr_accessor :date attr_accessor :proxy attr_accessor :allow_span def initialize(postal,cache_dir,date,proxy,allow_span) @postal=postal @cache_dir=cache_dir @date=date @proxy=proxy @allow_span = allow_span end def getFileStream(url, proxy) if /^http/ =~ url $stderr.puts "CHK; access; #{url}" require 'net/http' domain, port = "", "" if url =~ /\/\/(.+?)(?:\/|$)/ domain = $1.to_s end protocol = url.split(":").first + "://" path = url.gsub(Regexp.new(protocol + domain),"") if proxy proxy, port = proxy.split(':') port = port.to_i else proxy = port = nil end begin http = Net::HTTP::Proxy(proxy, port).new(domain, 80) if /1\.6/ =~ RUBY_VERSION file_info, = http.get2(path) else file_info = http.get(path) end if file_info.code == '302' path = file_info.header['location'].sub(Regexp.new(url), "") file_info = http.get(path) end return(file_info.response.body) rescue # return $! return nil end else open(url, "rb").read end end def getTime now = Time.now now_hour = now.strftime("%H\n").to_i get_time=nil if 0 <= now_hour and now_hour < 3 get_time = "00" elsif 3 <= now_hour and now_hour < 6 get_time = "03" elsif 6 <= now_hour and now_hour < 9 get_time = "06" elsif 9 <= now_hour and now_hour < 12 get_time = "09" elsif 12 <= now_hour and now_hour < 15 get_time = "12" elsif 15 <= now_hour and now_hour < 18 get_time = "15" elsif 18 <= now_hour and now_hour < 21 get_time = "18" elsif 21 <= now_hour and now_hour < 24 get_time = "21" end return get_time,now end def etenki get_time,now = getTime cachename = @date + "-" + get_time + "-" + @postal postal_cache = 'postal_url' old_cachename = @date + "-" + @postal if File::directory?(@cache_dir.to_s) cachefile = @cache_dir.to_s + File::Separator + cachename postal_cache = @cache_dir.to_s + File::Separator + 'postal_url' old_cachefile = @cache_dir.to_s + File::Separator + old_cachename else cachefile = cachename postal_cache = 'postal_url' end today_caches = Array.new Dir::entries(@cache_dir).each{|i| if /#{@date}-(\d\d-)?#{@postal}/ =~ i then today_caches << @cache_dir.to_s + File::Separator + i.to_s end } unless @postal.empty? then #if FileTest.exist?(cachefile) if (FileTest.exist?(cachefile) || FileTest.exist?(old_cachefile)) && today_caches.size == 1 begin cache = File.open(cachefile,mode="r") rescue cache = File.open(old_cachefile,mode="r") end #str = Marshal.load(cache) str = YAML::load(cache) cache.close return [str] else str=Array.new #今日の天気以外は調べられん #if Time.new.strftime("%Y%m%d") != @date then #コンパイルする日付と日記の日付とが 1 日違う場合、 #日付が変更して @allow_span の間は取得する my = @date.to_s.scan(/^\d\d\d\d/)[0] mm,md = @date.to_s.scan(/(\d\d)(\d\d)$/)[0] today = Time.local(my.to_i,mm.to_i,md.to_i) unless ((now - today) / 3600 - 24).to_i < @allow_span then if today_caches.size >= 1 then today_caches.each{|c| oldcache = File.open(c,mode="r") #s = Marshal.load(oldcache) s = YAML::load(oldcache) oldcache.close str << s } return str else # db search routine return false end end uri="http://www.e-tenki.net" unless FileTest.exist?(cachefile) then # 地域特定 url pinpoint_url='' if FileTest.exist?(postal_cache) then tmp = open(postal_cache, "r").read tmp.each{|line| if /^#{@postal} (.+)/ =~ line then pinpoint_url = $1.chomp break end } end p pinpoint_url if ! FileTest.exist?(postal_cache) || pinpoint_url.empty? then url=%Q!#{uri}/wr/ex/point/list/1,1548,,00.html?YubinNo3=#{@postal.split("-").first}&YubinNo4=#{@postal.split("-").last}&submit1=%8C%9F%8D%F5&Tiiki=&FMName=Yubin&vgn_form_encoding=SHIFT-JIS! gethtml=getFileStream(url,@proxy) if /ピンポイント予報 検索結果(1件〜1件).+?/mis =~ gethtml then pinpoint_url = uri + $1 end pcache = File.open(postal_cache,'a') pcache.puts "#{@postal} #{pinpoint_url}" pcache.close end tenki_result=getFileStream(pinpoint_url,@proxy) table='' if /.+?(.+?)<\/TABLE>\n/mis =~ tenki_result then table=$1 end pinpoint_region=nil if />([^>]+)のピンポイント天気/mis =~ tenki_result then pinpoint_region = $1 end table = table.gsub(/>\n<") row=false col=false val=Array.new vvv=Array.new table.each{|i| if //i =~ i then row=true end if /<\/tr>/i =~ i then row=false unless val.include?("−") vvv << val.dup.flatten end val.clear end if //i =~ i then col=true end if /<\/td>/i =~ i then col=false end if row then if col then unless i.scan(/>([^<]+)([^<]+)= 1 then today_caches.each{|c| oldcache = File.open(c,mode="r") #s = Marshal.load(oldcache) begin s = YAML::load(oldcache) oldcache.close str << s rescue puts oldcache puts $! end } return str else # db search routine return false end end uri="http://search.weather.yahoo.co.jp" unless FileTest.exist?(cachefile) then # 地域特定 url pinpoint_url='' if FileTest.exist?(postal_cache) then tmp = open(postal_cache, "r").read tmp.each{|line| if /^#{@postal} (.+)/ =~ line then pinpoint_url = $1.chomp break end } end p pinpoint_url if ! FileTest.exist?(postal_cache) || pinpoint_url.empty? then url=%Q!#{uri}/bin/search?pref=all&p=#{@postal}! gethtml=getFileStream(url,@proxy).tosjis if %r!!mis =~ gethtml then pinpoint_url = $1 end pcache = File.open(postal_cache,'a') pcache.puts "#{@postal} #{pinpoint_url}" pcache.close end pinpoint_region=nil if %r!\n\n!mis =~ gethtml then pinpoint_region = $1 + $2 end tenki_result = getFileStream(pinpoint_url,@proxy).tosjis table='' if %r|
.+?#{postal}(.+?)(.+?)
\n(.+?)|mis =~ tenki_result then table=$1 end table = table.gsub("\n","").gsub(%r!(
||)!,"").gsub(%r!()!,"\\1\n") row=false col=false val = Array.new vvv = Array.new value = "" index_time = 0 table.each{|i| if //i =~ i then row=true elsif /<\/tr>/i =~ i then row=false unless val.empty? then vvv << val.dup.flatten # ["hoge", "foo", ["bar"]] => ["hoge", "foo", "bar"] ii = 0 val.each{|z| if /(\d+)時/mis =~ z then if Regexp.new($1.to_s) =~ get_time then index_time = ii end end ii += 1 } end val.clear end if %r!(.+?)!i =~ i then col = true value = $1 if %r!風向!s =~ value then value = "風" elsif /img/i =~ value then value = value.scan(/alt="(.+?)"/i)[0].to_s else value = value.gsub(/[(].+?[)].*$/,"") end else col = false value = "" end if row && col then unless value.nil? val << value end end } str << Hash["地域",pinpoint_region] str << Hash["時刻","#{now.strftime("%H:%M:%S")}"] #disp_array=["天気","降水量","気温","風"] vvv.each{|i| str << Hash[i[0],i[index_time]] } cache = File.open(cachefile,mode="w") #Marshal.dump(str,cache) cache.write(str.to_yaml) cache.close else unless today_caches.empty? then today_caches.each{|c| oldcache = File.open(c,mode="r") #s = Marshal.load(oldcache) s = YAML::load(oldcache) oldcache.close str << s } end end return str end end end def yahooWeather_old get_time,now = getTime cachename = @date + "-" + get_time + "-" + @postal postal_cache = 'postal_url' old_cachename = @date + "-" + @postal if File::directory?(@cache_dir.to_s) cachefile = @cache_dir.to_s + File::Separator + cachename postal_cache = @cache_dir.to_s + File::Separator + 'postal_url' old_cachefile = @cache_dir.to_s + File::Separator + old_cachename else cachefile = cachename postal_cache = 'postal_url' end today_caches = Array.new Dir::entries(@cache_dir).each{|i| if /#{@date}-(\d\d-)?#{@postal}/ =~ i then today_caches << @cache_dir.to_s + File::Separator + i.to_s end } unless @postal.empty? then #if FileTest.exist?(cachefile) if (FileTest.exist?(cachefile) || FileTest.exist?(old_cachefile)) && today_caches.size == 1 begin cache = File.open(cachefile,mode="r") rescue cache = File.open(old_cachefile,mode="r") end #str = Marshal.load(cache) str = YAML::load(cache) cache.close return [str] else str=Array.new #今日の天気以外は調べられん #if Time.new.strftime("%Y%m%d") != @date then #コンパイルする日付と日記の日付とが 1 日違う場合、 #日付が変更して @allow_span の間は取得する my = @date.to_s.scan(/^\d\d\d\d/)[0] mm,md = @date.to_s.scan(/(\d\d)(\d\d)$/)[0] today = Time.local(my.to_i,mm.to_i,md.to_i) unless ((now - today) / 3600 - 24).to_i < @allow_span then if today_caches.size >= 1 then today_caches.each{|c| oldcache = File.open(c,mode="r") #s = Marshal.load(oldcache) s = YAML::load(oldcache) oldcache.close str << s } return str else # db search routine return false end end uri="http://search.weather.yahoo.co.jp" unless FileTest.exist?(cachefile) then # 地域特定 url pinpoint_url='' if FileTest.exist?(postal_cache) then tmp = open(postal_cache, "r").read tmp.each{|line| if /^#{@postal} (.+)/ =~ line then pinpoint_url = $1.chomp unless /yahoo/ =~ pinpoint_url then pinpoint_url = '' else break end end } end p pinpoint_url if ! FileTest.exist?(postal_cache) || pinpoint_url.empty? then url=%Q!#{uri}/bin/search?pref=all&p=#{@postal}! gethtml=getFileStream(url,@proxy).tosjis if %r!!mis =~ gethtml then pinpoint_url = $1 end pcache = File.open(postal_cache,'a') pcache.puts "#{@postal} #{pinpoint_url}" pcache.close end pinpoint_region=nil if %r!\n\n!mis =~ gethtml then pinpoint_region = $1 + $2 end tenki_result = getFileStream(pinpoint_url,@proxy).tosjis table='' if %r!\n(.+?)\n\nなんちゃら row=false col=false val = Array.new vvv = Array.new value = "" table.each{|i| if //i =~ i then row=true end if /<\/tr>/i =~ i then row=false unless val.empty? then vvv << val.dup.flatten # ["hoge", "foo", ["bar"]] => ["hoge", "foo", "bar"] end val.clear end if %r!(.+?)!i =~ i then col = true value = $1 if %r!風向!s =~ value then value = "風" elsif /img/i =~ value then value = value.scan(/alt="(.+?)"/i)[0].to_s else value = value.gsub(/[  ]/,"").gsub(/\(.+?\)/,"").to_s #空白と(.+?)をトリム end else col = false value = "" end if row then if col then unless value.nil? val << value end end end } str << Hash["地域",pinpoint_region] str << Hash["時刻","#{now.strftime("%H:%M:%S")}"] #disp_array=["天気","降水量","気温","風"] vvv.each{|i| str << Hash[i[0],i[1]] } cache = File.open(cachefile,mode="w") #Marshal.dump(str,cache) cache.write(str.to_yaml) cache.close else unless today_caches.empty? then today_caches.each{|c| oldcache = File.open(c,mode="r") #s = Marshal.load(oldcache) s = YAML::load(oldcache) oldcache.close str << s } end end return str end end end end class Filter def weather(str, type) case type when :P use_site = 'yahooWeather' #etenki or yahooWeather cache_dir = @diary.logDirectory + 'weather' proxy = @diary.config['PROXY'] img_dir = @diary.config['WEATHER_IMG_URL'] once_disp = @diary.config['WEATHER_ONCE_DISP'] # true/false unless @diary.config['WEATHER_ALLOW_SPAN'].to_s.empty? allow_span = @diary.config['WEATHER_ALLOW_SPAN'].to_i else allow_span = 0 end date = @diary.date if @diary.config['WEATHER_TEMPLATE'] then template = open(cache_dir + File::Separator + 'template', "r").read else template = "" end weather_img = Hash[\ "晴れ","sunny.png",\ "晴れ夜","sunny-night.png",\ "曇り","croudy.png",\ "雨","rainy.png",\ "弱雨","rainy_s.png",\ #"みぞれ・雪","snow.png",\ "雪","snow.png"\ ] str.gsub!(/Tenki:(\d{3}-\d{4})(true)?/i){ postal=$1 once_disp = $2 unless once_disp case use_site when /etenki/ tenki = Weather.new(postal,cache_dir,date,proxy,allow_span).etenki when /yahooWeather/ tenki = Weather.new(postal,cache_dir,date,proxy,allow_span).yahooWeather end if tenki then pinpoint_region,time,now_weather,precipitation,temp,wind,humidity = Array.new,Array.new,Array.new,Array.new,Array.new,Array.new,Array.new if once_disp then tenki = [tenki.last] end tenki.each{|i| i.each{|j| j.each{|key,val| o = "#{val}" pinpoint_region << o if key == "地域" time << o if key == "時刻" now_weather << o if key == "天気" precipitation << o if key == "降水量" temp << o if key == "気温" wind << o if key == "風" humidity << o if key == "湿度" } } } use_inlineimage = false @diary.filter.methods.each{|m| if /inlineimage.*/ =~ m then use_inlineimage = true end } s = "

" (0..time.size-1).each{|i| disp_w_img = "#{weather_img["晴れ"]}" case now_weather[i].to_s when /晴/ disp_w_img = "#{weather_img["晴れ"]}" when /雨/ disp_w_img = "#{weather_img["雨"]}" disp_w_img = "#{weather_img["弱雨"]}" if /弱/ =~ now_weather[i].to_s when /雪/ disp_w_img = "#{weather_img["雪"]}" else disp_w_img = "#{weather_img["#{now_weather[i]}"]}" end #s << now_weather[i].to_s night = false if /(?:(\d+)時)|(?:(\d\d):\d\d:\d\d)/ =~ time[i] hh = $1 [18,19,20,21,22,23,0,1,2,3,4,5].each{|t| if t == hh.to_i then night = true end } end if night and /晴/ =~ now_weather[i].to_s then disp_w_img = "#{weather_img["晴れ夜"]}" end w_image = "" if img_dir if use_inlineimage w_image = %Q!image(#{img_dir}/#{disp_w_img} #{now_weather[i]})! else w_image = %Q!#{now_weather[i]}' : '>') end else w_image = %Q!#{now_weather[i]}! end w_prec = precipitation[i].to_i w_temp = temp[i] w_wind = wind[i] w_time = time[i] w_humidity = humidity[i].gsub(/-+/,"") unless humidity[i].to_s.empty? unless %r!m/s! =~ w_wind then direction, strong = w_wind.scan(/([^\d]+)(\d)/).flatten w_wind = "#{direction}(#{strong} m/s)" end unless template.empty? then template.tosjis.each{|line| line.gsub!(/<-w_天気画像>/,w_image) line.gsub!(/<-w_降水量>/,w_prec.to_s) line.gsub!(/<-w_気温>/,w_temp) line.gsub!(/<-w_風>/,w_wind) line.gsub!(/<-w_取得時間>/,w_time) line.gsub!(/<-w_湿度>/,w_humidity.to_s) s << line } else s << w_image s << "(#{w_prec} mm)" s << " / " s << "#{w_temp}℃" s << " / " unless w_humidity.to_s.empty? then s << "#{w_humidity} %" s << " / " end s << "#{w_wind}" # s << " @ #{w_time[i].gsub(/^0時/,"24時")}" s << " @ #{w_time}" s << "#{@diary.tag_br}" unless i == time.size - 1 end } s << "" s << '

' s else "" end } when :AFTER_P str.gsub!(/\s*<\/p>/mi, '') end end end

.+?#{postal}(.+?)(.+?).+?