saber 1.1.1 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (68) hide show
  1. data/.gitignore +1 -0
  2. data/CHANGELOG.md +8 -1
  3. data/Gemfile +6 -1
  4. data/Gemfile.lock +58 -14
  5. data/README.md +40 -125
  6. data/bin/saber +4 -2
  7. data/bin/saber.bb +3 -0
  8. data/bin/saber.stp +3 -0
  9. data/lib/saber.rb +5 -0
  10. data/lib/saber/autofetcher/server.rb +1 -1
  11. data/lib/saber/book.rb +36 -0
  12. data/lib/saber/cli.rb +45 -19
  13. data/lib/saber/core_ext.rb +68 -0
  14. data/lib/saber/fetcher.rb +2 -2
  15. data/lib/saber/rc.rb +6 -0
  16. data/lib/saber/task.rb +3 -0
  17. data/lib/saber/task/base.rb +6 -1
  18. data/lib/saber/task/chd.rb +10 -2
  19. data/lib/saber/task/clean.rb +2 -2
  20. data/lib/saber/task/find_uploads.rb +53 -0
  21. data/lib/saber/task/generate.rb +37 -20
  22. data/lib/saber/task/make.rb +20 -8
  23. data/lib/saber/task/send.rb +1 -1
  24. data/lib/saber/task/upload.rb +29 -19
  25. data/lib/saber/tracker.rb +8 -4
  26. data/lib/saber/tracker/base.rb +36 -15
  27. data/lib/saber/tracker/bb.rb +4 -10
  28. data/lib/saber/tracker/bib.rb +27 -11
  29. data/lib/saber/tracker/chd.rb +4 -4
  30. data/lib/saber/tracker/gazelle.rb +7 -0
  31. data/lib/saber/tracker/ptp.rb +2 -2
  32. data/lib/saber/tracker/stp.rb +53 -0
  33. data/lib/saber/tracker/what.rb +2 -2
  34. data/lib/saber/tracker2.rb +31 -0
  35. data/lib/saber/tracker2/base.rb +126 -0
  36. data/lib/saber/tracker2/bb.rb +211 -0
  37. data/lib/saber/tracker2/bib.rb +162 -0
  38. data/lib/saber/tracker2/gazelle.rb +52 -0
  39. data/lib/saber/tracker2/stp.rb +136 -0
  40. data/lib/saber/tracker2/what.rb +51 -0
  41. data/lib/saber/version.rb +1 -1
  42. data/lib/saber/watir_ext.rb +95 -0
  43. data/saber.gemspec +6 -1
  44. data/spec/saber/autofetcher/server_spec.rb +1 -1
  45. data/spec/saber/task_spec.rb +1 -1
  46. data/systemd/saber-chd@.service +12 -0
  47. data/systemd/saber-client@.service +12 -0
  48. data/systemd/saber-server@.service +12 -0
  49. data/templates/_saberrc +29 -8
  50. data/templates/article.yml +18 -0
  51. data/templates/bib/application.yml +8 -8
  52. data/templates/bib/audiobook.yml +12 -14
  53. data/templates/comic.yml +25 -0
  54. data/templates/ebook.yml +35 -0
  55. data/templates/journal.yml +19 -0
  56. data/templates/magazine.yml +41 -0
  57. data/templates/manual.yml +6 -0
  58. data/templates/newspaper.yml +6 -0
  59. metadata +109 -13
  60. data/templates/bb/comic.yml +0 -7
  61. data/templates/bb/ebook.yml +0 -8
  62. data/templates/bb/magazine.yml +0 -6
  63. data/templates/bib/article.yml +0 -18
  64. data/templates/bib/comic.yml +0 -22
  65. data/templates/bib/ebook.yml +0 -20
  66. data/templates/bib/journal.yml +0 -18
  67. data/templates/bib/magazine.yml +0 -18
  68. data/templates/what/ebook.yml +0 -6
@@ -0,0 +1,52 @@
1
+ module Saber
2
+ module Tracker2
3
+ class Gazelle < Base
4
+ def add_format(info)
5
+ unless info[:groupid]
6
+ Saber.ui.error "You must provide groupid."
7
+ return false
8
+ end
9
+
10
+ agent.goto "#{self.class::BASE_URL}/upload.php?groupid=#{info[:groupid]}"
11
+ check_login %r~/upload\.php~
12
+
13
+ form = agent.form(action: "")
14
+ fill_add_form(form, info)
15
+ form.submit() unless options["dry-run"]
16
+
17
+ if agent.url =~ %r~/upload\.php~
18
+ begin
19
+ error = agent.element(xpath: "//*[@id='content']/div[2]/p[2]").html
20
+ rescue Watir::Exception::UnknownObjectException # unable to locate element
21
+ end
22
+ error = ReverseMarkdown.parse(error) if error
23
+ Saber.ui.error "ERROR: #{error.to_s.strip}\n"
24
+ return false
25
+ else
26
+ return true
27
+ end
28
+ end
29
+
30
+ def new_upload(info)
31
+ agent.goto "#{self.class::BASE_URL}/upload.php"
32
+ check_login %r~/upload\.php~
33
+
34
+ form = agent.form(action: "")
35
+ fill_form(form, info)
36
+ form.submit() unless options["dry-run"]
37
+
38
+ if agent.url =~ %r~/upload\.php~
39
+ begin
40
+ error = agent.element(xpath: "//*[@id='content']/div[2]/p[2]").html
41
+ rescue Watir::Exception::UnknownObjectException # unable to locate element
42
+ end
43
+ error = ReverseMarkdown.parse(error) if error
44
+ Saber.ui.error "ERROR: #{error.to_s.strip}\n"
45
+ return false
46
+ else
47
+ return true
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,136 @@
1
+ module Saber
2
+ module Tracker2
3
+ class STP < Gazelle
4
+ BASE_URL = "https://stopthepress.es"
5
+
6
+ TYPES = {
7
+ "magazine" => "Magazines",
8
+ "newspaper" => "Newspapers",
9
+ "manual" => "Manuals",
10
+ "journal" => "Journals",
11
+ "ebook" => "E-Books"
12
+ }
13
+
14
+ FIELDS = {
15
+ "magazine" => {
16
+ torrent_file: "//input[@name='file_input']",
17
+ name: "//input[@name='artists[]']",
18
+ title: "//input[@name='title']",
19
+ type: "//select[@name='releasetype']",
20
+ edition: "//input[@name='remaster_title']",
21
+ scene: "//input[@name='scene']",
22
+ format: "//select[@name='format']",
23
+ source: "//select[@name='media']",
24
+ retail: "//input[@name='flac_log']",
25
+ tags: "//input[@name='tags']",
26
+ image: "//input[@name='image']",
27
+ description: "//textarea[@name='album_desc']",
28
+ release_description: "//textarea[@name='release_desc']"
29
+ },
30
+
31
+ "newspaper" => {
32
+ torrent_file: "//input[@name='file_input']",
33
+ title: "//input[@name='title']",
34
+ tags: "//input[@name='tags']",
35
+ image: "//input[@name='image']",
36
+ description: "//textarea[@name='desc']"
37
+ },
38
+
39
+ "manual" => {
40
+ torrent_file: "//input[@name='file_input']",
41
+ title: "//input[@name='title']",
42
+ tags: "//input[@name='tags']",
43
+ image: "//input[@name='image']",
44
+ description: "//textarea[@name='desc']"
45
+ },
46
+
47
+ "journal" => {
48
+ torrent_file: "//input[@name='file_input']",
49
+ title: "//input[@name='title']",
50
+ tags: "//input[@name='tags']",
51
+ image: "//input[@name='image']",
52
+ description: "//textarea[@name='desc']"
53
+ },
54
+
55
+ "ebook" => {
56
+ torrent_file: "//input[@name='file_input']",
57
+ title: "//input[@name='title']",
58
+ publisher: "//input[@name='record_label']",
59
+ isbn: "//input[@name='catalogue_number']",
60
+ year: "//input[@name='year']",
61
+ #edition: "//input[@name='remaster_title']",
62
+ #edition_year: "//input[@name='remaster_year']",
63
+ #edition_publisher: "//input[@name='remaster_record_label']",
64
+ #edition_isbn: "//input[@name='remaster_catalogue_number']",
65
+ scene: "//input[@name='scene']",
66
+ format: "//select[@name='format']",
67
+ source: "//select[@name='media']",
68
+ retail: "//input[@name='flac_log']",
69
+ tags: "//input[@name='tags']",
70
+ image: "//input[@name='image']",
71
+ description: "//textarea[@name='album_desc']",
72
+ release_description: "//textarea[@name='release_desc']"
73
+ },
74
+ }
75
+
76
+ ADD_FIELDS = {
77
+ "ebook" => {
78
+ torrent_file: "//input[@name='file_input']",
79
+ edition: "//input[@name='remaster_title']",
80
+ year: "//input[@name='remaster_year']",
81
+ publisher: "//input[@name='remaster_record_label']",
82
+ isbn: "//input[@name='remaster_catalogue_number']",
83
+ scene: "//input[@name='scene']",
84
+ format: "//select[@name='format']",
85
+ source: "//select[@name='media']",
86
+ retail: "//input[@name='flac_log']",
87
+ release_description: "//textarea[@name='release_desc']"
88
+ },
89
+ }
90
+
91
+ def fill_add_form(form, info)
92
+ # ebook: edition
93
+ if %w[ebook].include? info[:upload_type]
94
+ form.checkbox(name: "remaster").set(true)
95
+ end
96
+
97
+ ADD_FIELDS[info[:upload_type]].each {|key, selector|
98
+ form.quick_set(selector, check_value!(info[key]))
99
+ }
100
+ end
101
+
102
+ def fill_form(form, info)
103
+ form.select(name: "type").select info[:upload_type2]
104
+ form.input(name: "artists[]").wait_while_present unless info[:upload_type] == "magazine"
105
+ sleep 0.1
106
+
107
+ # magazine. edition
108
+ if %[magazine].include? info[:upload_type]
109
+ form.checkbox(name: "remaster").set(true)
110
+ end
111
+
112
+ # edition, authors
113
+ if %w[ebook].include? info[:upload_type]
114
+ #form.checkbox(name: "remaster").set(true)
115
+
116
+ (info[:authors].split(",").length - 1).times {
117
+ form.a(text: '+').click
118
+ }
119
+ end
120
+
121
+ FIELDS[info[:upload_type]].each {|key, selector|
122
+ form.quick_set(selector, info[key])
123
+ }
124
+
125
+ # authors
126
+ if %w[ebook].include? info[:upload_type]
127
+ info[:authors].split(",").each.with_index { |author, i|
128
+ form.text_fields(name: "authors[]")[i].set author
129
+ }
130
+ end
131
+ end
132
+ end
133
+ end
134
+ end
135
+
136
+ # vim: fdn=4
@@ -0,0 +1,51 @@
1
+ module Saber
2
+ module Tracker2
3
+ class What < Base
4
+ BASE_URL = "https://what.cd"
5
+
6
+ TYPES = {
7
+ "music" => "Musics",
8
+ "application" => "Applications",
9
+ "ebook" => "E-Books",
10
+ "audiobook" => "Audiobooks",
11
+ "elearning-video" => "E-Learning Videos",
12
+ "comedy" => "Comedy",
13
+ "comic" => "Comics"
14
+ }
15
+
16
+ FIELDS = {
17
+ "ebook" => {
18
+ torrent_file: "//input[@name='file_input']",
19
+ title: "//input[@name='title']",
20
+ tags: "//input[@name='tags']",
21
+ image: "//input[@name='image']",
22
+ description: "//textarea[@name='desc']"
23
+ }
24
+ }
25
+
26
+ def do_upload(file, info)
27
+ #path = info["group_id"] ? "/upload.php?group_id=#{info['group_id']}" : "/upload.php"
28
+
29
+ agent.goto "#{BASE_URL}/upload.php"
30
+ check_login %r~/upload\.php~
31
+
32
+ form = agent.form(action: "")
33
+ form.select(name: "type").select info[:type2]
34
+ form.input(value: "Find Info").wait_while_present unless info[:type] == "music"
35
+ sleep 0.1
36
+
37
+ FIELDS[info[:type]].each {|key, selector|
38
+ form.quick_set(selector, info[key])
39
+ }
40
+
41
+ form.submit()
42
+
43
+ if agent.url =~ %r~/upload\.php~
44
+ return false
45
+ else
46
+ return true
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -1,3 +1,3 @@
1
1
  module Saber
2
- VERSION = "1.1.1"
2
+ VERSION = "1.2.0"
3
3
  end
@@ -0,0 +1,95 @@
1
+ # Cookies
2
+ module Watir
3
+ class Browser
4
+ # Read cookies from Mozilla cookies.txt-style IO stream
5
+ #
6
+ # @param file [IO,String]
7
+ #
8
+ def load_cookies(file)
9
+ now = ::Time.now
10
+
11
+ io = case file
12
+ when String
13
+ open(file)
14
+ else
15
+ file
16
+ end
17
+
18
+ io.each_line do |line|
19
+ line.chomp!
20
+ line.gsub!(/#.+/, '')
21
+ fields = line.split("\t")
22
+
23
+ next if fields.length != 7
24
+
25
+ name, value, domain, for_domain, path, secure, version = fields[5], fields[6],
26
+ fields[0], (fields[1] == "TRUE"), fields[2], (fields[3] == "TRUE"), 0
27
+
28
+ expires_seconds = fields[4].to_i
29
+ expires = (expires_seconds == 0) ? nil : ::Time.at(expires_seconds)
30
+ next if expires and (expires < now)
31
+
32
+ cookies.add(name, value, domain: domain, path: path, expires: expires, secure: secure)
33
+ end
34
+
35
+ io.close if String === file
36
+
37
+ self
38
+ end
39
+
40
+ # Write cookies to Mozilla cookies.txt-style IO stream
41
+ #
42
+ # @param file [IO,String]
43
+ def dump_cookies(file)
44
+ io = case file
45
+ when String
46
+ open(file, "w")
47
+ else
48
+ file
49
+ end
50
+
51
+ cookies.to_a.each do |cookie|
52
+ io.puts([
53
+ cookie[:domain],
54
+ "FALSE", # for_domain
55
+ cookie[:path],
56
+ cookie[:secure] ? "TRUE" : "FALSE",
57
+ cookie[:expires].to_i.to_s,
58
+ cookie[:name],
59
+ cookie[:value]
60
+ ].join("\t"))
61
+ end
62
+
63
+ io.close if String === file
64
+
65
+ self
66
+ end
67
+ end
68
+ end
69
+
70
+ # Element
71
+ module Watir
72
+ class Element
73
+ # quick set value.
74
+ #
75
+ # @example
76
+ #
77
+ # form = browser.form
78
+ # form.quick_set("//input[@name='value']", "hello")
79
+ # form.quick_set("//input[@name='check']", true)
80
+ # form.quick_set("//select[@name='foo']", "Bar")
81
+ # form.quick_set("//textarea[@name='foo']", "bar")
82
+ #
83
+ def quick_set(selector, value)
84
+ elem = element(xpath: selector).to_subtype
85
+ case elem.tag_name
86
+ when "input"
87
+ elem.set value
88
+ when "select"
89
+ elem.select value
90
+ when "textarea"
91
+ elem.set value
92
+ end
93
+ end
94
+ end
95
+ end
@@ -20,7 +20,7 @@ A complete solution for PT users.
20
20
  s.add_dependency "pd", ">= 0"
21
21
  s.add_dependency "tagen", "~> 2.0.1"
22
22
  s.add_dependency "optimism", "~> 3.3.1"
23
- s.add_dependency "pa", "~> 1.3.2"
23
+ s.add_dependency "pa", "~> 1.3.3"
24
24
  s.add_dependency "retort", "~> 0.0.6"
25
25
  s.add_dependency "thor", "~> 0.16.0"
26
26
  s.add_dependency "net-ssh", "~> 2.5.2"
@@ -28,4 +28,9 @@ A complete solution for PT users.
28
28
  s.add_dependency "mechanize", "~> 2.5.1"
29
29
  s.add_dependency "highline", "~> 1.6.14"
30
30
  s.add_dependency "reverse_markdown", "~> 0.3.0"
31
+ s.add_dependency "watir", "~> 4.0.1"
32
+ s.add_dependency "faraday", "~> 0.8.4"
33
+ s.add_dependency "faraday_middleware", "~> 0.8.8"
34
+ s.add_dependency "isbn", "~> 2.0.7"
35
+ s.add_dependency "sys-filesystem", "~> 1.0.0"
31
36
  end
@@ -4,7 +4,7 @@ Server = Saber::AutoFetcher::Server
4
4
  DRbServer = Saber::AutoFetcher::DRbServer
5
5
  public_all_methods DRbServer
6
6
 
7
- describe DRbServer do
7
+ xdescribe DRbServer do
8
8
  describe "#build_files" do
9
9
  it "works" do
10
10
  s = DRbServer.new(nil)
@@ -9,7 +9,7 @@ class Task::HelloTest < Task::Base
9
9
  end
10
10
  end
11
11
 
12
- describe Task do
12
+ xdescribe Task do
13
13
  it "(complete example)" do
14
14
  expect(Task["hello_test"]).to be(Task::HelloTest)
15
15
  expect(Task["hello_test"].invoke(:hello, [1, 2])).to eq([1, 2])
@@ -0,0 +1,12 @@
1
+ [Unit]
2
+ Description=saber-chd Service
3
+ After=network.target
4
+
5
+ [Service]
6
+ Type=simple
7
+ User=%i
8
+ Environment=VAR=/var/%i
9
+ ExecStart=/usr/bin/saber chd --log ${VAR}/saber-chd.log -V
10
+
11
+ [Install]
12
+ WantedBy=multi-user.target
@@ -0,0 +1,12 @@
1
+ [Unit]
2
+ Description=saber-client Service
3
+ After=network.target
4
+
5
+ [Service]
6
+ Type=simple
7
+ User=%i
8
+ Environment=VAR=/var/%i
9
+ ExecStart=/usr/bin/saber client --log ${VAR}/saber-client.log -V
10
+
11
+ [Install]
12
+ WantedBy=multi-user.target
@@ -0,0 +1,12 @@
1
+ [Unit]
2
+ Description=saber-server Service
3
+ After=network.target
4
+
5
+ [Service]
6
+ Type=simple
7
+ User=%i
8
+ Environment=VAR=/var/%i
9
+ ExecStart=/usr/bin/saber server --log ${VAR}/saber-server.log -V
10
+
11
+ [Install]
12
+ WantedBy=multi-user.target
@@ -1,9 +1,23 @@
1
- p:
2
- #watch = Pa("~/bt/watch") # OPTIONAL local watch directory. [saber-make]
3
- remote_watch = Pa("bt/watch") # OPTIONAL remote watch directory. [saber-make]
4
- fetcher_download = Pa("~/download") # aria2 download directory. [saber-fetch]
5
- remote_download = Pa("~/bt") # remote bt download directory. [saber-fetch]
6
- download = Pa("~/bt") # local bt download directory. [saber-clean]
1
+ #browser = [:firefox, {profile: "jobs"}]
2
+
3
+ make:
4
+ #dir = Pa(".") # move to directory.
5
+ #watch = Pa("~/bt/watch") # copy to local watch directory.
6
+ #remote_watch = Pa("bt/watch") # ssh copy to remote watch directory.
7
+
8
+ find_uploads:
9
+ #dir = Pa("~/bt/watch")
10
+
11
+ upload:
12
+ #move_yml = Pa("done")
13
+ #move_torrent = Pa("done")
14
+
15
+ fetch:
16
+ dir = Pa("~/downloads") # aria2 download directory.
17
+ remote_dir = Pa("~/bt") # remote bt download directory.
18
+
19
+ clean:
20
+ dir = Pa("~/bt") # local bt download directory.
7
21
 
8
22
  server:
9
23
  user = "x" # seedbox login name
@@ -13,8 +27,15 @@ server:
13
27
  username = "foo" # default username for login into site.
14
28
 
15
29
  bib:
16
- username = "bar" # OPTIONAL per-site username. use default username if not set.
17
- announce_url = "x" # [saber-make, saber-upload]
30
+ #username = "bar" # per-site username. use default username if not set.
31
+ announce_url = "x"
32
+
33
+ chd:
34
+ passkey = "x"
35
+ dir = Pa("~/bt/watch")
36
+ update_interval = 15*60
37
+ diskspace_dir = Pa("/")
38
+ diskspace_limit = 20.gigabytes
18
39
 
19
40
  # [saber-fetch]
20
41
  server: