news2kindle 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +12 -0
- data/.rspec +3 -0
- data/.tachikoma.yml +1 -0
- data/.travis.yml +18 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +119 -0
- data/README.md +59 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/bin/test-generator +21 -0
- data/exe/news2kindle +107 -0
- data/lib/news2kindle.rb +12 -0
- data/lib/news2kindle/dup_checker.rb +41 -0
- data/lib/news2kindle/generator/internet-watch.rb +236 -0
- data/lib/news2kindle/generator/nikkei-free.rb +18 -0
- data/lib/news2kindle/generator/nikkei-paid.rb +352 -0
- data/lib/news2kindle/generator/tdiary.rb +135 -0
- data/lib/news2kindle/generator/wsj-paid.rb +360 -0
- data/lib/news2kindle/generator/wsjus-paid.rb +90 -0
- data/lib/news2kindle/task.rb +116 -0
- data/lib/news2kindle/version.rb +3 -0
- data/news2kindle.gemspec +37 -0
- data/news2kindle.yaml.sample +31 -0
- data/resource/internet-watch.css +27 -0
- data/resource/internet-watch.jpg +0 -0
- data/resource/nikkei.css +43 -0
- data/resource/nikkei.jpg +0 -0
- data/resource/tdiary.css +27 -0
- data/resource/wsj-us.jpg +0 -0
- data/resource/wsj.css +19 -0
- data/resource/wsj.jpg +0 -0
- metadata +245 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 7d94ebc86c80c6feb22ad91f1467083a2d0ef3c7
|
4
|
+
data.tar.gz: 65e21c3bf9c757f41a030268b6e413370c0ccc16
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 28ee0b8f40be33d8cbd401e13c4d5e03a628798056e069b7a539bff484f48483d6a052a088eff9ea1b55635fd0cd0427ff729540cc7eb85d9cf7150abefabcf3
|
7
|
+
data.tar.gz: f21b50fc0f883cf0d8eba883651e0ffb5a8680b905e5ce57bf0f546764cdfc39a885f6038634760b555003d43d4bf0b79af85af11959aff2155d29848eb6f09e
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.tachikoma.yml
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
strategy: 'bundler'
|
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,119 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
news2kindle (0.1.1)
|
5
|
+
dropbox_api
|
6
|
+
kindlegen
|
7
|
+
mail
|
8
|
+
mechanize
|
9
|
+
mongoid (~> 6.1)
|
10
|
+
nokogiri
|
11
|
+
pit
|
12
|
+
systemu
|
13
|
+
|
14
|
+
GEM
|
15
|
+
remote: https://rubygems.org/
|
16
|
+
specs:
|
17
|
+
activemodel (5.1.4)
|
18
|
+
activesupport (= 5.1.4)
|
19
|
+
activesupport (5.1.4)
|
20
|
+
concurrent-ruby (~> 1.0, >= 1.0.2)
|
21
|
+
i18n (~> 0.7)
|
22
|
+
minitest (~> 5.1)
|
23
|
+
tzinfo (~> 1.1)
|
24
|
+
bson (4.2.2)
|
25
|
+
coderay (1.1.2)
|
26
|
+
concurrent-ruby (1.0.5)
|
27
|
+
diff-lcs (1.3)
|
28
|
+
domain_name (0.5.20170404)
|
29
|
+
unf (>= 0.0.5, < 1.0.0)
|
30
|
+
dropbox_api (0.1.10)
|
31
|
+
faraday (~> 0.9, ~> 0.8)
|
32
|
+
oauth2 (~> 1.1)
|
33
|
+
faraday (0.12.2)
|
34
|
+
multipart-post (>= 1.2, < 3)
|
35
|
+
http-cookie (1.0.3)
|
36
|
+
domain_name (~> 0.5)
|
37
|
+
i18n (0.9.0)
|
38
|
+
concurrent-ruby (~> 1.0)
|
39
|
+
jwt (1.5.6)
|
40
|
+
kindlegen (3.0.3)
|
41
|
+
rake
|
42
|
+
rubyzip
|
43
|
+
mail (2.6.6)
|
44
|
+
mime-types (>= 1.16, < 4)
|
45
|
+
mechanize (2.7.5)
|
46
|
+
domain_name (~> 0.5, >= 0.5.1)
|
47
|
+
http-cookie (~> 1.0)
|
48
|
+
mime-types (>= 1.17.2)
|
49
|
+
net-http-digest_auth (~> 1.1, >= 1.1.1)
|
50
|
+
net-http-persistent (~> 2.5, >= 2.5.2)
|
51
|
+
nokogiri (~> 1.6)
|
52
|
+
ntlm-http (~> 0.1, >= 0.1.1)
|
53
|
+
webrobots (>= 0.0.9, < 0.2)
|
54
|
+
method_source (0.9.0)
|
55
|
+
mime-types (3.1)
|
56
|
+
mime-types-data (~> 3.2015)
|
57
|
+
mime-types-data (3.2016.0521)
|
58
|
+
mini_portile2 (2.3.0)
|
59
|
+
minitest (5.10.3)
|
60
|
+
mongo (2.4.3)
|
61
|
+
bson (>= 4.2.1, < 5.0.0)
|
62
|
+
mongoid (6.2.1)
|
63
|
+
activemodel (~> 5.1)
|
64
|
+
mongo (>= 2.4.1, < 3.0.0)
|
65
|
+
multi_json (1.12.2)
|
66
|
+
multi_xml (0.6.0)
|
67
|
+
multipart-post (2.0.0)
|
68
|
+
net-http-digest_auth (1.4.1)
|
69
|
+
net-http-persistent (2.9.4)
|
70
|
+
nokogiri (1.8.1)
|
71
|
+
mini_portile2 (~> 2.3.0)
|
72
|
+
ntlm-http (0.1.1)
|
73
|
+
oauth2 (1.4.0)
|
74
|
+
faraday (>= 0.8, < 0.13)
|
75
|
+
jwt (~> 1.0)
|
76
|
+
multi_json (~> 1.3)
|
77
|
+
multi_xml (~> 0.5)
|
78
|
+
rack (>= 1.2, < 3)
|
79
|
+
pit (0.0.7)
|
80
|
+
pry (0.11.1)
|
81
|
+
coderay (~> 1.1.0)
|
82
|
+
method_source (~> 0.9.0)
|
83
|
+
rack (2.0.3)
|
84
|
+
rake (12.1.0)
|
85
|
+
rspec (3.6.0)
|
86
|
+
rspec-core (~> 3.6.0)
|
87
|
+
rspec-expectations (~> 3.6.0)
|
88
|
+
rspec-mocks (~> 3.6.0)
|
89
|
+
rspec-core (3.6.0)
|
90
|
+
rspec-support (~> 3.6.0)
|
91
|
+
rspec-expectations (3.6.0)
|
92
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
93
|
+
rspec-support (~> 3.6.0)
|
94
|
+
rspec-mocks (3.6.0)
|
95
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
96
|
+
rspec-support (~> 3.6.0)
|
97
|
+
rspec-support (3.6.0)
|
98
|
+
rubyzip (1.2.1)
|
99
|
+
systemu (2.6.5)
|
100
|
+
thread_safe (0.3.6)
|
101
|
+
tzinfo (1.2.3)
|
102
|
+
thread_safe (~> 0.1)
|
103
|
+
unf (0.1.4)
|
104
|
+
unf_ext
|
105
|
+
unf_ext (0.0.7.4)
|
106
|
+
webrobots (0.1.2)
|
107
|
+
|
108
|
+
PLATFORMS
|
109
|
+
ruby
|
110
|
+
|
111
|
+
DEPENDENCIES
|
112
|
+
bundler
|
113
|
+
news2kindle!
|
114
|
+
pry
|
115
|
+
rake
|
116
|
+
rspec
|
117
|
+
|
118
|
+
BUNDLED WITH
|
119
|
+
1.16.0.pre.3
|
data/README.md
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
# News2Kindle
|
2
|
+
ニュースサイトを定期的にスクレイピングしてmobiファイルを生成し、Kindle Personal Documentへメールで送信するコマンドライン・ツール
|
3
|
+
|
4
|
+
ニュースの電子書籍化と配信を自動化するソフトウェアとしては電子書籍管理ツールであるCalibreが豊富なレシピで抜きん出た存在ですが、クライアントPCを常時稼動しておかなくてはならず、環境面で稼働が難しい面があります。そこで、サーバ上でcronタスクとして稼働する仕組みを作りました。ただしレシピはまだぜんぜんありません(作者が使っている日経新聞電子版とINTERNET Watch、tDiaryのみ)。
|
5
|
+
|
6
|
+
## 仕組み
|
7
|
+
cronタスクとして動かすことを前提にしています。
|
8
|
+
|
9
|
+
実際にどのサイトをmobiファイル化するのかという指定は、`~/.news2kindle`ないし`./news2kindle.yaml`のconfigファイルで指定します。configファイルのサンプルです:
|
10
|
+
|
11
|
+
```yaml
|
12
|
+
:tasks:
|
13
|
+
sites1:
|
14
|
+
:media:
|
15
|
+
- foo
|
16
|
+
- bar
|
17
|
+
:receiver:
|
18
|
+
- receiver1@example.com
|
19
|
+
sites2:
|
20
|
+
:media:
|
21
|
+
- buz
|
22
|
+
:receiver:
|
23
|
+
- dropbox:/Public
|
24
|
+
:sender: hoge@example.com
|
25
|
+
:email:
|
26
|
+
:address: smtp.sendgrid.net
|
27
|
+
:port: 587
|
28
|
+
:user_name: yes
|
29
|
+
:password: yes
|
30
|
+
:authentication: :plain
|
31
|
+
:mongodb_uri: mongodb://localhost:27017/news2kindle
|
32
|
+
```
|
33
|
+
|
34
|
+
cronタスクを動かす時間によって、異なるニュースサイトにアクセスしたり、送り先を変えたいでしょう。そのため、コマンドに指定する「タスク(:tasks)」を分けて、それぞれに「メディア(:media)」と「送り先(:receiver)」を指定できるようになっています。receiverにはメールアドレスの他に「dropbox:」で始まるDropboxのディレクトリも指定できます。Dropboxを利用する場合には、Dropboxの開発者向けサービスから各種APIトークンを取得しておく必要があります。
|
35
|
+
|
36
|
+
「送信元(:sender)」は、KPDサービスに登録してあるメールアドレスを指定します。
|
37
|
+
|
38
|
+
「:email」は、メールサーバ(SMTP)の設定です。プログラムを動かしている環境からアクセスできるメールサーバの情報を指定します。なお、メールサーバが認証を必要とする場合は「:user_name」や「:password」を指定する必要がありますが、configファイルには直接書くことはありません。これらの項目を「yes」にしておくと、初回実行時にプログラムが聞いてきます(~/.pit/default.yamlというファイルに保存されます)。
|
39
|
+
|
40
|
+
「:mongodb_uri」はURIの重複チェックをする場合にMongoDBの情報を指定します。日に何度も動かすと、すでに取得済みの記事が重複して含まれてしまいますが、それをチェックして除外したい場合に利用します。URIにパスワード等の情報が含まれている場合には「yes」とだけ指定しておくと、最初の実行時に尋ねてくるようになります(Pitによって安全な別ファイルに保管されます)。
|
41
|
+
|
42
|
+
mobiファイルの生成に成功すると、指定したアドレスにメールを送ったり、Dropboxの指定フォルダに保存します。メールアドレスは、実際は〜@kindle.comになるでしょう(:receiver)。また、送信元のアドレスもKindle Personal Documentで許可したアドレスを指定して置く必要があります(:sender)。
|
43
|
+
|
44
|
+
## 動かし方
|
45
|
+
インストール方法:
|
46
|
+
|
47
|
+
```sh
|
48
|
+
% gem install news2kindle
|
49
|
+
```
|
50
|
+
|
51
|
+
news2kindleコマンドを実行すると、ヘルプが出ます。適切なconfigファイルがあれば、そこに記述してあるタスクを指定することで、mobiファイルが生成され、指定した送信先へ送られます。
|
52
|
+
|
53
|
+
|
54
|
+
## ジェネレータの作り方
|
55
|
+
あとで書く。
|
56
|
+
|
57
|
+
## Contributing
|
58
|
+
|
59
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/tdtds/news2kindle.
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "news2kindle"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start(__FILE__)
|
data/bin/setup
ADDED
data/bin/test-generator
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require 'news2kindle'
|
3
|
+
require 'kindlegen'
|
4
|
+
require 'logger'
|
5
|
+
|
6
|
+
News2Kindle::DupChecker.setup({
|
7
|
+
clients: {
|
8
|
+
default: {
|
9
|
+
uri: 'mongodb://localhost:27017/news2kindle'
|
10
|
+
}
|
11
|
+
}
|
12
|
+
})
|
13
|
+
|
14
|
+
ARGV.each do |task|
|
15
|
+
require "news2kindle/generator/#{task}"
|
16
|
+
gen = News2Kindle::Generator.const_get(task.split(/-/).map{|a|a.capitalize}.join)
|
17
|
+
Dir::mkdir(task)
|
18
|
+
gen.new(task).generate({now:Time::now}) do |opf|
|
19
|
+
Kindlegen.run(opf, '-o', "#{task}.mobi")
|
20
|
+
end
|
21
|
+
end
|
data/exe/news2kindle
ADDED
@@ -0,0 +1,107 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
#
|
3
|
+
# news2kindle: scraping news sites and generate kindle document
|
4
|
+
#
|
5
|
+
# Copyright (C) 2017 by TADA Tadashi <t@tdtds.jp>
|
6
|
+
# Distributed under GPL
|
7
|
+
#
|
8
|
+
|
9
|
+
require 'news2kindle'
|
10
|
+
require 'optparse'
|
11
|
+
require 'open-uri'
|
12
|
+
require 'yaml'
|
13
|
+
|
14
|
+
module News2Kindle
|
15
|
+
|
16
|
+
class CLI
|
17
|
+
def run
|
18
|
+
conf, tasks = parse_options
|
19
|
+
News2Kindle.logger.level = Logger::DEBUG if conf[:verbose]
|
20
|
+
|
21
|
+
if conf[:mongodb_uri]
|
22
|
+
unless conf[:mongodb_uri] =~ %r|^mongodb://|
|
23
|
+
conf[:mongodb_uri] = Pit::get('news2kindle', require: {
|
24
|
+
mongodb_uri: 'MongoDB URI for Dupulicate Check starts with "mongodb://".'
|
25
|
+
})[:mongodb_uri]
|
26
|
+
end
|
27
|
+
if conf[:mongodb_uri]
|
28
|
+
DupChecker.setup({clients:{default:{uri:conf[:mongodb_uri]}}})
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
tasks.each do |name|
|
33
|
+
task = conf[:tasks][name]
|
34
|
+
usage("task '#{name}' not found") unless task
|
35
|
+
|
36
|
+
task[:media].each do |media|
|
37
|
+
begin
|
38
|
+
opts = {now: Time.now}.merge(task[:option] || {})
|
39
|
+
News2Kindle.logger.info "starting #{media}..."
|
40
|
+
Task::new(media).run(task[:receiver], conf[:sender], opts)
|
41
|
+
rescue
|
42
|
+
News2Kindle.logger.fatal($!)
|
43
|
+
raise
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
def parse_options(argv = ARGV)
|
51
|
+
op = OptionParser.new
|
52
|
+
|
53
|
+
self.class.module_eval do
|
54
|
+
define_method(:usage) do |msg = nil|
|
55
|
+
puts op.to_s
|
56
|
+
puts "error: #{msg}" if msg
|
57
|
+
exit 1
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
opts = {
|
62
|
+
verbose: false
|
63
|
+
}
|
64
|
+
|
65
|
+
op.on('-C', '--config VALUE', "configuration file") do |v|
|
66
|
+
usage("#{v} is not existent") unless Pathname(v).expand_path.exist?
|
67
|
+
opts[:config] = v
|
68
|
+
end
|
69
|
+
op.on('-s', '--sender VALUE', "sender e-mail address") do |v|
|
70
|
+
opts[:sender] = v
|
71
|
+
end
|
72
|
+
op.on('-m', '--mongodb-uri VALUE', "MongoDB URI for dupulicate check or 'no'") do |v|
|
73
|
+
opts[:mongodb_uri] = v == 'no' ? false : v
|
74
|
+
end
|
75
|
+
op.on('-V', '--verbose', "print verbose messages") do |v|
|
76
|
+
opts[:verbose] = true
|
77
|
+
end
|
78
|
+
|
79
|
+
op.banner += ' TASK1 [TASK2...]'
|
80
|
+
begin
|
81
|
+
args = op.parse(argv)
|
82
|
+
rescue OptionParser::InvalidOption => e
|
83
|
+
usage e.message
|
84
|
+
end
|
85
|
+
|
86
|
+
conf = nil
|
87
|
+
[opts[:config], './news2kindle.yaml', '~/.news2kindle'].each do |config_file|
|
88
|
+
begin
|
89
|
+
file = Pathname(config_file).expand_path
|
90
|
+
conf = YAML.load_file(file)
|
91
|
+
opts[:config] = file
|
92
|
+
break
|
93
|
+
rescue TypeError, Errno::ENOENT
|
94
|
+
end
|
95
|
+
end
|
96
|
+
usage 'needs configuration file ./news2kindle.yaml or ~/.news2kindle' unless conf
|
97
|
+
conf.merge!(opts)
|
98
|
+
|
99
|
+
if args.size < 1
|
100
|
+
usage "needs some tasks: #{conf[:tasks].keys.join(', ')}"
|
101
|
+
end
|
102
|
+
[conf, args]
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
News2Kindle::CLI.new.run
|
data/lib/news2kindle.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'news2kindle/version'
|
2
|
+
require 'news2kindle/task'
|
3
|
+
require 'news2kindle/dup_checker'
|
4
|
+
require 'logger'
|
5
|
+
|
6
|
+
module News2Kindle
|
7
|
+
@logger = Logger.new(STDERR)
|
8
|
+
@logger.level = Logger::ERROR
|
9
|
+
@logger.formatter = proc{|severity, _, _, msg| "#{severity}: #{msg}\n"}
|
10
|
+
def self.logger; @logger; end
|
11
|
+
def self.logger=(logger); @logger = logger; end
|
12
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# uri duplication checker
|
2
|
+
#
|
3
|
+
# Copyright (C) 2017 by TADA Tadashi <t@tdtds.jp>
|
4
|
+
# Distributed under GPL.
|
5
|
+
#
|
6
|
+
require 'mongoid'
|
7
|
+
|
8
|
+
module News2Kindle
|
9
|
+
class DupChecker
|
10
|
+
Mongo::Logger.level = Logger::WARN
|
11
|
+
@@mongoid_conf = nil
|
12
|
+
|
13
|
+
include Mongoid::Document
|
14
|
+
include Mongoid::Timestamps
|
15
|
+
store_in collection: 'uri'
|
16
|
+
field :uri, type: String
|
17
|
+
|
18
|
+
def self.setup(mongoid_conf)
|
19
|
+
@@mongoid_conf = mongoid_conf
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.dup?(uri)
|
23
|
+
return false unless @@mongoid_conf
|
24
|
+
Mongoid::Config.load_configuration(@@mongoid_conf) if Mongoid::Config.clients.size == 0
|
25
|
+
|
26
|
+
begin
|
27
|
+
url = uri.to_s
|
28
|
+
if self.where(uri: uri.to_s).size == 0
|
29
|
+
self.create(uri: uri.to_s)
|
30
|
+
return false
|
31
|
+
else
|
32
|
+
return true
|
33
|
+
end
|
34
|
+
rescue Moped::Errors::ConnectionFailure
|
35
|
+
News2Kindle.logger.error $!
|
36
|
+
@@mongoid_conf = nil
|
37
|
+
return false
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|