saber 0.0.7 → 1.0.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.
Files changed (76) hide show
  1. data/.gitignore +1 -0
  2. data/.travis.yml +4 -0
  3. data/CHANGELOG.md +3 -0
  4. data/Gemfile +18 -8
  5. data/Gemfile.lock +72 -33
  6. data/Guardfile +4 -0
  7. data/README.md +192 -52
  8. data/Rakefile +46 -0
  9. data/bin/1saber +5 -3
  10. data/bin/saber +4 -0
  11. data/bin/saber.bib +3 -0
  12. data/bin/saber.what +3 -0
  13. data/extconf.rb +4 -1
  14. data/lib/saber.rb +7 -13
  15. data/lib/saber/autofetcher.rb +8 -0
  16. data/lib/saber/autofetcher/client.rb +66 -0
  17. data/lib/saber/autofetcher/server.rb +78 -0
  18. data/lib/saber/cli.rb +65 -26
  19. data/lib/saber/{downloader.rb → fetcher.rb} +9 -11
  20. data/lib/saber/mechanize_ext.rb +136 -0
  21. data/lib/saber/rc.rb +3 -21
  22. data/lib/saber/task.rb +26 -11
  23. data/lib/saber/task/base.rb +18 -0
  24. data/lib/saber/task/clean.rb +18 -0
  25. data/lib/saber/task/generate.rb +38 -0
  26. data/lib/saber/task/make.rb +44 -0
  27. data/lib/saber/task/send.rb +21 -0
  28. data/lib/saber/task/upload.rb +37 -0
  29. data/lib/saber/tracker.rb +28 -0
  30. data/lib/saber/tracker/base.rb +115 -2
  31. data/lib/saber/tracker/bb.rb +244 -0
  32. data/lib/saber/tracker/bib.rb +225 -0
  33. data/lib/saber/tracker/ptp.rb +100 -0
  34. data/lib/saber/tracker/what.rb +55 -7
  35. data/lib/saber/ui.rb +65 -22
  36. data/lib/saber/version.rb +1 -1
  37. data/rutorrent/init.js +8 -9
  38. data/rutorrent/plugin.info +1 -1
  39. data/saber.gemspec +14 -10
  40. data/spec/data/_saber/.gitkeep +0 -0
  41. data/spec/saber/downloader_spec.rb +5 -2
  42. data/spec/saber/task_spec.rb +16 -0
  43. data/spec/saber/tracker/bib_spec.rb +24 -0
  44. data/spec/spec_helper.rb +25 -0
  45. data/templates/_saberrc +36 -0
  46. data/templates/bb/anime.yml +6 -0
  47. data/templates/bb/application.yml +7 -0
  48. data/templates/bb/audiobook.yml +12 -0
  49. data/templates/bb/comic.yml +7 -0
  50. data/templates/bb/documentary.yml +26 -0
  51. data/templates/bb/ebook.yml +8 -0
  52. data/templates/bb/elearning_video.yml +7 -0
  53. data/templates/bb/game_console.yml +6 -0
  54. data/templates/bb/game_pc.yml +6 -0
  55. data/templates/bb/magazine.yml +6 -0
  56. data/templates/bb/misc.yml +6 -0
  57. data/templates/bb/movie.yml +26 -0
  58. data/templates/bb/music.yml +21 -0
  59. data/templates/bb/tv.yml +6 -0
  60. data/templates/bib/application.yml +9 -0
  61. data/templates/bib/article.yml +18 -0
  62. data/templates/bib/audiobook.yml +17 -0
  63. data/templates/bib/comic.yml +22 -0
  64. data/templates/bib/ebook.yml +20 -0
  65. data/templates/bib/journal.yml +18 -0
  66. data/templates/bib/magazine.yml +18 -0
  67. data/templates/ptp/movie.yml +63 -0
  68. data/templates/ptp/movie_add.yml +35 -0
  69. data/templates/what/ebook.yml +6 -0
  70. data/templates/what/music.yml +2 -0
  71. data/templates/what/music_add.yml +2 -0
  72. metadata +182 -26
  73. data/doc/Development.md +0 -3
  74. data/lib/saber/client.rb +0 -58
  75. data/lib/saber/server.rb +0 -70
  76. data/saber.watchr +0 -23
@@ -0,0 +1,244 @@
1
+ module Saber
2
+ module Tracker
3
+ # DOESN'T WORK for mechanize does not support javascript.
4
+ class BB < Base
5
+ @@BASE_URL = "https://baconbits.org"
6
+
7
+ @@LOGIN_CHECK_PATH = "/inbox.php"
8
+
9
+ FIELDS = {
10
+ "Musics" => {
11
+ "file_input" => :file_upload,
12
+ "type" => :select_list,
13
+ "artist" => :text,
14
+ "title" => :text,
15
+ "remaster" => :check_box,
16
+ "year" => :text,
17
+ "scene" => :checkbox,
18
+ "format" => :select_list,
19
+ "bitrate" => :select_list,
20
+ "media" => :select_list,
21
+ "tags" => :text,
22
+ "image" => :text,
23
+ "album_desc" => :text,
24
+ "release_desc" => :text,
25
+ },
26
+
27
+ "Applications" => {
28
+ "file_input" => :file_upload,
29
+ "type" => :select_list,
30
+ "title" => :text,
31
+ "tags" => :text,
32
+ "desc" => :text,
33
+ "image" => :text,
34
+ "scene" => :checkbox,
35
+ },
36
+
37
+ "E-Books" => {
38
+ "file_input" => :file_upload,
39
+ "type" => :select_list,
40
+ "title" => :text,
41
+ "tags" => :text,
42
+ "isbn" => :text,
43
+ "desc" => :text,
44
+ "image" => :text,
45
+ "scene" => :checkbox,
46
+ },
47
+
48
+ "Audiobooks" => {
49
+ "file_input" => :file_upload,
50
+ "type" => :select_list,
51
+ "title" => :text,
52
+ "year" => :text,
53
+ "format" => :select_list,
54
+ "bitrate" => :select_list,
55
+ "tags" => :text,
56
+ "image" => :text,
57
+ "album_desc" => :text,
58
+ "release_desc" => :text,
59
+ },
60
+
61
+ "E-Learning Videos" => {
62
+ "type" => :select_list,
63
+ "title" => :text,
64
+ "tags" => :text,
65
+ "isbn" => :text,
66
+ "desc" => :text,
67
+ "image" => :text,
68
+ "scene" => :checkbox,
69
+ },
70
+
71
+ "Magazines" => {
72
+ "file_input" => :file_upload,
73
+ "type" => :select_list,
74
+ "title" => :text,
75
+ "tags" => :text,
76
+ "desc" => :text,
77
+ "image" => :text,
78
+ "scene" => :checkbox,
79
+ },
80
+
81
+ "Comics" => {
82
+ "file_input" => :file_upload,
83
+ "type" => :select_list,
84
+ "title" => :text,
85
+ "tags" => :text,
86
+ "isbn" => :text,
87
+ "desc" => :text,
88
+ "image" => :text,
89
+ "scene" => :checkbox,
90
+ },
91
+
92
+ "Anime" => {
93
+ "file_input" => :file_upload,
94
+ "type" => :select_list,
95
+ "title" => :text,
96
+ "tags" => :text,
97
+ "desc" => :text,
98
+ "image" => :text,
99
+ "scene" => :checkbox,
100
+ },
101
+
102
+ "Movies" => {
103
+ "file_input" => :file_upload,
104
+ "type" => :select_list,
105
+ "title" => :text,
106
+ "source" => :select_list,
107
+ "videoformat" => :select_list,
108
+ "audioformat" => :select_list,
109
+ "container" => :select_list,
110
+ "resolution" => :select_list,
111
+ "remaster_title" => :text,
112
+ "year" => :text,
113
+ "tags" => :text,
114
+ "desc" => :text,
115
+ "release_info" => :text,
116
+ "screenshot1" => :text,
117
+ "screenshot2" => :text,
118
+ "image" => :text,
119
+ "scene" => :checkbox,
120
+ },
121
+
122
+ "TV" => {
123
+ "file_input" => :file_upload,
124
+ "type" => :select_list,
125
+ "title" => :text,
126
+ "tags" => :text,
127
+ "desc" => :text,
128
+ "image" => :text,
129
+ "scene" => :checkbox,
130
+ },
131
+
132
+ "Games - PC" => {
133
+ "file_input" => :file_upload,
134
+ "type" => :select_list,
135
+ "title" => :text,
136
+ "tags" => :text,
137
+ "desc" => :text,
138
+ "image" => :text,
139
+ "scene" => :checkbox,
140
+ },
141
+
142
+ "Games - Console" => {
143
+ "file_input" => :file_upload,
144
+ "type" => :select_list,
145
+ "title" => :text,
146
+ "tags" => :text,
147
+ "desc" => :text,
148
+ "image" => :text,
149
+ "scene" => :checkbox,
150
+ },
151
+
152
+ "Documentaries" => {
153
+ "file_input" => :file_upload,
154
+ "type" => :select_list,
155
+ "title" => :text,
156
+ "source" => :select_list,
157
+ "videoformat" => :select_list,
158
+ "audioformat" => :select_list,
159
+ "container" => :select_list,
160
+ "resolution" => :select_list,
161
+ "remaster_title" => :text,
162
+ "year" => :text,
163
+ "tags" => :text,
164
+ "desc" => :text,
165
+ "release_info" => :text,
166
+ "screenshot1" => :text,
167
+ "screenshot2" => :text,
168
+ "image" => :text,
169
+ "scene" => :checkbox,
170
+ },
171
+
172
+ "Misc" => {
173
+ "file_input" => :file_upload,
174
+ "type" => :select_list,
175
+ "title" => :text,
176
+ "tags" => :text,
177
+ "desc" => :text,
178
+ "image" => :text,
179
+ "scene" => :checkbox,
180
+ },
181
+ }
182
+
183
+ # We have below attributes:
184
+ #
185
+ # * agent: a Mechanize object
186
+ # * site_name: "bib"
187
+
188
+ # Upload one torrent file to the site.
189
+ #
190
+ # @param [String] file a filename
191
+ # @param [Optimism] info comes from <file>.yml data file.
192
+ #
193
+ # @return [Boolean] result-code
194
+ def do_upload(file, info)
195
+ info["file_input"] = "#{file}.torrent"
196
+
197
+ agent.get("/upload.php") {|p|
198
+ ret = p.form_with(action: "") {|f|
199
+ FIELDS[info.type].each {|k,t|
200
+ f.set(t, k, info[k])
201
+ }
202
+ }.submit
203
+
204
+ if ret.uri.path == "/upload.php"
205
+ msg = ReverseMarkdown.parse(ret.at("//*[@id='content']/div[2]/p[2]")
206
+ Saber.ui.error "ERROR:\n#{msg}"
207
+ return false
208
+ else
209
+ return true
210
+ end
211
+ }
212
+ end
213
+
214
+ protected
215
+
216
+ # Attpened to login the site with username and password. this happens
217
+ # after login failed with cookie.
218
+ def do_login_with_username(username)
219
+ agent.get("/login.php") {|p|
220
+ ret = p.form_with(action: "login.php" ) {|f|
221
+ unless f
222
+ Saber.ui.error! p.at("//body").inner_text
223
+ end
224
+
225
+ f.username = username || ask("Username: ")
226
+ f.password = ask("Password: "){|q| q.echo = false}
227
+ f.checkbox(name: "keeplogged").check
228
+ }.submit
229
+
230
+ # error
231
+ if ret.uri.path == "/login.php"
232
+ msg = ret.at("//*[@id='loginform']/font[2]").inner_text
233
+ Saber.ui.error "Failed. You have #{msg} attempts remaining."
234
+ return false
235
+ else
236
+ return true
237
+ end
238
+ }
239
+ end
240
+ end
241
+ end
242
+ end
243
+
244
+ # vim: fdn=4
@@ -0,0 +1,225 @@
1
+ module Saber
2
+ module Tracker
3
+ class BIB < Base
4
+ @@POPULATE_TYPES = %w[ebook audiobook]
5
+
6
+ @@BASE_URL = "http://bibliotik.org"
7
+
8
+ # used by login-with-cookie to check if it's succeed.
9
+ @@LOGIN_CHECK_PATH = "/conversations"
10
+
11
+ FIELDS = {
12
+ "applications" => {
13
+ "TorrentFile" => :file_upload,
14
+ "Scene" => :checkbox,
15
+ "Title" => :text,
16
+ "Tags" => :text,
17
+ "Image" => :text,
18
+ "Description" => :text,
19
+ "Anonymous" => :checkbox,
20
+ "Notify" => :checkbox,
21
+ },
22
+
23
+ "articles" => {
24
+ "TorrentFile" => :file_upload,
25
+ "Authors" => :text,
26
+ "Title" => :text,
27
+ "Pages" => :text,
28
+ "Year" => :text,
29
+ "YearTo" => :text,
30
+ "Complete" => :checkbox,
31
+ "Format" => :text,
32
+ "Language" => :text,
33
+ "Tags" => :text,
34
+ "Image" => :text,
35
+ "Description" => :text,
36
+ "Anonymous" => :checkbox,
37
+ "Notify" => :checkbox,
38
+ },
39
+
40
+
41
+ "autobooks" => {
42
+ "TorrentFile" => :file_upload,
43
+ "Authors" => :text,
44
+ "Title" => :text,
45
+ "ISBN" => :text,
46
+ "Publishers" => :text,
47
+ "Year" => :text,
48
+ "Format" => :select_list_text,
49
+ "Language" => :select_list_text,
50
+ "Tags" => :text,
51
+ "Image" => :text,
52
+ "Description" => :text,
53
+ "Anonymous" => :checkbox,
54
+ "Notify" => :checkbox,
55
+ },
56
+
57
+ "comics" => {
58
+ "TorrentFile" => :file_upload,
59
+ "Scene" => :checkbox,
60
+ "Authors" => :text,
61
+ "Artists" => :text,
62
+ "Title" => :text,
63
+ "Publishers" => :text,
64
+ "Pages" => :text,
65
+ "Year" => :text,
66
+ "YearTo" => :text,
67
+ "Complete" => :checkbox,
68
+ "Format" => :select_list_text,
69
+ "Language" => :select_list_text,
70
+ "Tags" => :text,
71
+ "Image" => :text,
72
+ "Description" => :text,
73
+ "Anonymous" => :checkbox,
74
+ "Notify" => :checkbox,
75
+ },
76
+
77
+ "ebooks" => {
78
+ "TorrentFile" => :file_upload,
79
+ "Scene" => :checkbox,
80
+ "Authors" => :text,
81
+ "Title" => :text,
82
+ "ISBN" => :text,
83
+ "Publishers" => :text,
84
+ "Pages" => :text,
85
+ "Year" => :text,
86
+ "Format" => :select_list_text,
87
+ "Language" => :select_list_text,
88
+ "Retail" => :checkbox,
89
+ "Tags" => :text,
90
+ "Image" => :text,
91
+ "Description" => :text,
92
+ "Anonymous" => :checkbox,
93
+ "Notify" => :checkbox,
94
+ },
95
+
96
+ "journals" => {
97
+ "TorrentFile" => :file_upload,
98
+ "Scene" => :checkbox,
99
+ "Title" => :text,
100
+ "Pages" => :text,
101
+ "Year" => :text,
102
+ "YearTo" => :text,
103
+ "Complete" => :checkbox,
104
+ "Format" => :select_list_text,
105
+ "Language" => :select_list_text,
106
+ "Tags" => :text,
107
+ "Image" => :text,
108
+ "Description" => :text,
109
+ "Anonymous" => :checkbox,
110
+ "Notify" => :checkbox,
111
+ },
112
+
113
+ "magazines" => {
114
+ "TorrentFile" => :file_upload,
115
+ "Scene" => :checkbox,
116
+ "Title" => :text,
117
+ "Pages" => :text,
118
+ "Year" => :text,
119
+ "YearTo" => :text,
120
+ "Complete" => :checkbox,
121
+ "Format" => :select_list_text,
122
+ "Language" => :select_list_text,
123
+ "Tags" => :text,
124
+ "Image" => :text,
125
+ "Description" => :text,
126
+ "Anonymous" => :checkbox,
127
+ "Notify" => :checkbox,
128
+ }
129
+ }
130
+
131
+ # We have below attributes:
132
+ #
133
+ # * agent: a Mechanize object
134
+ # * site_name: "bib"
135
+
136
+ # Upload one torrent file to the site.
137
+ #
138
+ # @param [String] file a filename
139
+ # @param [Optimism] info comes from <file>.yml data file.
140
+ #
141
+ # @return [Boolean] result-code
142
+ def do_upload(file, info)
143
+ info["TorrentFile"] = "#{file}.torrent"
144
+
145
+ agent.get("/upload/#{info.type}") {|p|
146
+ ret = p.form_with(action: "") {|f|
147
+ FIELDS[info.type].each {|k,t|
148
+ f.set(t, "#{k}Field", info[k])
149
+ }
150
+ }.submit
151
+
152
+ # error if return path is "/upload/<type>"
153
+ if ret.uri.path == "/upload/#{info.type}"
154
+ msg = nil
155
+ if (err=ret.at("//*[@id='formerrorlist']"))
156
+ # convert html to markdown for pretty print.
157
+ msg = ReverseMarkdown.parse(err)
158
+ else
159
+ msg = ret.body
160
+ end
161
+ Saber.ui.error "ERROR:\n#{msg}"
162
+ return false
163
+ else
164
+ return true
165
+ end
166
+ }
167
+ end
168
+
169
+ protected
170
+
171
+ # Attpened to login the site with username and password. this happens
172
+ # after login failed with cookie.
173
+ def do_login_with_username(username)
174
+ agent.get("/login") {|p|
175
+ ret = p.form_with(action: "login" ) {|f|
176
+ # error. e.g. temporary disabled for failed logining exceed maxmium count.
177
+ unless f
178
+ # print error in red color and exit the program.
179
+ Saber.ui.error! p.at("//body").inner_text
180
+ end
181
+
182
+ f.username = username || ask("Username: ")
183
+ f.password = ask("Password: "){|q| q.echo = false}
184
+ f.checkbox(name: "keeplogged").check
185
+ }.submit
186
+
187
+ # error
188
+ if ret.uri.path == "/login"
189
+ msg = ret.at("//body/center").inner_text
190
+ Saber.ui.error "Failed. #{msg}"
191
+ return false
192
+ else
193
+ return true
194
+ end
195
+ }
196
+ end
197
+
198
+ def populate_ebook(isbn)
199
+ populate_isbn("ebooks", isbn)
200
+ end
201
+
202
+ def populate_audiobook(isbn)
203
+ populate_isbn("audiobooks", isbn)
204
+ end
205
+
206
+ def populate_isbn(type, isbn)
207
+ headers = {"X-Requested-With" => "XMLHttpRequest", "Content-Type" => "application/json; charset=utf-8", "Accept" => "application/json, text/javascript, */*"}
208
+ page = agent.get("/upload/#{type}")
209
+ authkey = page.at("//input[@name='authkey']")["value"]
210
+
211
+ params = {isbn: isbn, authkey: authkey}
212
+ ret = JSON.parse(agent.get("/isbnlookup", params, nil, headers).body)
213
+
214
+ if ret["error"]
215
+ Saber.ui.error "Populate Failed. #{ret['error']}"
216
+ {}
217
+ else
218
+ Hash[ret.map{|k, v| [(k=="publisher" ? "publishers" : k).capitalize, v]}]
219
+ end
220
+ end
221
+ end
222
+ end
223
+ end
224
+
225
+ # vim: fdn=4