saber 1.1.1 → 1.2.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 (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: