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.
- 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
@@ -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
|
data/lib/saber/version.rb
CHANGED
@@ -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
|
data/saber.gemspec
CHANGED
@@ -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.
|
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
|
data/spec/saber/task_spec.rb
CHANGED
data/templates/_saberrc
CHANGED
@@ -1,9 +1,23 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
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"
|
17
|
-
announce_url = "x"
|
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:
|