saber 1.1.1 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/CHANGELOG.md +8 -1
- data/Gemfile +6 -1
- data/Gemfile.lock +58 -14
- data/README.md +40 -125
- data/bin/saber +4 -2
- data/bin/saber.bb +3 -0
- data/bin/saber.stp +3 -0
- data/lib/saber.rb +5 -0
- data/lib/saber/autofetcher/server.rb +1 -1
- data/lib/saber/book.rb +36 -0
- data/lib/saber/cli.rb +45 -19
- data/lib/saber/core_ext.rb +68 -0
- data/lib/saber/fetcher.rb +2 -2
- data/lib/saber/rc.rb +6 -0
- data/lib/saber/task.rb +3 -0
- data/lib/saber/task/base.rb +6 -1
- data/lib/saber/task/chd.rb +10 -2
- data/lib/saber/task/clean.rb +2 -2
- data/lib/saber/task/find_uploads.rb +53 -0
- data/lib/saber/task/generate.rb +37 -20
- data/lib/saber/task/make.rb +20 -8
- data/lib/saber/task/send.rb +1 -1
- data/lib/saber/task/upload.rb +29 -19
- data/lib/saber/tracker.rb +8 -4
- data/lib/saber/tracker/base.rb +36 -15
- data/lib/saber/tracker/bb.rb +4 -10
- data/lib/saber/tracker/bib.rb +27 -11
- data/lib/saber/tracker/chd.rb +4 -4
- data/lib/saber/tracker/gazelle.rb +7 -0
- data/lib/saber/tracker/ptp.rb +2 -2
- data/lib/saber/tracker/stp.rb +53 -0
- data/lib/saber/tracker/what.rb +2 -2
- data/lib/saber/tracker2.rb +31 -0
- data/lib/saber/tracker2/base.rb +126 -0
- data/lib/saber/tracker2/bb.rb +211 -0
- data/lib/saber/tracker2/bib.rb +162 -0
- data/lib/saber/tracker2/gazelle.rb +52 -0
- data/lib/saber/tracker2/stp.rb +136 -0
- data/lib/saber/tracker2/what.rb +51 -0
- data/lib/saber/version.rb +1 -1
- data/lib/saber/watir_ext.rb +95 -0
- data/saber.gemspec +6 -1
- data/spec/saber/autofetcher/server_spec.rb +1 -1
- data/spec/saber/task_spec.rb +1 -1
- data/systemd/saber-chd@.service +12 -0
- data/systemd/saber-client@.service +12 -0
- data/systemd/saber-server@.service +12 -0
- data/templates/_saberrc +29 -8
- data/templates/article.yml +18 -0
- data/templates/bib/application.yml +8 -8
- data/templates/bib/audiobook.yml +12 -14
- data/templates/comic.yml +25 -0
- data/templates/ebook.yml +35 -0
- data/templates/journal.yml +19 -0
- data/templates/magazine.yml +41 -0
- data/templates/manual.yml +6 -0
- data/templates/newspaper.yml +6 -0
- metadata +109 -13
- data/templates/bb/comic.yml +0 -7
- data/templates/bb/ebook.yml +0 -8
- data/templates/bb/magazine.yml +0 -6
- data/templates/bib/article.yml +0 -18
- data/templates/bib/comic.yml +0 -22
- data/templates/bib/ebook.yml +0 -20
- data/templates/bib/journal.yml +0 -18
- data/templates/bib/magazine.yml +0 -18
- data/templates/what/ebook.yml +0 -6
data/bin/saber.bb
ADDED
data/bin/saber.stp
ADDED
data/lib/saber.rb
CHANGED
@@ -3,6 +3,8 @@ require "pa"
|
|
3
3
|
require "optimism"
|
4
4
|
require "active_support/core_ext/module/attribute_accessors"
|
5
5
|
require "active_support/concern"
|
6
|
+
require "active_support/core_ext/numeric/bytes"
|
7
|
+
require "saber/core_ext"
|
6
8
|
|
7
9
|
module Saber
|
8
10
|
autoload :VERSION, "saber/version"
|
@@ -12,11 +14,14 @@ module Saber
|
|
12
14
|
autoload :Fetcher, "saber/fetcher"
|
13
15
|
autoload :AutoFetcher, "saber/autofetcher"
|
14
16
|
autoload :Tracker, "saber/tracker"
|
17
|
+
autoload :Tracker2, "saber/tracker2"
|
18
|
+
autoload :Book, "saber/book"
|
15
19
|
|
16
20
|
Error = Class.new Exception
|
17
21
|
FatalError = Class.new Exception
|
18
22
|
Rc = Optimism.require "saber/rc", "~/.saberrc"
|
19
23
|
|
24
|
+
|
20
25
|
class << self
|
21
26
|
attr_accessor :ui
|
22
27
|
|
@@ -65,7 +65,7 @@ module Saber
|
|
65
65
|
|
66
66
|
# ["filea", "foo/filea", "foo/fileb"]
|
67
67
|
def build_files(*names)
|
68
|
-
Pa.ls2_r(*names, :base_dir => Rc.
|
68
|
+
Pa.ls2_r(*names, :base_dir => Rc.fetch.remote_dir, :file => true, :include => true) { |p,abs| not Pa.directory?(abs) }
|
69
69
|
end
|
70
70
|
end
|
71
71
|
end
|
data/lib/saber/book.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
require "faraday"
|
2
|
+
require "faraday_middleware"
|
3
|
+
|
4
|
+
module Saber
|
5
|
+
class Book
|
6
|
+
# delegate to #populate
|
7
|
+
def self.populate(*args)
|
8
|
+
new.populate(*args)
|
9
|
+
end
|
10
|
+
|
11
|
+
attr_reader :client
|
12
|
+
|
13
|
+
def initialize
|
14
|
+
@client = Faraday.new(url: Rc.api_url) {|c|
|
15
|
+
c.response :follow_redirects
|
16
|
+
c.response :json, :content_type => /\bjson$/
|
17
|
+
|
18
|
+
c.adapter Faraday.default_adapter
|
19
|
+
}
|
20
|
+
end
|
21
|
+
|
22
|
+
# @return [Hash] data
|
23
|
+
def populate(isbn, filename)
|
24
|
+
params = {}
|
25
|
+
rep = client.get("/books/#{isbn}", params)
|
26
|
+
data = rep.body
|
27
|
+
|
28
|
+
if data["status"] == 0
|
29
|
+
data["tracker"]
|
30
|
+
else
|
31
|
+
Saber.ui.error "Can't populate book -- #{isbn} #{filename}."
|
32
|
+
{}
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
data/lib/saber/cli.rb
CHANGED
@@ -7,28 +7,29 @@ module Saber
|
|
7
7
|
class_option "no-color", banner: "Disable colorization in output", type: :boolean
|
8
8
|
class_option "verbose", aliases: "-V", banner: "Enable verbose output mode", type: :boolean
|
9
9
|
class_option "log", banner: "Log file", type: :string
|
10
|
-
class_option "force",
|
10
|
+
class_option "force", banner: "Fore writing even if file exists", type: :boolean
|
11
11
|
class_option "tracker", aliases: "-t", banner: "tracker name", type: :string
|
12
|
-
|
13
|
-
attr_reader :o
|
12
|
+
class_option "dry-run", aliases: "-n", banner: "dry run", type: :boolean
|
14
13
|
|
15
14
|
def initialize(*)
|
16
15
|
super
|
17
|
-
|
16
|
+
self.options = self.options.dup
|
18
17
|
|
19
|
-
Saber.ui = if
|
18
|
+
Saber.ui = if options["log"] then
|
20
19
|
require "logger"
|
21
|
-
UI::Logger.new(::Logger.new(
|
20
|
+
UI::Logger.new(::Logger.new(options["log"]))
|
22
21
|
else
|
23
22
|
the_shell = (options["no-color"] ? Thor::Shell::Basic.new : shell)
|
24
23
|
UI::Shell.new(the_shell)
|
25
24
|
end
|
26
25
|
|
27
|
-
Saber.ui.debug! if
|
26
|
+
Saber.ui.debug! if options["verbose"]
|
28
27
|
|
29
28
|
# Initialize environment in first time
|
30
29
|
unless Rc.p.home.exists?
|
31
|
-
Pa.mkdir Rc.p.home
|
30
|
+
Pa.mkdir Rc.p.home
|
31
|
+
Pa.mkdir "#{Rc.p.home}/templates"
|
32
|
+
Pa.mkdir "#{Rc.p.home}/database"
|
32
33
|
end
|
33
34
|
end
|
34
35
|
|
@@ -36,7 +37,7 @@ module Saber
|
|
36
37
|
def clean
|
37
38
|
require "saber/task/clean"
|
38
39
|
|
39
|
-
Task["clean"].invoke(:clean, [],
|
40
|
+
Task["clean"].invoke(:clean, [], options)
|
40
41
|
end
|
41
42
|
|
42
43
|
desc "server", "start saber-server daemon"
|
@@ -62,18 +63,25 @@ module Saber
|
|
62
63
|
AutoFetcher::DRbClient.new.add(*names)
|
63
64
|
end
|
64
65
|
|
65
|
-
desc "upload [options] <torrent_file/file ...>", "[make a torrent file and] upoad a torrent file to the site"
|
66
|
-
|
66
|
+
desc "upload [options] <format> <torrent_file/file ...>", "[make a torrent file and] upoad a torrent file to the site"
|
67
|
+
method_option "add", aliases: "-a", desc: "upload via add format.", type: :boolean
|
68
|
+
def upload(format0, *files)
|
67
69
|
require "saber/task/upload"
|
70
|
+
format = format0.downcase
|
71
|
+
Saber.ui.error! "Don't support this format -- #{format0}" unless Rc.book_exts.include?(".#{format}")
|
68
72
|
|
69
|
-
|
73
|
+
files = files.map{|v| v.dup} # unfrozen string.
|
74
|
+
Task["upload"].invoke(:upload, [options["tracker"] || ENV["SABER_TRACKER"], format, *wrap_file(*files)], options)
|
70
75
|
end
|
71
76
|
|
72
|
-
desc "generate [options] <type>
|
73
|
-
|
77
|
+
desc "generate [options] <type> [filename:isbn ...]", %~generate a meta data file (alias: "g")~
|
78
|
+
method_option "file", aliases: "-f", desc: "read files from file list", type: :string
|
79
|
+
def generate(type, *files)
|
74
80
|
require "saber/task/generate"
|
75
81
|
|
76
|
-
|
82
|
+
files = File.read(options["file"]).split(/\n+/).map{|v| v.strip} if options["file"]
|
83
|
+
files = files.map{|v| name, isbn = v.split(":"); [*wrap_file(name), isbn]}
|
84
|
+
Task["generate"].invoke(:generate, [type, *files], options)
|
77
85
|
end
|
78
86
|
map "g" => "generate"
|
79
87
|
|
@@ -86,21 +94,39 @@ module Saber
|
|
86
94
|
def send1(*names)
|
87
95
|
require "saber/task/send"
|
88
96
|
|
89
|
-
Task["send"].invoke(:send1, names,
|
97
|
+
Task["send"].invoke(:send1, names, options)
|
90
98
|
end
|
91
99
|
|
92
100
|
desc "make [options] <file ..>", "make a torent file and send it to local and/or remote watch directory"
|
101
|
+
method_option "option", aliases: "-o", desc: "extra options passed to mktorrent", type: :string
|
102
|
+
method_option "file", aliases: "-f", desc: "read files from file list", type: :string
|
93
103
|
def make(*files)
|
94
104
|
require "saber/task/make"
|
95
105
|
|
96
|
-
|
106
|
+
files = File.read(options["file"]).split(/\n+/).map{|v| v.strip.split(":")[0] } if options["file"]
|
107
|
+
Task["make"].invoke(:make, [options["tracker"] || ENV["SABER_TRACKER"], *files], options)
|
97
108
|
end
|
98
109
|
|
99
|
-
desc "chd", "
|
110
|
+
desc "chd", "NOT WORKING"
|
100
111
|
def chd
|
101
112
|
require "saber/task/chd"
|
102
113
|
|
103
|
-
Task["chd"].invoke(:chd,
|
114
|
+
Task["chd"].invoke(:chd, [], options)
|
115
|
+
end
|
116
|
+
|
117
|
+
desc "find_uploads", "NOT WORKING"
|
118
|
+
def find_uploads(page)
|
119
|
+
require "saber/task/find_uploads"
|
120
|
+
|
121
|
+
Task["find_uploads"].invoke(:find_uploads, [page], options)
|
122
|
+
end
|
123
|
+
|
124
|
+
private
|
125
|
+
|
126
|
+
# a.yml -> a
|
127
|
+
# a.epub.torrent -> a
|
128
|
+
def wrap_file(*names)
|
129
|
+
names.map{|v| Pa.delete_ext(v, *%w[.torrent .yml]).delete_ext2(*Rc.book_exts)}
|
104
130
|
end
|
105
131
|
end
|
106
132
|
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
class Hash
|
2
|
+
# From Rails 4.0
|
3
|
+
|
4
|
+
# Return a new hash with all keys converted by the block operation.
|
5
|
+
# This includes the keys from the root hash and from all
|
6
|
+
# nested hashes.
|
7
|
+
#
|
8
|
+
# hash = { person: { name: 'Rob', age: '28' } }
|
9
|
+
#
|
10
|
+
# hash.deep_transform_keys{ |key| key.to_s.upcase }
|
11
|
+
# # => { "PERSON" => { "NAME" => "Rob", "AGE" => "28" } }
|
12
|
+
def deep_transform_keys(&block)
|
13
|
+
result = {}
|
14
|
+
each do |key, value|
|
15
|
+
result[yield(key)] = value.is_a?(Hash) ? value.deep_transform_keys(&block) : value
|
16
|
+
end
|
17
|
+
result
|
18
|
+
end
|
19
|
+
|
20
|
+
# Destructively convert all keys by using the block operation.
|
21
|
+
# This includes the keys from the root hash and from all
|
22
|
+
# nested hashes.
|
23
|
+
def deep_transform_keys!(&block)
|
24
|
+
keys.each do |key|
|
25
|
+
value = delete(key)
|
26
|
+
self[yield(key)] = value.is_a?(Hash) ? value.deep_transform_keys!(&block) : value
|
27
|
+
end
|
28
|
+
self
|
29
|
+
end
|
30
|
+
|
31
|
+
# Return a new hash with all keys converted to strings.
|
32
|
+
# This includes the keys from the root hash and from all
|
33
|
+
# nested hashes.
|
34
|
+
#
|
35
|
+
# hash = { person: { name: 'Rob', age: '28' } }
|
36
|
+
#
|
37
|
+
# hash.deep_stringify_keys
|
38
|
+
# # => { "person" => { "name" => "Rob", "age" => "28" } }
|
39
|
+
def deep_stringify_keys
|
40
|
+
deep_transform_keys{ |key| key.to_s }
|
41
|
+
end
|
42
|
+
|
43
|
+
# Destructively convert all keys to strings.
|
44
|
+
# This includes the keys from the root hash and from all
|
45
|
+
# nested hashes.
|
46
|
+
def deep_stringify_keys!
|
47
|
+
deep_transform_keys!{ |key| key.to_s }
|
48
|
+
end
|
49
|
+
|
50
|
+
# Return a new hash with all keys converted to symbols, as long as
|
51
|
+
# they respond to +to_sym+. This includes the keys from the root hash
|
52
|
+
# and from all nested hashes.
|
53
|
+
#
|
54
|
+
# hash = { 'person' => { 'name' => 'Rob', 'age' => '28' } }
|
55
|
+
#
|
56
|
+
# hash.deep_symbolize_keys
|
57
|
+
# # => { person: { name: "Rob", age: "28" } }
|
58
|
+
def deep_symbolize_keys
|
59
|
+
deep_transform_keys{ |key| key.to_sym rescue key }
|
60
|
+
end
|
61
|
+
|
62
|
+
# Destructively convert all keys to symbols, as long as they respond
|
63
|
+
# to +to_sym+. This includes the keys from the root hash and from all
|
64
|
+
# nested hashes.
|
65
|
+
def deep_symbolize_keys!
|
66
|
+
deep_transform_keys!{ |key| key.to_sym rescue key }
|
67
|
+
end
|
68
|
+
end
|
data/lib/saber/fetcher.rb
CHANGED
@@ -17,7 +17,7 @@ module Saber
|
|
17
17
|
def add(*files)
|
18
18
|
files.each { |file|
|
19
19
|
uri = "#{Rc.server.ftp}/#{file}"
|
20
|
-
gid = aria2_add([uri], :dir => Pa.dir2("#{Rc.
|
20
|
+
gid = aria2_add([uri], :dir => Pa.dir2("#{Rc.fetch.dir}/#{file}"))
|
21
21
|
Saber.ui.debug "DOWNLOAD #{gid} #{uri}"
|
22
22
|
}
|
23
23
|
end
|
@@ -28,7 +28,7 @@ module Saber
|
|
28
28
|
files = []
|
29
29
|
Net::SSH.start(Rc.server.host, Rc.server.user) do |s|
|
30
30
|
name = "'#{names.join("' '")}'"
|
31
|
-
cmd = "cd #{Rc.
|
31
|
+
cmd = "cd #{Rc.fetch.remote_dir} && find #{name} -type f"
|
32
32
|
|
33
33
|
rst = s.exec!(cmd)
|
34
34
|
if rst =~ /^find: `|^cd:cd:/
|
data/lib/saber/rc.rb
CHANGED
@@ -1,9 +1,15 @@
|
|
1
|
+
api_url = "http://saberapi.heroku.com"
|
1
2
|
scgi_server = "http://localhost/RPC2"
|
3
|
+
browser = [:firefox]
|
4
|
+
book_exts = %w[.epub .mobi .pdf .txt .html .djvu .chm .cbr .cbz .azw3]
|
5
|
+
book_formats = %w[epub mobi pdf txt html djvu chm cbr cbz azw3]
|
2
6
|
|
3
7
|
p:
|
4
8
|
root = Pa.expand("../../..", __FILE__)
|
5
9
|
home = Pa("~/.saber")
|
6
10
|
homerc = Pa("~/.saberrc")
|
11
|
+
database = Pa("~/.saber/database")
|
12
|
+
template = Pa("~/.saber/templates")
|
7
13
|
|
8
14
|
aria2:
|
9
15
|
rpc = "http://localhost:6800/rpc"
|
data/lib/saber/task.rb
CHANGED
@@ -18,6 +18,7 @@ module Saber
|
|
18
18
|
autoload :Clean, "saber/task/clean"
|
19
19
|
autoload :Make, "saber/task/make"
|
20
20
|
autoload :Upload, "saber/task/upload"
|
21
|
+
autoload :FindUploads, "saber/task/find_uploads"
|
21
22
|
|
22
23
|
@@tasks = {}
|
23
24
|
|
@@ -26,6 +27,8 @@ module Saber
|
|
26
27
|
|
27
28
|
class << self
|
28
29
|
def [](name)
|
30
|
+
require "saber/task/#{name}"
|
31
|
+
|
29
32
|
tasks[name]
|
30
33
|
end
|
31
34
|
end
|
data/lib/saber/task/base.rb
CHANGED
@@ -8,11 +8,16 @@ module Saber
|
|
8
8
|
Task.tasks[child.name.demodulize.underscore] = child
|
9
9
|
end
|
10
10
|
|
11
|
-
#
|
11
|
+
# delegate to #invoke
|
12
12
|
def invoke(*args)
|
13
13
|
new.invoke(*args)
|
14
14
|
end
|
15
15
|
end
|
16
|
+
|
17
|
+
def initialize(*)
|
18
|
+
super
|
19
|
+
self.options = self.options.dup
|
20
|
+
end
|
16
21
|
end
|
17
22
|
end
|
18
23
|
end
|
data/lib/saber/task/chd.rb
CHANGED
@@ -1,10 +1,11 @@
|
|
1
|
+
require "sys/filesystem"
|
2
|
+
|
1
3
|
module Saber
|
2
4
|
module Task
|
3
5
|
class CHD < Base
|
4
6
|
|
5
7
|
desc "chd", "chd"
|
6
8
|
def chd(o={})
|
7
|
-
require "saber/tracker/chd"
|
8
9
|
t = Tracker["chd"].new
|
9
10
|
|
10
11
|
begin
|
@@ -14,7 +15,14 @@ module Saber
|
|
14
15
|
t.update_cache(true)
|
15
16
|
|
16
17
|
while true
|
17
|
-
|
18
|
+
# check free diskspace
|
19
|
+
s = Sys::Filesystem.stat(Rc.chd.diskspace_dir.p)
|
20
|
+
if s.block_size * s.blocks_free < Rc.chd.diskspace_limit
|
21
|
+
Saber.ui.say "::SKIP:: Reach low diskspace."
|
22
|
+
else
|
23
|
+
t.add_torrents
|
24
|
+
end
|
25
|
+
|
18
26
|
sleep Rc.chd.update_interval
|
19
27
|
end
|
20
28
|
rescue Errno::ETIMEDOUT, Mechanize::ResponseCodeError, SocketError
|
data/lib/saber/task/clean.rb
CHANGED
@@ -6,8 +6,8 @@ module Saber
|
|
6
6
|
class Clean < Base
|
7
7
|
desc "clean", "clean"
|
8
8
|
def clean
|
9
|
-
disk_files = Pa.ls2(Rc.
|
10
|
-
bt_files = Retort::Torrent.all.map{|t| Retort::Torrent.action("name", t.info_hash) }.map{|n| Pa.join2(Rc.
|
9
|
+
disk_files = Pa.ls2(Rc.clean.dir, absolute: true)
|
10
|
+
bt_files = Retort::Torrent.all.map{|t| Retort::Torrent.action("name", t.info_hash) }.map{|n| Pa.join2(Rc.clean.dir, n)}
|
11
11
|
|
12
12
|
(disk_files - bt_files).each { |file|
|
13
13
|
Pa.rm_r file, :verbose => true
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require "tagen/core/io"
|
2
|
+
require "isbn"
|
3
|
+
|
4
|
+
module Saber
|
5
|
+
module Task
|
6
|
+
class FindUploads < Base
|
7
|
+
desc "find_uploads", "find_uploads"
|
8
|
+
def find_uploads(page="1")
|
9
|
+
bib = Tracker["bib"].new(options)
|
10
|
+
stp = Tracker["stp"].new(options)
|
11
|
+
dir = Rc._fetch("find_uploads.dir", ".")
|
12
|
+
bib.agent.pluggable_parser["application/x-bittorrent"] = Mechanize::DirectorySaver.save_to(dir.to_s)
|
13
|
+
bib.login
|
14
|
+
stp.login
|
15
|
+
|
16
|
+
bib.browse(page) {|torrent|
|
17
|
+
title, isbn, download_link, filenames, tags = torrent[:title], torrent[:isbn],
|
18
|
+
torrent[:download_link], torrent[:filenames], torrent[:tags]
|
19
|
+
|
20
|
+
generic_tags = convert_bibtags(tags)
|
21
|
+
|
22
|
+
begin
|
23
|
+
isbn = ISBN.thirteen(torrent[:isbn])
|
24
|
+
rescue ISBN::Invalid13DigitISBN # empty
|
25
|
+
next
|
26
|
+
end
|
27
|
+
|
28
|
+
if not stp.exists?(isbn: isbn)
|
29
|
+
bib.get(download_link)
|
30
|
+
|
31
|
+
Saber.ui.say "#{isbn} #{title}\n #{filenames.join("\n ")}"
|
32
|
+
File.append("list", "#{filenames[0]}:#{isbn}\n")
|
33
|
+
|
34
|
+
# local data
|
35
|
+
local_data = Pa.exists?("#{Rc.p.database}/#{isbn}.yml") ? YAML.load_file("#{Rc.p.database}/#{isbn}.yml") : {}
|
36
|
+
local_data.merge!({"tags" => generic_tags.join(", "), "bib.tags" => tags.join(", ")})
|
37
|
+
File.write "#{Rc.p.database}/#{isbn}.yml", YAML.dump(local_data)
|
38
|
+
end
|
39
|
+
}
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def convert_bibtags(tags)
|
45
|
+
tags.map{|v|
|
46
|
+
v.gsub(/ \(programming\)/i, '')
|
47
|
+
}.sort_by {|v|
|
48
|
+
%w[fiction nonfiction].include?(v) ? -1 : tags.index(v)
|
49
|
+
}
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
data/lib/saber/task/generate.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require "isbn"
|
2
|
+
|
1
3
|
module Saber
|
2
4
|
module Task
|
3
5
|
# Generate meta data file.
|
@@ -5,34 +7,49 @@ module Saber
|
|
5
7
|
# Usage
|
6
8
|
# -----
|
7
9
|
#
|
8
|
-
# Task["generate"].invoke(:generate, ["
|
10
|
+
# Task["generate"].invoke(:generate, ["ebook", ["harry_potter", isbn], ...])
|
9
11
|
# > generate Hello.epub.yml data file.
|
10
12
|
#
|
11
13
|
class Generate < Base
|
12
14
|
include Thor::Actions
|
13
15
|
|
16
|
+
def self.source_paths
|
17
|
+
["#{Rc.p.home}/templates"]
|
18
|
+
end
|
19
|
+
|
14
20
|
source_root "#{Rc.p.root}/templates"
|
15
21
|
|
16
22
|
desc "generate", "generate"
|
17
|
-
def generate(
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
23
|
+
def generate(type, *filenames)
|
24
|
+
template_file = find_in_source_paths("#{type}.yml")
|
25
|
+
|
26
|
+
filenames.each {|filename, isbn|
|
27
|
+
isbn = ISBN.thirteen(isbn) rescue nil
|
28
|
+
Saber.ui.say "Populating {#{isbn}} #{filename} ..."
|
29
|
+
dest = "#{filename}.yml"
|
30
|
+
|
31
|
+
if isbn
|
32
|
+
require "yaml"
|
33
|
+
populate = {}
|
34
|
+
data = YAML.load_file(template_file)
|
35
|
+
data.merge! Book.populate(isbn, filename)
|
36
|
+
data.merge! YAML.load_file("#{Rc.p.database}/#{isbn}.yml") if Pa.exists?("#{Rc.p.database}/#{isbn}.yml")
|
37
|
+
|
38
|
+
# tags
|
39
|
+
if data["tags"]
|
40
|
+
Tracker.trackers.each {|name, tracker_class|
|
41
|
+
if data["#{name}.tags"].nil? and tracker_class.method_defined?(:convert_tags)
|
42
|
+
tracker = tracker_class.new(options)
|
43
|
+
data["#{name}.tags"] = tracker.convert_tags(*data["tags"].split(/, */)).join(", ")
|
44
|
+
end
|
45
|
+
}
|
46
|
+
end
|
47
|
+
|
48
|
+
create_file dest, YAML.dump(data)
|
49
|
+
else
|
50
|
+
copy_file template_file, dest
|
51
|
+
end
|
52
|
+
}
|
36
53
|
end
|
37
54
|
end
|
38
55
|
end
|