td2planet 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/ChangeLog ADDED
@@ -0,0 +1,3 @@
1
+ 2007-02-22 Kazuhiro NISHIYAMA <zn@mbf.nifty.com>
2
+
3
+ * Initial public release.
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2006 Kazuhiro NISHIYAMA
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README ADDED
@@ -0,0 +1,63 @@
1
+ = TD2Planet
2
+ This is a planet implementation of ruby, mainly for tdiary.
3
+
4
+ See http://www.planetplanet.org about planet.
5
+
6
+ == Install
7
+ === Install using setup.rb
8
+ 1. ruby setup.rb
9
+
10
+ === Install using rubygems
11
+ 1. gem build *.gemspec
12
+ 2. gem install *.gem
13
+
14
+ == Usage
15
+ 1. copy and edit config.yaml
16
+ 2. run "td2planet.rb config.yaml"
17
+ 3. copy output files to public directory if need be
18
+ 4. set cron and so on if need be
19
+
20
+ === Usage without install
21
+ 1. copy and edit config.yaml
22
+ 2. run "ruby -I lib bin/td2planet.rb config.yaml"
23
+ 3. same as above
24
+
25
+ == SECURITY NOTICE
26
+ Do not add untrusted feeds.
27
+ All content:encoded in feeds output to the file of output_html as is,
28
+ even if content:encoded includes scripts and so on.
29
+
30
+ To avoid security problem, I recommend to divide the domain of
31
+ this planet from the domains of other contents.
32
+ (e.g. planet.example.jp)
33
+
34
+ == Customize Output
35
+ After customize, run "td2planet.rb -n config.yaml" to update output files.
36
+
37
+ === Customize Template
38
+ 1. make override templates directory
39
+ 2. copy the file under templates to the override templates directory
40
+ 3. edit the file
41
+ 4. add the override templates directory to templates_path in config.yaml
42
+
43
+ === Customize Formatter
44
+ 1. copy default_formatter.rb or sample_formatter.rb to ./your_formatter.rb
45
+ 2. edit the file (you must change class name from DefaultFormatter or SampleFormatter to YourFormatter if the filename is your_formatter.rb)
46
+
47
+ == Q&A
48
+ [Q. Why do this planet outputs content:encoded as is?]
49
+ A. I can not keep safe white lists and/or black lists.
50
+ (see one of white lists: http://d.hatena.ne.jp/keyword/%A4%CF%A4%C6%A4%CA%A5%C0%A5%A4%A5%A2%A5%EA%A1%BCXSS%C2%D0%BA%F6 (Japanese))
51
+ [Q. Why do not output feeds include contents?]
52
+ A. If you use other feed reader, you can import original feeds
53
+ from opml to the feed reader.
54
+
55
+ == License
56
+ setup.rb:: GNU LGPL
57
+ other files:: MIT-LICENSE
58
+
59
+ Copyright (c) 2006, 2007 Kazuhiro NISHIYAMA
60
+
61
+ --
62
+ # -*- coding: utf-8 -*-
63
+ # vim: ts=2 sw=2 sts=2 fenc=utf-8:
data/README.ja ADDED
@@ -0,0 +1,66 @@
1
+ = TD2Planet
2
+ これはrubyによるplanet実装です。
3
+ 主にtDiaryのmakerss.rbプラグインの出力を扱う用に調整してあります。
4
+
5
+ planetとは何かについては http://www.planetplanet.org などを
6
+ 参照してください。
7
+
8
+ == インストール
9
+ === setup.rbを使ったインストール
10
+ 1. ruby setup.rb
11
+
12
+ === rubygemsを使ったインストール
13
+ 1. gem build *.gemspec
14
+ 2. gem install *.gem
15
+
16
+ == 使い方
17
+ 1. config.yamlを適当なところにコピーして編集
18
+ 2. td2planet.rb config.yaml
19
+ 3. 必要なら出力されたファイルを公開ディレクトリにコピー
20
+ 4. 必要ならcronなどで定期的に実行
21
+
22
+ === インストールせずに使う方法
23
+ 1. config.yamlを編集
24
+ 2. ruby -I lib bin/td2planet.rb config.yaml
25
+ 3. 以降は上と同じ
26
+
27
+ == セキュリティ上の注意
28
+ 信頼できないRSSは設定しないでください。
29
+ output_htmlで指定したファイルには元のRSSのcontent:encodedの内容が、
30
+ スクリプトなどを含んでいたとしても、そのまま出力されます。
31
+
32
+ セキュリティ上の問題を避けるため、このplanetのドメインを他の
33
+ コンテンツのドメインとわけることをお薦めします。
34
+ (例えば planet.example.jp)
35
+
36
+
37
+ == 出力のカスタマイズ
38
+ カスタマイズ後、"td2planet.rb -n config.yaml"で出力を更新できます。
39
+
40
+ === テンプレートのカスタマイズ
41
+ 1. カスタマイズするテンプレート用のディレクトリを作成
42
+ 2. カスタマイズしたいテンプレートファイルをtemplates以下からコピー
43
+ 3. コピーしたテンプレートファイルを編集
44
+ 4. カスタマイズしたテンプレート用のディレクトリをconfig.yamlのtemplates_pathに追加
45
+
46
+ === Formatterのカスタマイズ
47
+ 1. default_formatter.rbかsample_formatter.rbを./your_formatter.rbなどにコピー
48
+ 2. ファイルを編集(DefaultFormatterかSampleFormatterをファイル名がyour_formatter.rbならYourFormatterに変更する必要あり)
49
+
50
+ == Q&A
51
+ [Q. なぜcontent:encodedをそのまま出力?]
52
+ A. 安全なホワイトリストやブラックリストを保守できないため。
53
+ (ホワイトリストの例: http://d.hatena.ne.jp/keyword/%A4%CF%A4%C6%A4%CA%A5%C0%A5%A4%A5%A2%A5%EA%A1%BCXSS%C2%D0%BA%F6 )
54
+ [Q. RSSに内容をいれていないのはなぜ?]
55
+ A. 他のフィードリーダーを使っているのなら、opmlを使って
56
+ 元のフィードをインポートして購読できるから。
57
+
58
+ == License
59
+ setup.rb:: GNU LGPL
60
+ other files:: MIT-LICENSE
61
+
62
+ Copyright (c) 2006, 2007 Kazuhiro NISHIYAMA
63
+
64
+ --
65
+ # -*- coding: utf-8 -*-
66
+ # vim: ts=2 sw=2 sts=2 fenc=utf-8:
data/bin/td2planet.rb ADDED
@@ -0,0 +1,10 @@
1
+ #! /usr/bin/ruby1.8 -Ku
2
+ # -*- mode: ruby; coding: utf-8 -*-
3
+ # vim: set filetype=ruby ts=2 sw=2 sts=2 fenc=utf-8:
4
+ #
5
+ # copyright (c) 2006, 2007 Kazuhiro NISHIYAMA
6
+
7
+ require 'td2planet/runner'
8
+ require 'td2planet/version'
9
+
10
+ TD2Planet.main
data/config.yaml ADDED
@@ -0,0 +1,57 @@
1
+ ## general config
2
+ title: TD2Planet Sample
3
+ base_uri: http://planet.example.jp/
4
+
5
+ ## feed URIs
6
+ uri:
7
+ - http://kazuhiko.tdiary.net/index.rdf
8
+ - http://sho.tdiary.net/index.rdf
9
+ - http://www.tdiary.net/index.rdf
10
+ - http://www.tdiary.org/index.rdf
11
+
12
+ ## feeds cache into cache_dir
13
+ cache_dir: cache
14
+
15
+ ## generated files into output_dir
16
+ output_dir: output
17
+ output_html: planet.html
18
+
19
+ ## themes
20
+ #tdiary_theme_path: http://localhost/tdiary/theme
21
+ tdiary_theme_path: /var/www/tdiary/theme
22
+ tdiary_theme: light-blue
23
+
24
+ ## parts of templates
25
+ #author: Your name
26
+ #made: mailto:webmaster@example.jp
27
+ #favicon: /favicon.ico
28
+ #logo_html: <img src="http://planet.example.jp/images/logo.png" width="168" height="150" alt="">
29
+ date_strftime_format: '%Y-%m-%d'
30
+ sanchor_strftime_format: '%H:%M:%S'
31
+
32
+ ## templates search path
33
+ #templates_path:
34
+ # - /path/to/override/templates
35
+ # - /path/to/other/override/templates
36
+
37
+ ## formatter
38
+ formatter: default_formatter
39
+ #formatter: sample_formatter
40
+ #formatter: your_formatter
41
+
42
+ ## spam filter (default_formatter feature)
43
+ ## (filtered if last value is true, output if false)
44
+ filter: |
45
+ if (/ツッコミ/ =~ k(item.title) &&
46
+ (
47
+ (k(item.content_encoded).scan(/http:/).size >= 5) ||
48
+ (k(item.description).scan(/http:/).size >= 5) ||
49
+ (/\[\/url\]/ =~ k(item.content_encoded)) ||
50
+ (/\[\/url\]/ =~ k(item.description)) ||
51
+ (/★/ =~ k(item.dc_creator)) ||
52
+ /@google\.com/ =~ k(item.dc_creator)
53
+ ))
54
+ true
55
+ else
56
+ false
57
+ end
@@ -0,0 +1,30 @@
1
+ <hr class="sep">
2
+ <div class="day">
3
+ <h2>
4
+ <span class="date"><%=h date_format(items[0]) %></span>
5
+ <span class="title">
6
+ <% if rss.channel.link -%>
7
+ <a href="<%=hk rss.channel.link %>"><%=hk rss.channel.title %></a>
8
+ <% else -%>
9
+ <%=hk rss.channel.title %>
10
+ <% end -%>
11
+ <% if rss.channel.dc_creator -%>
12
+ (<%=hk rss.channel.dc_creator %>)
13
+ <% end -%>
14
+ </span>
15
+ </h2>
16
+ <div class="body">
17
+ <% items.each do |item| -%>
18
+ <%= section(item, rss) -%>
19
+ <% end -%>
20
+ </div>
21
+ <% if /./ =~ rss.channel.dc_rights.to_s -%>
22
+ <div class="comment">
23
+ <!--<div class="caption"></div>-->
24
+ <div class="commentshort">
25
+ <!--<p><span class="canchor"></span><span class="commentator"></span>&nbsp;[...]</p>-->
26
+ <p><%=hk rss.channel.dc_rights %></p>
27
+ </div>
28
+ </div>
29
+ <% end -%>
30
+ </div>
@@ -0,0 +1,30 @@
1
+ </div>
2
+ <div class="sidebar">
3
+ <% if @config['logo_html'] -%>
4
+ <%= @config['logo_html'] %>
5
+ <% end -%>
6
+ <div class="block">
7
+ <h3>Subscriptions</h3>
8
+ <ul>
9
+ <% @rss_list.sort_by{|rss| -rss.item.date.to_i }.each do |rss| -%>
10
+ <li>
11
+ <a href="<%=hk rss.channel.link %>" title="<%=hk rss.channel.description %>"><%=hk rss.channel.title %></a>
12
+ <a href="<%=hk rss.channel.about %>">(feed)</a>
13
+ </li>
14
+ <% end -%>
15
+ </ul>
16
+ </div>
17
+
18
+ <div class="block">
19
+ <h3>Other formats</h3>
20
+ <ul>
21
+ <li><a href="rss10.xml">RSS 1.0</a></li>
22
+ <li><a href="rss20.xml">RSS 2.0</a></li>
23
+ <li><a href="opml.xml">opml</a></li>
24
+ </ul>
25
+ </div>
26
+
27
+ <div class="block">
28
+ <p>Last updated: <%= Time.now.localtime.strftime('%Y-%m-%d %H:%M:%S') %></p>
29
+ </div>
30
+ </div>
@@ -0,0 +1 @@
1
+ <div class="main">
@@ -0,0 +1,33 @@
1
+ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
2
+ <html>
3
+ <meta http-equiv="content-type" content="text/html; charset=utf-8">
4
+ <meta name="generator" content="<%=h TD2Planet.generator %>">
5
+ <meta http-equiv="content-script-type" content="text/plain"><!-- wish to disable scripts -->
6
+ <% if @config['author'] -%>
7
+ <meta name="author" content="<%=h @config['author'] %>">
8
+ <% end -%>
9
+ <% if @config['made'] -%>
10
+ <link rev="made" href="<%=h @config['made'] %>">
11
+ <% end -%>
12
+ <% if @config['favicon'] -%>
13
+ <link rel="shortcut icon" href="<%=h @config['favicon'] %>" type="image/x-icon">
14
+ <% end -%>
15
+ <meta http-equiv="content-style-type" content="text/css">
16
+ <link rel="stylesheet" href="<%=h @config['tdiary_theme_path'] %>/base.css" type="text/css" media="all">
17
+ <link rel="stylesheet" href="<%=h @config['tdiary_theme_path'] %>/<%=h @config['tdiary_theme'] %>/<%=h @config['tdiary_theme'] %>.css" title="<%=h @config['tdiary_theme'] %>" type="text/css" media="all">
18
+ <title><%=h @config['title'] %></title>
19
+ </head>
20
+ <body>
21
+ <h1><%=h @config['title'] %></h1>
22
+ <%= header %>
23
+ <% days.each do |day| -%>
24
+ <%= move_tukkomi_link(day(day[:items], day[:rss])) %>
25
+ <% end -%>
26
+ <hr class="sep">
27
+ <%= footer %>
28
+ <div class="footer">
29
+ Generated by <%=h TD2Planet.td2planet_version %><br>
30
+ Powered by <%=h TD2Planet.ruby_version %>
31
+ </div>
32
+ </body>
33
+ </html>
@@ -0,0 +1,19 @@
1
+ <?xml version="1.0"?>
2
+ <opml version="1.0">
3
+ <head>
4
+ <title><%=h @config['title'] %></title>
5
+ <dateCreated><%=h Time.now %></dateCreated>
6
+ <dateModified><%=h Time.now %></dateModified>
7
+ <% if @config.key?('author') -%>
8
+ <ownerName><%=h @config['author'] %></ownerName>
9
+ <% end -%>
10
+ <% if @config.key?('made') -%>
11
+ <ownerEmail><%=h @config['made'].sub(/^mailto:/, '') %></ownerEmail>
12
+ <% end -%>
13
+ </head>
14
+ <body>
15
+ <% rss_list.sort_by{|rss| -rss.item.date.to_i }.each do |rss| -%>
16
+ <outline text="<%=hk rss.channel.title %>" type="link" xmlUrl="<%=hk rss.channel.link %>"/>
17
+ <% end -%>
18
+ </body>
19
+ </opml>
@@ -0,0 +1,23 @@
1
+ <div class="section">
2
+ <%
3
+ section_body = to_section_body(item)
4
+ # tdiary makerss.rb plugin
5
+ if /<h3/ =~ section_body
6
+ -%>
7
+ <%=
8
+ section_body.sub(/<h3.*?>/) do
9
+ $& + to_sanchor(item) # + to_categories(item) # categories in original h3
10
+ end.sub(/<\/h3>/) do
11
+ to_author(item) + $&
12
+ end
13
+ %>
14
+ <% else -%>
15
+ <h3>
16
+ <%= to_sanchor(item) %>
17
+ <%= to_categories(item) %>
18
+ <%=hk item.title %>
19
+ <%= to_author(item) %>
20
+ </h3>
21
+ <%= to_section_body(item) %>
22
+ <% end -%>
23
+ </div>
@@ -0,0 +1,23 @@
1
+ #--
2
+ # -*- mode: ruby; coding: utf-8 -*-
3
+ # vim: set filetype=ruby ts=2 sw=2 sts=2 fenc=utf-8:
4
+ #
5
+ # copyright (c) 2006, 2007 Kazuhiro NISHIYAMA
6
+ #++
7
+
8
+ require 'td2planet/formatter'
9
+
10
+ module TD2Planet
11
+ class DefaultFormatter < Formatter
12
+ def initialize(config)
13
+ super
14
+ unless @config.key?('filter')
15
+ @config['filter'] = 'true'
16
+ end
17
+ end
18
+
19
+ def skip?(item)
20
+ eval(@config['filter']) or too_old?(item)
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,63 @@
1
+ #--
2
+ # -*- mode: ruby; coding: utf-8 -*-
3
+ # vim: set filetype=ruby ts=2 sw=2 sts=2 fenc=utf-8:
4
+ #
5
+ # copyright (c) 2006, 2007 Kazuhiro NISHIYAMA
6
+ #++
7
+
8
+ require 'erb'
9
+ require 'pathname'
10
+ require 'rss'
11
+ require 'uri'
12
+
13
+ module TD2Planet
14
+ class Fetcher
15
+ def initialize(cache_dir, dry_run=false)
16
+ @cache_dir = Pathname.new(cache_dir)
17
+ unless @cache_dir.exist?
18
+ @cache_dir.mkdir
19
+ end
20
+ @dry_run = dry_run
21
+ end
22
+
23
+ def fetch_all_rss(uris)
24
+ rss_list = []
25
+ uris.each do |uri|
26
+ cache_file = @cache_dir + ERB::Util.u(uri)
27
+ if @dry_run
28
+ puts "use cache: #{cache_file}"
29
+ text = cache_file.read
30
+ else
31
+ text = nil
32
+ begin
33
+ puts "fetch: #{uri}"
34
+ text = URI.parse(uri).read
35
+ rescue Timeout::Error
36
+ # fallback
37
+ puts "ERROR: timeout #{uri}"
38
+ text = cache_file.read
39
+ rescue Exception
40
+ puts "ERROR: #{$!} (#{$!.class}) on #{uri}"
41
+ raise
42
+ else
43
+ if text.status[0] == '200' && /rss/ =~ text
44
+ cache_file.open('wb'){|f| f.write(text) }
45
+ else
46
+ # fallback
47
+ puts "ERROR: fetch failed #{uri} #{text.status}"
48
+ text = cache_file.read
49
+ end
50
+ end
51
+ end
52
+ text = fixup_rss(text)
53
+ rss_list << RSS::Parser.parse(text, false)
54
+ end
55
+ rss_list
56
+ end
57
+
58
+ # euc-jp may fail to parse
59
+ def fixup_rss(text)
60
+ text.sub(/\bencoding="euc-jp"/ni, 'encoding="euc-jp-ms"')
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,224 @@
1
+ #--
2
+ # -*- mode: ruby; coding: utf-8 -*-
3
+ # vim: set filetype=ruby ts=2 sw=2 sts=2 fenc=utf-8:
4
+ #
5
+ # copyright (c) 2006, 2007 Kazuhiro NISHIYAMA
6
+ #++
7
+
8
+ require 'erb'
9
+ require 'nkf'
10
+ require 'uri'
11
+ require 'rss/maker'
12
+
13
+ module TD2Planet
14
+ class Formatter
15
+ include ERB::Util
16
+
17
+ ERB_METHODS = []
18
+ def self.def_erb_method(method_name, fname=nil)
19
+ if /\A\w+/ =~ method_name
20
+ fname ||= "#{$&}.rhtml"
21
+ end
22
+ ERB_METHODS << [method_name, fname]
23
+ end
24
+ def_erb_method('layout(days)')
25
+ def_erb_method('day(items, rss)')
26
+ def_erb_method('section(item, rss)')
27
+ def_erb_method('header()')
28
+ def_erb_method('footer()')
29
+
30
+ def k(s)
31
+ NKF.nkf('-wm0', s)
32
+ end
33
+ def hk(s)
34
+ h(k(s))
35
+ end
36
+
37
+ def default_templates_dir
38
+ basename = 'layout.rhtml'
39
+ dir = File.expand_path('../../data/td2planet/templates', File.dirname(__FILE__))
40
+ if File.exist?(File.join(dir, basename))
41
+ return dir
42
+ end
43
+
44
+ require 'rbconfig'
45
+ dir = File.expand_path('td2planet/templates', Config::CONFIG['datadir'])
46
+ if File.exist?(File.join(dir, basename))
47
+ return dir
48
+ end
49
+ raise "not found templates"
50
+ end
51
+
52
+ def initialize(config)
53
+ @config = config
54
+ @config['title'] ||= '(no title Planet)'
55
+ @config['tdiary_theme_path'] ||= '/tdiary/theme'
56
+ @config['tdiary_theme'] ||= 'default'
57
+ @config['date_strftime_format'] ||= '%Y-%m-%d'
58
+ @config['sanchor_strftime_format'] ||= '%H:%M:%S'
59
+ @base_uri = URI.parse(@config['base_uri'])
60
+ @config['templates_path'] ||= []
61
+ @config['templates_path'].push(default_templates_dir)
62
+ ERB_METHODS.each do |method_name, basename|
63
+ @config['templates_path'].find do |dir|
64
+ fname = File.expand_path(basename, dir)
65
+ if File.exist?(fname)
66
+ puts "use template #{basename}: #{fname}"
67
+ erb = ERB.new(File.read(fname), nil, '-')
68
+ eval("def self.#{method_name}\n#{erb.src}\nend\n", binding, fname, 0)
69
+ true
70
+ else
71
+ false
72
+ end
73
+ end
74
+ end
75
+ end
76
+
77
+ def date_format(item)
78
+ item.date.localtime.strftime(@config['date_strftime_format'])
79
+ end
80
+ def sanchor_format(item)
81
+ item.date.localtime.strftime(@config['sanchor_strftime_format'])
82
+ end
83
+
84
+ def too_old?(item, sec=7*24*60*60)
85
+ item.date < Time.now - sec
86
+ end
87
+
88
+ # override
89
+ def skip?(item)
90
+ false
91
+ end
92
+
93
+ def to_html(rss_list)
94
+ @rss_list = rss_list
95
+ day_rss = {}
96
+ rss_list.each do |rss|
97
+ next unless rss.items
98
+ rss.items.each do |item|
99
+ next if skip?(item)
100
+ day = (day_rss[[date_format(item), rss]] ||= Array.new)
101
+ day.push(item)
102
+ end
103
+ end
104
+ days = []
105
+ day_rss.keys.sort_by do |date, rss|
106
+ date
107
+ end.reverse_each do |key|
108
+ date, rss = key
109
+ items = day_rss[key]
110
+ items = items.sort_by do |item|
111
+ # tdiary makerss plugin generates same time entries
112
+ item.date.to_s + item.link
113
+ end
114
+ days << {:items => items, :rss => rss}
115
+ end
116
+ days = days.sort_by do |day|
117
+ -day[:items].collect{|item| item.date.to_i}.max
118
+ end
119
+ layout(days)
120
+ end
121
+
122
+ def relative_path_to_absolute_uri(attr_value, base_uri)
123
+ uri = URI.parse(attr_value)
124
+ if uri.scheme.nil?
125
+ URI.parse(base_uri) + uri
126
+ else
127
+ uri
128
+ end
129
+ end
130
+
131
+ def tag_attr_relative_path_to_absolute_uri(tag, attr_name, base_uri)
132
+ tag.gsub!(/#{attr_name}=([\"\'])([^\"\']+)\1/i) do
133
+ %Q!#{attr_name}=#{$1}#{relative_path_to_absolute_uri($2, base_uri)}#{$1}!
134
+ end or tag.gsub!(/#{attr_name}=(\S+)/) do
135
+ %Q!#{attr_name}=#{relative_path_to_absolute_uri($1, base_uri)}!
136
+ end
137
+ tag
138
+ end
139
+
140
+ def to_section_body(item)
141
+ if item.content_encoded
142
+ k(item.content_encoded).gsub(/<([aA]\b[\s\S]+?)>/) do
143
+ a = tag_attr_relative_path_to_absolute_uri($1, "href", item.link)
144
+ %Q!<#{a} rel="nofollow">!
145
+ #end.gsub(/<img\b[\s\S]+?>/i) do
146
+ # tag_attr_relative_path_to_absolute_uri($&, "src", item.link)
147
+ end.gsub(/<img\b[\s\S]+?>/i) do
148
+ img = $&
149
+ case img
150
+ when /alt=([\"\'])(.+?)\1/
151
+ $2
152
+ when /alt=(\S+?)/
153
+ $1
154
+ else
155
+ "[img]"
156
+ end
157
+ end
158
+ else
159
+ '<p>' + h(k(item.description)).gsub(/\r?\n/, '<br>') + '</p>'
160
+ end
161
+ end
162
+
163
+ def to_sanchor(item)
164
+ %Q!<a href="#{hk item.link}"><span class="sanchor">#{h sanchor_format(item)}</span></a> !
165
+ end
166
+
167
+ def to_categories(item)
168
+ h(item.dc_subjects.collect{|s|"[#{k(s.content)}]" if /./ =~ s.content})
169
+ end
170
+
171
+ def to_author(item)
172
+ if item.dc_creator
173
+ " (#{hk(item.dc_creator)})"
174
+ else
175
+ ""
176
+ end
177
+ end
178
+
179
+ TukkomiLinkRe = /^<p><a href="(.+)">ツッコミを入れる<\/a><\/p>$/
180
+ def move_tukkomi_link(html)
181
+ if TukkomiLinkRe =~ html
182
+ tukkomi_link = $&
183
+ tukkomi_uri = $1
184
+ re = Regexp.new(Regexp.quote(tukkomi_link))
185
+ tukkomi_moved_html = html.gsub(re, '')
186
+ re = Regexp.new(Regexp.quote('<!--<div class="caption"></div>-->'))
187
+ tukkomi_moved_html.sub!(re) { %Q|<div class="caption">[<a href="#{tukkomi_uri}">ツッコミを入れる</a>]</div>| }
188
+ # other day tukkomi_link found
189
+ if TukkomiLinkRe =~ tukkomi_moved_html
190
+ html.gsub!(TukkomiLinkRe) { %Q|<div class="caption">[<a href="#{$1}">ツッコミを入れる</a>]</div>| }
191
+ else
192
+ html = tukkomi_moved_html
193
+ end
194
+ end
195
+ html
196
+ end
197
+
198
+
199
+ def_erb_method('to_opml(rss_list)', 'opml.rxml')
200
+
201
+ def to_rss(rss_list, version='1.0', basename='rss.xml')
202
+ RSS::Maker.make(version) do |maker|
203
+ maker.channel.about = @base_uri + basename
204
+ maker.channel.title = @config['title']
205
+ maker.channel.link = @base_uri
206
+ maker.channel.description = "#{@base_uri} - #{@config['title']}"
207
+
208
+ maker.items.do_sort = true
209
+
210
+ rss_list.each do |rss|
211
+ rss.items.each do |item|
212
+ next if skip?(item)
213
+ new_item = maker.items.new_item
214
+ %w"link title date".each do |attr|
215
+ value = item.__send__(attr)
216
+ value = k(value) if value.is_a?(String)
217
+ new_item.__send__("#{attr}=", value)
218
+ end
219
+ end
220
+ end
221
+ end
222
+ end
223
+ end
224
+ end
@@ -0,0 +1,60 @@
1
+ #--
2
+ # -*- mode: ruby; coding: utf-8 -*-
3
+ # vim: set filetype=ruby ts=2 sw=2 sts=2 fenc=utf-8:
4
+ #
5
+ # copyright (c) 2006, 2007 Kazuhiro NISHIYAMA
6
+ #++
7
+
8
+ require 'optparse'
9
+ require 'td2planet/fetcher'
10
+ require 'td2planet/formatter'
11
+ require 'td2planet/writer'
12
+ require 'yaml'
13
+
14
+ module TD2Planet
15
+ module_function
16
+
17
+ def main(argv=ARGV)
18
+ opts = OptionParser.new
19
+ usage = proc { puts opts; exit(1) }
20
+ opts.banner << " config.yaml"
21
+ @dry_run = false
22
+ opts.on('-n', '--dry-run', 'do not fetch, generate files only') { @dry_run = true }
23
+ opts.on('-h', '--help', 'show this message') { usage.call }
24
+ opts.parse!(argv)
25
+ if argv.empty?
26
+ usage.call
27
+ end
28
+ argv.each do |filename|
29
+ config = YAML.load(File.read(filename))
30
+ run(config)
31
+ end
32
+ end
33
+
34
+ def get_formatter_class(formatter_name)
35
+ formatter_class_name = formatter_name.gsub(/(^|_)(.)/) { $2.upcase }
36
+ begin
37
+ require formatter_name
38
+ rescue LoadError
39
+ begin
40
+ require "td2planet/#{formatter_name}"
41
+ rescue LoadError
42
+ raise LoadError, "no such formatter: #{formatter_name}"
43
+ end
44
+ end
45
+ formatter = const_get(formatter_class_name)
46
+ end
47
+
48
+ def run(config)
49
+ formatter_name = config['formatter'] || 'default_formatter'
50
+ formatter = get_formatter_class(formatter_name).new(config)
51
+
52
+ writer = Writer.new(config, formatter)
53
+ fetcher = Fetcher.new(config['cache_dir'], @dry_run)
54
+ rss_list = fetcher.fetch_all_rss(config['uri'])
55
+
56
+ writer.output_html(rss_list)
57
+ writer.output_opml(rss_list)
58
+ writer.output_rss(rss_list)
59
+ end
60
+ end
@@ -0,0 +1,26 @@
1
+ #--
2
+ # -*- mode: ruby; coding: utf-8 -*-
3
+ # vim: set filetype=ruby ts=2 sw=2 sts=2 fenc=utf-8:
4
+ #
5
+ # copyright (c) 2006, 2007 Kazuhiro NISHIYAMA
6
+ #++
7
+
8
+ require 'td2planet/formatter'
9
+
10
+ module TD2Planet
11
+ class SampleFormatter < Formatter
12
+ def spam?(item)
13
+ if /ツッコミ/ =~ k(item.title) &&
14
+ /casino/ =~ item.dc_creator &&
15
+ /casino/ =~ item.description
16
+ true
17
+ else
18
+ false
19
+ end
20
+ end
21
+
22
+ def skip?(item)
23
+ spam?(item) or too_old?(item)
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,30 @@
1
+ #--
2
+ # -*- mode: ruby; coding: utf-8 -*-
3
+ # vim: set filetype=ruby ts=2 sw=2 sts=2 fenc=utf-8:
4
+ #
5
+ # copyright (c) 2006, 2007 Kazuhiro NISHIYAMA
6
+ #++
7
+
8
+ module TD2Planet
9
+ TD2PLANET_VERSION = "0.1.0"
10
+ TD2PLANET_RELEASE_DATE = "2007-02-22"
11
+
12
+ # return ruby version string (simulate output of ruby -v)
13
+ def self.ruby_version
14
+ if defined?(RUBY_PATCHLEVEL)
15
+ "ruby #{RUBY_VERSION} (#{RUBY_RELEASE_DATE} patchlevel #{RUBY_PATCHLEVEL}) [#{RUBY_PLATFORM}]"
16
+ else
17
+ "ruby #{RUBY_VERSION} (#{RUBY_RELEASE_DATE}) [#{RUBY_PLATFORM}]"
18
+ end
19
+ end
20
+
21
+ # return TD2Planet version string
22
+ def self.td2planet_version
23
+ "TD2Planet #{TD2PLANET_VERSION} (#{TD2PLANET_RELEASE_DATE})"
24
+ end
25
+
26
+ # return string for meta generator (see templates/layout.rhtml)
27
+ def self.generator
28
+ "#{td2planet_version} / Powered by #{ruby_version}"
29
+ end
30
+ end
@@ -0,0 +1,52 @@
1
+ #--
2
+ # -*- mode: ruby; coding: utf-8 -*-
3
+ # vim: set filetype=ruby ts=2 sw=2 sts=2 fenc=utf-8:
4
+ #
5
+ # copyright (c) 2006, 2007 Kazuhiro NISHIYAMA
6
+ #++
7
+
8
+ require 'pathname'
9
+
10
+ module TD2Planet
11
+ class Writer
12
+ def initialize(config, formatter)
13
+ @config = config
14
+ @output_dir ||= Pathname.new(config['output_dir'])
15
+ unless @output_dir.exist?
16
+ @output_dir.mkdir
17
+ end
18
+ @formatter = formatter
19
+ end
20
+
21
+ def output_html(rss_list)
22
+ if @config.key?('output_html')
23
+ output_html = @output_dir + @config['output_html']
24
+ else
25
+ output_html = @output_dir + 'index.html'
26
+ end
27
+
28
+ output_html.open('wb') do |f|
29
+ f.write(@formatter.to_html(rss_list))
30
+ end
31
+ end
32
+
33
+ def output_opml(rss_list)
34
+ output_opml = @output_dir + 'opml.xml'
35
+ output_opml.open('wb') do |f|
36
+ f.write(@formatter.to_opml(rss_list))
37
+ end
38
+ end
39
+
40
+ def output_rss(rss_list)
41
+ [
42
+ ['1.0', 'rss10.xml'],
43
+ ['2.0', 'rss20.xml'],
44
+ ].each do |rss_version, basename|
45
+ output_rss = @output_dir + basename
46
+ output_rss.open('wb') do |f|
47
+ f.write(@formatter.to_rss(rss_list, rss_version, basename))
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
metadata ADDED
@@ -0,0 +1,70 @@
1
+ --- !ruby/object:Gem::Specification
2
+ rubygems_version: 0.9.2
3
+ specification_version: 1
4
+ name: td2planet
5
+ version: !ruby/object:Gem::Version
6
+ version: 0.1.0
7
+ date: 2007-02-22 00:00:00 +09:00
8
+ summary: planet of ruby, mainly for tdiary
9
+ require_paths:
10
+ - lib
11
+ email: zn@mbf.nifty.com
12
+ homepage: http://rubyforge.org/projects/td2planet/
13
+ rubyforge_project: td2planet
14
+ description:
15
+ autorequire:
16
+ default_executable:
17
+ bindir: bin
18
+ has_rdoc: true
19
+ required_ruby_version: !ruby/object:Gem::Version::Requirement
20
+ requirements:
21
+ - - ">"
22
+ - !ruby/object:Gem::Version
23
+ version: 0.0.0
24
+ version:
25
+ platform: ruby
26
+ signing_key:
27
+ cert_chain:
28
+ post_install_message:
29
+ authors:
30
+ - Kazuhiro NISHIYAMA
31
+ files:
32
+ - ChangeLog
33
+ - MIT-LICENSE
34
+ - README
35
+ - README.ja
36
+ - bin/td2planet.rb
37
+ - config.yaml
38
+ - data/td2planet/templates/day.rhtml
39
+ - data/td2planet/templates/footer.rhtml
40
+ - data/td2planet/templates/header.rhtml
41
+ - data/td2planet/templates/layout.rhtml
42
+ - data/td2planet/templates/opml.rxml
43
+ - data/td2planet/templates/section.rhtml
44
+ - lib/td2planet/default_formatter.rb
45
+ - lib/td2planet/fetcher.rb
46
+ - lib/td2planet/formatter.rb
47
+ - lib/td2planet/runner.rb
48
+ - lib/td2planet/sample_formatter.rb
49
+ - lib/td2planet/version.rb
50
+ - lib/td2planet/writer.rb
51
+ test_files: []
52
+
53
+ rdoc_options:
54
+ - --charset
55
+ - utf-8
56
+ - --inline-source
57
+ - --line-numbers
58
+ - --main
59
+ - README
60
+ extra_rdoc_files:
61
+ - README
62
+ - README.ja
63
+ executables:
64
+ - td2planet.rb
65
+ extensions: []
66
+
67
+ requirements: []
68
+
69
+ dependencies: []
70
+