root/platform/tdiary/plugin/hb_footer/rss-recent.rb @ 3219

Revision 3219, 5.1 kB (checked in by hsbt, 5 years ago)

platform/tdiary/plugin/*: import from my repos.

Line 
1# rss-recent.rb: RSS recent plugin
2#
3# rss_recnet: show recnet list from RSS
4#   parameters (default):
5#      url: URL of RSS
6#      max: max of list itmes(5)
7#      cache_time: cache time(second) of RSS(60*60)
8#      template_head: rendering header part
9#      template_list: rendering RSS item part(with loop)
10#      template_foot: rendering footer part
11#
12# Copyright (c) 2003-2004 Kouhei Sutou <kou@cozmixng.org>
13# Distributed under the GPL
14#
15# Modified using template string and content:encoded
16# Version 0.0.5i2 by ishinao <ishinao@ishinao.net>
17#
18
19require "rss/rss"
20
21RSS_RECENT_FIELD_SEPARATOR = "\0"
22RSS_RECENT_ENTRY_SEPARATOR = "\1"
23RSS_RECENT_VERSION = "0.0.5i2"
24RSS_RECENT_HTTP_HEADER = {
25        "User-Agent" => "tDiary RSS recent plugin version #{RSS_RECENT_VERSION}. " <<
26        "Using RSS parser version is #{::RSS::VERSION}.",
27}
28
29def rss_recent(url, max = 5, cache_time = 3600, \
30        template_head = "<ul>\n", \
31        template_list = '<li><span class="#{rss_recent_modified_class(time)}"><a href="#{CGI.escapeHTML(url)}" title="#{CGI.escapeHTML(title)}">#{CGI::escapeHTML(title)}</a></span></li>\n', \
32        template_foot = "</ul>\n")
33        url.untaint
34
35        cache_file = "#{@cache_path}/rss-recent.#{CGI.escape(url)}"
36
37        rss_recent_cache_rss(url, cache_file, cache_time.to_i)
38       
39        return '' unless test(?r, cache_file)
40
41        rv = template_head
42       
43        i = 0
44        rss_recent_read_from_cache(cache_file).each do |title, url, time, content, description|
45                break if i >= max
46                next if (url.nil? or title.nil?)
47                rv << eval('%Q[' + template_list + ']')
48                i += 1
49        end
50
51        rv << template_foot
52
53        if i > 0
54                rv
55        else
56                ''
57        end
58end
59
60class InvalidResourceError < StandardError; end
61
62def rss_recent_cache_rss(url, cache_file, cache_time)
63
64        cached_time = nil
65        cached_time = File.mtime(cache_file) if File.exist?(cache_file)
66
67        if cached_time.nil? or Time.now > cached_time + cache_time
68                require 'time'
69                require 'open-uri'
70                require 'net/http'
71                require 'uri/generic'
72                require 'rss/parser'
73                require 'rss/1.0'
74                require 'rss/2.0'
75                require 'rss/dublincore'
76                require 'rss/content'
77               
78                begin
79                        uri = URI.parse(url)
80
81                        raise URI::InvalidURIError if uri.scheme != "http"
82
83                        rss_source = rss_recent_fetch_rss(uri, cached_time)
84                       
85                        raise InvalidResourceError if rss_source.nil?
86
87                        # parse RSS
88                        rss = ::RSS::Parser.parse(rss_source, false)
89                        raise ::RSS::Error if rss.nil?
90
91                        # pre processing
92                        begin
93                                rss.output_encoding = @conf.charset || charset
94                        rescue ::RSS::UnknownConversionMethodError
95                        end
96
97                        rss_infos = rss.items.collect do |item|
98                                rss_recent_pubDate_to_dc_date(item)
99                                [item.title, item.link, item.dc_date, item.content_encoded, item.description]
100                        end
101                        rss_recent_write_to_cache(cache_file, rss_infos)
102
103                rescue URI::InvalidURIError
104                        rss_recent_write_to_cache(cache_file, [['Invalid URI', url]])
105                rescue InvalidResourceError, ::RSS::Error
106#                       rss_recent_write_to_cache(cache_file, [['Invalid Resource', url]])
107# when cannot get valid RSS, use old cache
108                end
109        end
110
111end
112
113def rss_recent_fetch_rss(uri, cache_time)
114        rss = nil
115        begin
116                uri.open(rss_recent_http_header(cache_time)) do |f|
117                        case f.status.first
118                        when "200"
119                                rss = f.read
120                                # STDERR.puts "Got RSS of #{uri}"
121                        when "304"
122                                # not modified
123                                # STDERR.puts "#{uri} does not modified"
124                        else
125                                raise InvalidResourceError
126                        end
127                end
128        rescue TimeoutError, SocketError, StandardError,
129                        SecurityError # occured in redirect
130                raise InvalidResourceError
131        end
132        rss
133end
134
135def rss_recent_http_header(cache_time)
136        header = RSS_RECENT_HTTP_HEADER.dup
137        if cache_time.respond_to?(:rfc2822)
138                header["If-Modified-Since"] = cache_time.rfc2822
139        end
140        header
141end
142
143def rss_recent_write_to_cache(cache_file, rss_infos)
144        File.open(cache_file, 'w') do |f|
145                f.flock(File::LOCK_EX)
146                rss_infos.each do |info|
147                        f << info.join(RSS_RECENT_FIELD_SEPARATOR)
148                        f << RSS_RECENT_ENTRY_SEPARATOR
149                end
150                f.flock(File::LOCK_UN)
151        end
152end
153
154def rss_recent_read_from_cache(cache_file)
155        require 'time'
156        infos = []
157        File.open(cache_file) do |f|
158                while info = f.gets(RSS_RECENT_ENTRY_SEPARATOR)
159                        info = info.chomp(RSS_RECENT_ENTRY_SEPARATOR)
160                        infos << info.split(RSS_RECENT_FIELD_SEPARATOR)
161                end
162        end
163        infos.collect do |title, url, time, content, description|
164                [
165                        rss_recent_convert(title),
166                        rss_recent_convert(url),
167                        rss_recent_convert(time) {|time| Time.parse(time)},
168                        rss_recent_convert(content),
169            rss_recent_convert(description),
170                ]
171        end
172end
173
174def rss_recent_convert(str)
175        if str.nil? or str.empty?
176                nil
177        else
178                if block_given?
179                        yield str
180                else
181                        str
182                end
183        end
184end
185
186# from RWiki
187def rss_recent_modified(t)
188        return '-' unless t
189        dif = (Time.now - t).to_i
190        dif = dif / 60
191        return "#{dif}m" if dif <= 60
192        dif = dif / 60
193        return "#{dif}h" if dif <= 24
194        dif = dif / 24
195        return "#{dif}d"
196end
197
198# from RWiki
199def rss_recent_modified_class(t)
200        return 'dangling' unless t
201        dif = (Time.now - t).to_i
202        dif = dif / 60
203        return "modified-hour" if dif <= 60
204        dif = dif / 60
205        return "modified-today" if dif <= 24
206        dif = dif / 24
207        return "modified-month" if dif <= 30
208        return "modified-year" if dif <= 365
209        return "modified-old"
210end
211
212def rss_recent_pubDate_to_dc_date(target)
213        if target.respond_to?(:pubDate)
214                class << target
215                        alias_method(:dc_date, :pubDate)
216                end
217        end
218end
Note: See TracBrowser for help on using the browser.