saber 0.0.7 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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