rubyhexagon 0.4.0 → 0.4.1
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.
- checksums.yaml +7 -0
- data/lib/api.rb +31 -75
- data/lib/container.rb +2 -2
- data/lib/pool.rb +1 -1
- data/lib/post.rb +20 -81
- data/lib/rubyhexagon.rb +2 -3
- data/lib/search.rb +36 -28
- data/lib/set.rb +1 -1
- data/lib/standard/error.rb +1 -1
- data/lib/standard/hash.rb +1 -1
- data/lib/standard/http.rb +43 -34
- data/lib/standard/int.rb +1 -1
- data/lib/standard/string.rb +5 -1
- data/lib/standard/time.rb +2 -2
- metadata +46 -26
- data/bin/e621 +0 -27
- data/lib/config.rb +0 -46
- data/lib/examples/add.rb +0 -57
- data/lib/examples/db.rb +0 -143
- data/lib/examples/sync.rb +0 -187
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 34c8430199af7c9d7c8e2efb98cf8da90cbcdf09
|
4
|
+
data.tar.gz: 5675d205567c98595d52b5651eefe4fdd99f5dc6
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 4907ea016fa1d66489323f71cf10ed2ff9bd07a251f7462c6d7c09d8820115477ae9f5378431b583724ce81d9866fe6626db07cbc2947c94a1e05a94168e7738
|
7
|
+
data.tar.gz: 6aa265a2deb00c532ec2fcc0d7ac60a79fea98cd5b237f5c628ea1846dc91ccab034cb045dc121e3db9bb5543bd878eb4c08d7aad0e0b69f3efed6237c37237a
|
data/lib/api.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
=begin
|
2
|
-
Copyright 2014 Maxine Red <
|
2
|
+
Copyright 2014, 2015 Maxine Red <maxine@furfind.net>
|
3
3
|
|
4
4
|
This file is part of rubyhexagon.
|
5
5
|
|
@@ -20,104 +20,60 @@
|
|
20
20
|
require "standard/http"
|
21
21
|
|
22
22
|
module E621
|
23
|
-
attr_reader :user
|
24
23
|
class API
|
25
|
-
|
26
|
-
def initialize(mod=nil)
|
24
|
+
def initialize(user=nil,pass=nil)
|
27
25
|
@http = HTTP.new
|
28
|
-
|
29
|
-
|
26
|
+
login(user,pass) if !defined? @@login
|
27
|
+
end
|
28
|
+
# A wrapper function to fit into the general theme better.
|
29
|
+
def post_list(*args)
|
30
|
+
post_index(*args)
|
30
31
|
end
|
31
32
|
# Send commands to API and parse all answers, even errors.
|
32
33
|
# Also make it work with POST and GET requests.
|
33
34
|
def method_missing(method,*args)
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
# is something wrong
|
46
|
-
retry
|
47
|
-
end
|
48
|
-
#raise APIError,json["reason"] if json.include?("success") && !json["success"]
|
49
|
-
return json
|
50
|
-
else
|
51
|
-
raise NoMethodError, "undefined method #{method} for #{self.class}"
|
52
|
-
end
|
35
|
+
request = request2body(args.first)
|
36
|
+
method = method.to_s.split("_")
|
37
|
+
m = case method[0]
|
38
|
+
when "post" then
|
39
|
+
case method[1]
|
40
|
+
when "show" then :get
|
41
|
+
else :post
|
42
|
+
end
|
43
|
+
else :post
|
44
|
+
end
|
45
|
+
@http.__send__(m,"/#{method.join("/")}.json",request)
|
53
46
|
end
|
54
47
|
private
|
55
48
|
# This helper function provides the functionality of translating Ruby Hashes
|
56
49
|
# into HTTP POST body strings.
|
57
|
-
def request2body(
|
58
|
-
|
59
|
-
|
60
|
-
s += "&" unless s == String.new
|
50
|
+
def request2body(request)
|
51
|
+
query = @@login ? "#@@login&" : String.new
|
52
|
+
request = request.map do |k,v|
|
61
53
|
if v.is_a?(Hash) then
|
62
|
-
t
|
63
|
-
|
64
|
-
|
65
|
-
t += "#{k}[#{e}]=#{a}"
|
66
|
-
end
|
67
|
-
s += t
|
68
|
-
else
|
69
|
-
s += "#{k}=#{v}"
|
54
|
+
raise Argumenterror, "Hashes as request values aren't allowed."
|
55
|
+
elsif v.is_a?(Array) then
|
56
|
+
v = v.join(",")
|
70
57
|
end
|
58
|
+
"#{k}=#{v}"
|
71
59
|
end
|
72
|
-
|
73
|
-
return
|
60
|
+
query += request.join("&")
|
61
|
+
return query
|
74
62
|
end
|
75
63
|
# Perform an API and site login. This function needs to be called once
|
76
64
|
# before any actual API call can be made.
|
77
|
-
def
|
78
|
-
|
79
|
-
|
80
|
-
# Perform a re-login if the last time is older than x days. Or if there is
|
81
|
-
# no cookie.
|
82
|
-
passwd = File.expand_path(Config.paths["passwd"])
|
83
|
-
if File.exist?(passwd) then
|
84
|
-
File.open(passwd){|f|@passwd=f.read.parse}
|
65
|
+
def login(user,pass)
|
66
|
+
if user == nil && pass == nil then
|
67
|
+
@@login = nil
|
85
68
|
else
|
86
|
-
|
87
|
-
end
|
88
|
-
if (Time.now.to_i-@passwd["last_login"].to_i) < 3.days then
|
89
|
-
@@login = @passwd["login"]
|
90
|
-
else
|
91
|
-
if @passwd["name"] != "" && @passwd["pass"] != "" then
|
92
|
-
name,pass = @passwd["name"],@passwd["pass"]
|
93
|
-
else
|
94
|
-
puts "No user data found. Please provide user data."
|
95
|
-
name,pass = get_credentials
|
96
|
-
@passwd["name"],@passwd["pass"] = name,pass
|
97
|
-
# Store that data for later use.
|
98
|
-
end
|
99
|
-
request = "name=#{name}&password=#{pass}"
|
69
|
+
request = {name:name,password:pass}
|
100
70
|
body = @http.get("/user/login.json",request)
|
101
71
|
if body.has_key?("success") && (!body["success"] || body["success"] == "failed") then
|
102
72
|
raise AuthentificationError, "Username or password wrong!"
|
103
73
|
else
|
104
74
|
@@login = "login=#{body["name"]}&password_hash=#{body["password_hash"]}"
|
105
|
-
@passwd["login"] = @@login # Save login string for later use.
|
106
75
|
end
|
107
|
-
@passwd["last_login"] = Time.now.to_i
|
108
|
-
# Write everything back!
|
109
|
-
File.open(passwd,"w"){|f|f.print @passwd.to_json}
|
110
76
|
end
|
111
|
-
return @passwd["name"]
|
112
|
-
end
|
113
|
-
# If there is no data saved for login, ask the user. They must know!
|
114
|
-
def get_credentials
|
115
|
-
print "Username: "
|
116
|
-
name = $stdin.gets.chomp
|
117
|
-
print "Password: "
|
118
|
-
pass = `stty_o=$(stty -g);stty -echo;read pass;stty $stty_o; echo $pass`.chomp
|
119
|
-
puts
|
120
|
-
return [name,pass]
|
121
77
|
end
|
122
78
|
end
|
123
79
|
end
|
data/lib/container.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
=begin
|
2
|
-
Copyright 2014 Maxine Red <
|
2
|
+
Copyright 2014, 2015 Maxine Red <maxine@furfind.net>
|
3
3
|
|
4
4
|
This file is part of rubyhexagon.
|
5
5
|
|
@@ -20,7 +20,7 @@
|
|
20
20
|
module E621
|
21
21
|
class Container
|
22
22
|
def method_missing(method)
|
23
|
-
if instance_variables.include?("@#{method}".to_sym) then
|
23
|
+
if instance_variables.include?("@#{method}".to_sym) && method != :api then
|
24
24
|
return instance_variable_get("@#{method}")
|
25
25
|
else
|
26
26
|
raise NoMethodError, "undefined method #{method} for #{self.class}"
|
data/lib/pool.rb
CHANGED
data/lib/post.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
=begin
|
2
|
-
Copyright 2014 Maxine Red <
|
2
|
+
Copyright 2014, 2015 Maxine Red <maxine@furfind.net>
|
3
3
|
|
4
4
|
This file is part of rubyhexagon.
|
5
5
|
|
@@ -22,90 +22,29 @@ require "digest/md5"
|
|
22
22
|
module E621
|
23
23
|
class Post < Container
|
24
24
|
def initialize(post)
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
return body
|
36
|
-
end
|
37
|
-
|
38
|
-
def download(where)
|
39
|
-
if @file_url then
|
40
|
-
host,port = @file_url.sub(%r{^.+?//},"").sub(%r{/.+$},""),@file_url.match(/^https/) ? 443 : 80
|
25
|
+
@api = API.new
|
26
|
+
if post.is_a?(Fixnum) || (post.is_a?(String) && post.match(/^[0-9,a-f]+$/i)) then
|
27
|
+
post = if post.is_a?(String) && post.length == 32 then {md5:post}
|
28
|
+
elsif post.is_a?(Fixnum) || (post.is_a?(String) && post.match(/^\d+$/)) then
|
29
|
+
{id:post.to_i}
|
30
|
+
else
|
31
|
+
raise ArgumentError, "Neither an ID nor a MD5 Hash."
|
32
|
+
end
|
33
|
+
post = @api.post_show(post)
|
34
|
+
elsif post.is_a?(Hash) then # Variable post is ready to use. Do nothing.
|
41
35
|
else
|
42
|
-
|
43
|
-
@file_url = "/data/#{@md5[0,2]}/#{@md5[2,2]}/#@md5.#@file_ext"
|
36
|
+
raise ArgumentError, "Post only accepts an id, a MD5 hashsum or a Ruby hash."
|
44
37
|
end
|
45
|
-
|
46
|
-
if !File.exist?(where) then
|
47
|
-
body = ""
|
48
|
-
while Digest::MD5.hexdigest(body) != @md5 do
|
49
|
-
body = http.get(@file_url.sub(/^.+?\.net/,""),"")["body"]
|
50
|
-
end
|
51
|
-
File.open(where,"w") do |f|
|
52
|
-
f.print body
|
53
|
-
end
|
54
|
-
else
|
55
|
-
md5 = String.new
|
56
|
-
File.open(where,"r") do |f|
|
57
|
-
md5 = Digest::MD5.hexdigest(f.read)
|
58
|
-
end
|
59
|
-
if md5 != @md5 then
|
60
|
-
body = ""
|
61
|
-
while Digest::MD5.hexdigest(body) != @md5 do
|
62
|
-
body = http.get(@file_url.sub(/^.+?\.net/,""),"")["body"]
|
63
|
-
end
|
64
|
-
File.open(where,"w") do |f|
|
65
|
-
f.print body
|
66
|
-
end
|
67
|
-
end
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
|
-
def add_to_set(id)
|
72
|
-
api = API.new("set")
|
73
|
-
api.post("add_post",{"post_id"=>@id,"set_id"=>id})
|
74
|
-
end
|
75
|
-
|
76
|
-
def remove_from_set(id)
|
77
|
-
api = API.new("set")
|
78
|
-
api.post("remove_post",{"post_id"=>@id,"set_id"=>id})
|
79
|
-
end
|
80
|
-
|
81
|
-
def favorite
|
82
|
-
api = API.new("favorite")
|
83
|
-
api.post("create",{"id"=>@id})
|
84
|
-
end
|
85
|
-
|
86
|
-
def unfavorite
|
87
|
-
api = API.new("favorite")
|
88
|
-
api.post("destroy",{"id"=>@id})
|
89
|
-
end
|
90
|
-
|
91
|
-
def vote(dir)
|
92
|
-
dir = if dir >= 0 then 1 elsif dir < 0 then -1 end
|
93
|
-
api = API.new("post")
|
94
|
-
api.post("vote",{"id"=>@id,"score"=>dir})
|
95
|
-
end
|
96
|
-
|
97
|
-
def keys
|
98
|
-
return instance_variables.map{|i|i.to_s.sub("@","")}
|
38
|
+
set_variables(post)
|
99
39
|
end
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
40
|
+
alias show initialize
|
41
|
+
# Cast a vote! Any value above 0 votes up, every value below 0 votes down.
|
42
|
+
# Zero itself causes an error.
|
43
|
+
def vote(direction)
|
44
|
+
if direction > 0 then @api.post_vote(1)
|
45
|
+
elsif direction < 0 then @api.post_vote(-1)
|
46
|
+
else raise ArgumentError, "Zero isn't allowed for voting results."
|
107
47
|
end
|
108
|
-
return json_hash.to_json
|
109
48
|
end
|
110
49
|
end
|
111
50
|
end
|
data/lib/rubyhexagon.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
=begin
|
2
|
-
Copyright 2014 Maxine Red <
|
2
|
+
Copyright 2014, 2015 Maxine Red <maxine@furfind.net>
|
3
3
|
|
4
4
|
This file is part of rubyhexagon.
|
5
5
|
|
@@ -23,12 +23,11 @@ require "standard/error"
|
|
23
23
|
require "standard/time"
|
24
24
|
|
25
25
|
require "api"
|
26
|
-
require "config"
|
27
26
|
require "container"
|
28
27
|
require "search"
|
29
28
|
require "pool"
|
30
29
|
|
31
30
|
module E621
|
32
31
|
Name = "rubyhexagon"
|
33
|
-
Version = "0.4.
|
32
|
+
Version = "0.4.1"
|
34
33
|
end
|
data/lib/search.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
=begin
|
2
|
-
Copyright 2014 Maxine Red <
|
2
|
+
Copyright 2014, 2015 Maxine Red <maxine@furfind.net>
|
3
3
|
|
4
4
|
This file is part of rubyhexagon.
|
5
5
|
|
@@ -18,56 +18,64 @@
|
|
18
18
|
=end
|
19
19
|
|
20
20
|
require "post"
|
21
|
+
require "thread"
|
21
22
|
|
22
23
|
module E621
|
23
|
-
attr_reader :posts
|
24
24
|
class Search
|
25
25
|
# commands update/download
|
26
|
-
def initialize(query)
|
27
|
-
@api
|
28
|
-
@
|
29
|
-
@request = {"limit"=>100,"page"=>1,"tags"=>query.join("+")}
|
30
|
-
fetch
|
26
|
+
def initialize(query,page=1)
|
27
|
+
@api, @queue = API.new, SizedQueue.new(4096)
|
28
|
+
@request = {limit:100,page:page,tags:query.url_encode}
|
31
29
|
end
|
32
30
|
|
33
|
-
def
|
34
|
-
@request[
|
35
|
-
fetch
|
31
|
+
def next_page
|
32
|
+
@request[:page] += 1
|
36
33
|
end
|
37
34
|
|
35
|
+
def previous_page
|
36
|
+
@request[:page] -= 1
|
37
|
+
end
|
38
|
+
# Return each post via a block and process them individually.
|
39
|
+
# This could cause a race condition in the unlikely manner when the queue is
|
40
|
+
# empty and not being filled again, but the worker is still runnning.
|
38
41
|
def each_post
|
39
|
-
|
40
|
-
|
42
|
+
fetch_all
|
43
|
+
until !@worker.status do
|
44
|
+
until @queue.empty? do
|
45
|
+
post = @queue.pop
|
41
46
|
yield post
|
42
47
|
end
|
43
|
-
next!
|
44
48
|
end
|
45
49
|
end
|
46
50
|
|
47
|
-
def
|
48
|
-
return @request["page"]
|
49
|
-
end
|
50
|
-
|
51
|
-
def page=(page)
|
52
|
-
@request["page"]=page
|
51
|
+
def posts
|
53
52
|
fetch
|
54
53
|
end
|
55
54
|
|
56
|
-
def
|
57
|
-
@request[
|
58
|
-
fetch
|
55
|
+
def page
|
56
|
+
return @request[:page]
|
59
57
|
end
|
60
58
|
|
61
|
-
def
|
62
|
-
|
63
|
-
{"name"=>@name,"queries"=>@queries,"posts"=>posts}.to_json
|
59
|
+
def page=(page)
|
60
|
+
@request[:page] = page
|
64
61
|
end
|
62
|
+
|
65
63
|
private
|
66
64
|
def fetch
|
67
|
-
@
|
68
|
-
|
69
|
-
Post.new(post) unless post["tags"].match(@bad_tags)
|
65
|
+
@api.post_list(@request).map do |post|
|
66
|
+
Post.new(post)
|
70
67
|
end.compact
|
71
68
|
end
|
69
|
+
def fetch_all
|
70
|
+
@worker = Thread.new do
|
71
|
+
until (posts = @api.post_list(@request)) == Array.new do
|
72
|
+
posts.each do |post|
|
73
|
+
post = Post.new(post)
|
74
|
+
@queue << post if post
|
75
|
+
end
|
76
|
+
next_page
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
72
80
|
end
|
73
81
|
end
|
data/lib/set.rb
CHANGED
data/lib/standard/error.rb
CHANGED
data/lib/standard/hash.rb
CHANGED
data/lib/standard/http.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
=begin
|
2
|
-
Copyright 2014 Maxine Red <
|
2
|
+
Copyright 2014, 2015 Maxine Red <maxine@furfind.net>
|
3
3
|
|
4
4
|
This file is part of rubyhexagon.
|
5
5
|
|
@@ -25,28 +25,25 @@ module E621
|
|
25
25
|
@http = Net::HTTP.new(host,port)
|
26
26
|
@http.use_ssl = true if port == 443
|
27
27
|
end
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
message += body
|
46
|
-
mlength = (message.length/1024.0).round(1)
|
47
|
-
print "Downloaded #{" "*(clength-mlength.to_s.length)}#{mlength}/#{count}kB\r"
|
28
|
+
def method_missing(method, *args)
|
29
|
+
if [:get,:post].include?(method) then
|
30
|
+
tries,url,request = 0, *args
|
31
|
+
begin
|
32
|
+
response = case method
|
33
|
+
when :get then @http.get("#{url}?#{request}")
|
34
|
+
when :post then @http.post(url,request)
|
35
|
+
end
|
36
|
+
rescue
|
37
|
+
sleep 2**tries
|
38
|
+
tries += 1
|
39
|
+
raise if tries >= 8
|
40
|
+
retry
|
41
|
+
end
|
42
|
+
response = parse_body(response)
|
43
|
+
else
|
44
|
+
raise NoMethodError, "undefined method #{method} for #{self.class}"
|
48
45
|
end
|
49
|
-
return
|
46
|
+
return response
|
50
47
|
end
|
51
48
|
private
|
52
49
|
# As every body gets processed the same, just put it into a seperate method.
|
@@ -64,18 +61,30 @@ module E621
|
|
64
61
|
# Parse all code that returns not in JSON to actual JSON like hashes.
|
65
62
|
def errorcode(code,url)
|
66
63
|
body = {"success"=>false,"reason"=>""}
|
67
|
-
body["reason"] = if code.match(/3\d{2}/) then
|
68
|
-
|
69
|
-
elsif code.match(/
|
70
|
-
|
71
|
-
elsif code.match(/
|
72
|
-
|
73
|
-
elsif code.match(/
|
74
|
-
|
75
|
-
elsif code.match(/
|
76
|
-
|
77
|
-
elsif code.match(/
|
78
|
-
|
64
|
+
body["reason"] = if code.match(/3\d{2}/) then
|
65
|
+
"We got redirected!"
|
66
|
+
elsif code.match(/403/) then
|
67
|
+
"Access denied!"
|
68
|
+
elsif code.match(/404/) then
|
69
|
+
"File not found!"
|
70
|
+
elsif code.match(/420/) then
|
71
|
+
"Record could not be saved!"
|
72
|
+
elsif code.match(/421/) then
|
73
|
+
"User is throttled, try again later!"
|
74
|
+
elsif code.match(/422/) then
|
75
|
+
"The resource is locked!"
|
76
|
+
elsif code.match(/423/) then
|
77
|
+
"Resource already exists!"
|
78
|
+
elsif code.match(/4\d{2}/) then
|
79
|
+
"We made a bad request!"
|
80
|
+
elsif code.match(/500/) then
|
81
|
+
"Internal server error!"
|
82
|
+
elsif code.match(/503/) then
|
83
|
+
"Server has too much load!"
|
84
|
+
elsif code.match(/5\d{2}/) then
|
85
|
+
"Some unkown server side error!"
|
86
|
+
else
|
87
|
+
"HTTP response code out of range!!"
|
79
88
|
end
|
80
89
|
return body
|
81
90
|
end
|
data/lib/standard/int.rb
CHANGED
data/lib/standard/string.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
=begin
|
2
|
-
Copyright 2014 Maxine Red <
|
2
|
+
Copyright 2014, 2015 Maxine Red <maxine@furfind.net>
|
3
3
|
|
4
4
|
This file is part of rubyhexagon.
|
5
5
|
|
@@ -18,6 +18,7 @@
|
|
18
18
|
=end
|
19
19
|
|
20
20
|
require "json"
|
21
|
+
require "cgi"
|
21
22
|
|
22
23
|
class String
|
23
24
|
# Make json parsing a lot easier and less to write.
|
@@ -27,6 +28,9 @@ class String
|
|
27
28
|
def to_ascii
|
28
29
|
self.gsub("_"," ").encode("us-ascii", :invalid => :replace, :undef => :replace, :replace => "")
|
29
30
|
end
|
31
|
+
def url_encode
|
32
|
+
CGI.escape(self)
|
33
|
+
end
|
30
34
|
# Remove all tags inside of a string.
|
31
35
|
def clean
|
32
36
|
self.gsub(/<.+?>/,"")
|
data/lib/standard/time.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
=begin
|
2
|
-
Copyright 2014 Maxine Red <
|
2
|
+
Copyright 2014, 2015 Maxine Red <maxine@furfind.net>
|
3
3
|
|
4
4
|
This file is part of rubyhexagon.
|
5
5
|
|
@@ -19,7 +19,7 @@
|
|
19
19
|
class Time
|
20
20
|
# A general to_s function for Time objects.
|
21
21
|
def to_s
|
22
|
-
self.strftime("%b %e,%Y %I:%M %p")
|
22
|
+
self.strftime("%b %e,%Y %I:%M:%S %p")
|
23
23
|
end
|
24
24
|
# This methods takes a block and returns how long it took to execute that block.
|
25
25
|
def self.measure
|
metadata
CHANGED
@@ -1,64 +1,84 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rubyhexagon
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
5
|
-
prerelease:
|
4
|
+
version: 0.4.1
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Maxine Red
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date:
|
13
|
-
dependencies:
|
11
|
+
date: 2016-01-09 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: json
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.1'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.1'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: pg
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0.18'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0.18'
|
14
41
|
description: Rubyhexagon provides Ruby bindings for the e621 [dot] net API.
|
15
|
-
email:
|
16
|
-
executables:
|
17
|
-
- e621
|
42
|
+
email: maxine@furfind.net
|
43
|
+
executables: []
|
18
44
|
extensions: []
|
19
45
|
extra_rdoc_files: []
|
20
46
|
files:
|
21
|
-
- lib/
|
22
|
-
- lib/
|
23
|
-
- lib/examples/add.rb
|
24
|
-
- lib/examples/db.rb
|
47
|
+
- lib/api.rb
|
48
|
+
- lib/container.rb
|
25
49
|
- lib/pool.rb
|
26
50
|
- lib/post.rb
|
27
|
-
- lib/
|
28
|
-
- lib/
|
51
|
+
- lib/rubyhexagon.rb
|
52
|
+
- lib/search.rb
|
53
|
+
- lib/set.rb
|
29
54
|
- lib/standard/error.rb
|
30
|
-
- lib/standard/int.rb
|
31
55
|
- lib/standard/hash.rb
|
56
|
+
- lib/standard/http.rb
|
57
|
+
- lib/standard/int.rb
|
32
58
|
- lib/standard/string.rb
|
33
|
-
- lib/
|
34
|
-
- lib/container.rb
|
35
|
-
- lib/rubyhexagon.rb
|
36
|
-
- lib/api.rb
|
37
|
-
- lib/search.rb
|
38
|
-
- bin/e621
|
59
|
+
- lib/standard/time.rb
|
39
60
|
homepage: https://github.com/maxine-red/rubyhexagon
|
40
61
|
licenses:
|
41
62
|
- GPL-3.0
|
63
|
+
metadata: {}
|
42
64
|
post_install_message:
|
43
65
|
rdoc_options: []
|
44
66
|
require_paths:
|
45
67
|
- lib
|
46
68
|
required_ruby_version: !ruby/object:Gem::Requirement
|
47
|
-
none: false
|
48
69
|
requirements:
|
49
|
-
- -
|
70
|
+
- - ">="
|
50
71
|
- !ruby/object:Gem::Version
|
51
72
|
version: 1.9.2
|
52
73
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
53
|
-
none: false
|
54
74
|
requirements:
|
55
|
-
- -
|
75
|
+
- - ">="
|
56
76
|
- !ruby/object:Gem::Version
|
57
77
|
version: '0'
|
58
78
|
requirements: []
|
59
79
|
rubyforge_project:
|
60
|
-
rubygems_version:
|
80
|
+
rubygems_version: 2.2.2
|
61
81
|
signing_key:
|
62
|
-
specification_version:
|
82
|
+
specification_version: 4
|
63
83
|
summary: Rubyhexagon, Ruby bindings for e621[dot]net.
|
64
84
|
test_files: []
|
data/bin/e621
DELETED
@@ -1,27 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
=begin
|
3
|
-
Copyright 2014 Maxine Red <maxine_red1@yahoo.com>
|
4
|
-
|
5
|
-
This file is part of rubyhexahon.
|
6
|
-
|
7
|
-
rubyhexahon is free software: you can redistribute it and/or modify
|
8
|
-
it under the terms of the GNU General Public License as published by
|
9
|
-
the Free Software Foundation, either version 3 of the License, or
|
10
|
-
(at your option) any later version.
|
11
|
-
|
12
|
-
rubyhexahon is distributed in the hope that it will be useful,
|
13
|
-
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
14
|
-
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
15
|
-
GNU General Public License for more details.
|
16
|
-
|
17
|
-
You should have received a copy of the GNU General Public License
|
18
|
-
along with rubyhexahon. If not, see <http://www.gnu.org/licenses/>.
|
19
|
-
=end
|
20
|
-
|
21
|
-
$:.unshift File.dirname(__FILE__)+"/../lib"
|
22
|
-
|
23
|
-
require "rubyhexagon"
|
24
|
-
|
25
|
-
$0 = "E621 #{ARGV[0]} #{ARGV[1]}"
|
26
|
-
|
27
|
-
require "examples/#{ARGV.shift}"
|
data/lib/config.rb
DELETED
@@ -1,46 +0,0 @@
|
|
1
|
-
=begin
|
2
|
-
Copyright 2014 Maxine Red <maxine_red1@yahoo.com>
|
3
|
-
|
4
|
-
This file is part of rubyhexagon.
|
5
|
-
|
6
|
-
rubyhexagon is free software: you can redistribute it and/or modify
|
7
|
-
it under the terms of the GNU General Public License as published by
|
8
|
-
the Free Software Foundation, either version 3 of the License, or
|
9
|
-
(at your option) any later version.
|
10
|
-
|
11
|
-
rubyhexagon is distributed in the hope that it will be useful,
|
12
|
-
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
-
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14
|
-
GNU General Public License for more details.
|
15
|
-
|
16
|
-
You should have received a copy of the GNU General Public License
|
17
|
-
along with rubyhexagon. If not, see <http://www.gnu.org/licenses/>.
|
18
|
-
=end
|
19
|
-
module E621
|
20
|
-
class Config
|
21
|
-
def self.config
|
22
|
-
return @@config
|
23
|
-
end
|
24
|
-
|
25
|
-
def self.paths
|
26
|
-
return @@paths
|
27
|
-
end
|
28
|
-
|
29
|
-
def self.blacklist
|
30
|
-
return @@blacklist
|
31
|
-
end
|
32
|
-
|
33
|
-
def self.config=(config)
|
34
|
-
if File.exist?(config) then
|
35
|
-
File.open(config) do |f|
|
36
|
-
c = f.read.parse
|
37
|
-
@@paths = c.delete("paths")
|
38
|
-
@@blacklist = c.delete("blacklist")
|
39
|
-
@@config = c
|
40
|
-
end
|
41
|
-
else
|
42
|
-
raise ArgumentError, "No configuration file specified. Broken installation!"
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|
data/lib/examples/add.rb
DELETED
@@ -1,57 +0,0 @@
|
|
1
|
-
=begin
|
2
|
-
Copyright 2014 Maxine Red <maxine_red1@yahoo.com>
|
3
|
-
|
4
|
-
This file is part of rubyhexagon.
|
5
|
-
|
6
|
-
rubyhexagon is free software: you can redistribute it and/or modify
|
7
|
-
it under the terms of the GNU General Public License as published by
|
8
|
-
the Free Software Foundation, either version 3 of the License, or
|
9
|
-
(at your option) any later version.
|
10
|
-
|
11
|
-
rubyhexagon is distributed in the hope that it will be useful,
|
12
|
-
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
-
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14
|
-
GNU General Public License for more details.
|
15
|
-
|
16
|
-
You should have received a copy of the GNU General Public License
|
17
|
-
along with rubyhexagon. If not, see <http://www.gnu.org/licenses/>.
|
18
|
-
=end
|
19
|
-
|
20
|
-
require "json"
|
21
|
-
|
22
|
-
include E621
|
23
|
-
|
24
|
-
mod = ARGV.shift
|
25
|
-
|
26
|
-
$0 = "E621 #{mod}"
|
27
|
-
|
28
|
-
E621::Config.config = File.expand_path("~/.hexagon/conf.json")
|
29
|
-
Dir.chdir(File.expand_path(E621::Config.paths["home"])) do
|
30
|
-
pools, api = Array.new, API.new(mod)
|
31
|
-
File.open(File.expand_path(E621::Config.paths["j#{mod}s"])) do |f|
|
32
|
-
pools = JSON.parser.new(f.read).parse
|
33
|
-
end
|
34
|
-
puts "Old count: #{pools.length}"
|
35
|
-
candidates = ARGV.map{|x|x.to_i}.reject{|x|x==0}
|
36
|
-
puts "Adding candidates: #{candidates.length}"
|
37
|
-
new = ARGV.map{|x|x.to_i}.reject{|x|x==0||pools.include?(x)}
|
38
|
-
new.each do |id|
|
39
|
-
pool = api.post("show",{"id"=>id})
|
40
|
-
if pool["id"] && mod == "pool" then
|
41
|
-
pools << id
|
42
|
-
elsif pool["id"] && mod == "set" then
|
43
|
-
pools << {"id"=>pool["id"],"owner"=>pool["user_id"]}
|
44
|
-
end
|
45
|
-
end
|
46
|
-
puts "Adding: #{new.length}"
|
47
|
-
if mod == "pool" then
|
48
|
-
pools = pools.sort.uniq
|
49
|
-
elsif mod == "set" then
|
50
|
-
pools = pools.sort{|k1,k2|k1["id"]<=>k2["id"]}.uniq
|
51
|
-
end
|
52
|
-
puts "New count: #{pools.length}"
|
53
|
-
pools = pools.to_json
|
54
|
-
File.open(File.expand_path(E621::Config.paths["j#{mod}s"]),"w") do |f|
|
55
|
-
f.print pools
|
56
|
-
end
|
57
|
-
end
|
data/lib/examples/db.rb
DELETED
@@ -1,143 +0,0 @@
|
|
1
|
-
=begin
|
2
|
-
Copyright 2014 Maxine Red <maxine_red1@yahoo.com>
|
3
|
-
|
4
|
-
This file is part of rubyhexagon.
|
5
|
-
|
6
|
-
rubyhexagon is free software: you can redistribute it and/or modify
|
7
|
-
it under the terms of the GNU General Public License as published by
|
8
|
-
the Free Software Foundation, either version 3 of the License, or
|
9
|
-
(at your option) any later version.
|
10
|
-
|
11
|
-
rubyhexagon is distributed in the hope that it will be useful,
|
12
|
-
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
-
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14
|
-
GNU General Public License for more details.
|
15
|
-
|
16
|
-
You should have received a copy of the GNU General Public License
|
17
|
-
along with rubyhexagon. If not, see <http://www.gnu.org/licenses/>.
|
18
|
-
=end
|
19
|
-
|
20
|
-
require "logger"
|
21
|
-
require "thread"
|
22
|
-
require "pg"
|
23
|
-
|
24
|
-
include E621
|
25
|
-
|
26
|
-
$form = "%b %e, %Y %I:%M:%S %p"
|
27
|
-
|
28
|
-
require "search"
|
29
|
-
require "pool"
|
30
|
-
require "set"
|
31
|
-
|
32
|
-
Thread.abort_on_exception = true
|
33
|
-
|
34
|
-
class DB
|
35
|
-
def initialize(database)
|
36
|
-
@pg = PG.connect(dbname:database)
|
37
|
-
@mt = Mutex.new
|
38
|
-
end
|
39
|
-
def exec(query)
|
40
|
-
@mt.synchronize do
|
41
|
-
result = @pg.exec(query)
|
42
|
-
return result
|
43
|
-
end
|
44
|
-
end
|
45
|
-
def escape_string(str)
|
46
|
-
@pg.escape_string(str)
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
class Sync
|
51
|
-
def initialize
|
52
|
-
E621::Config.config = File.expand_path("~/.hexagon/conf.json")
|
53
|
-
if $stdout.tty? then
|
54
|
-
@log = Logger.new($stdout)
|
55
|
-
@log.level = Logger::DEBUG
|
56
|
-
else
|
57
|
-
@log = Logger.new(File.expand_path(E621::Config.paths["logging"]))
|
58
|
-
@log.level = Logger::INFO
|
59
|
-
end
|
60
|
-
@log.formatter = proc do |sev,dat,prog,msg|
|
61
|
-
"#{Time.now.strftime($form)} [#{sev.pad(5)}] #{msg}#$/"
|
62
|
-
end
|
63
|
-
api = API.new("user") # Used for login
|
64
|
-
@log.info("Program #$0 started.")
|
65
|
-
@uid = api.get("index",{"name"=>api.user}).first["id"]
|
66
|
-
@max_wait = 1
|
67
|
-
Dir.chdir(File.expand_path(E621::Config.paths["files"]))
|
68
|
-
@db = DB.new("danbooru")
|
69
|
-
@queue = Queue.new
|
70
|
-
@mt = Mutex.new
|
71
|
-
end
|
72
|
-
|
73
|
-
def threads
|
74
|
-
return E621::Config.threads
|
75
|
-
end
|
76
|
-
|
77
|
-
def worker(mod)
|
78
|
-
if mod == "post" then
|
79
|
-
fetch_posts
|
80
|
-
end
|
81
|
-
end
|
82
|
-
|
83
|
-
def fetch_posts
|
84
|
-
lid = @db.exec("SELECT id FROM e621.posts ORDER BY id DESC LIMIT 1;").first
|
85
|
-
if lid then
|
86
|
-
lid = lid["id"].to_i
|
87
|
-
else
|
88
|
-
lid = 0
|
89
|
-
end
|
90
|
-
posts = Search.new(["order:id", "id:#{lid}.."])
|
91
|
-
@cols = ["id","tags","artist","created_at","score","md5","file_ext","description","rating","width","height","has_children","parent_id","file_size"]
|
92
|
-
posts.each_post do |post|
|
93
|
-
@queue << [post,"#{post.md5[0,2]}/#{post.md5[2,2]}/#{post.md5}.#{post.file_ext}"]
|
94
|
-
end
|
95
|
-
end
|
96
|
-
def download
|
97
|
-
Thread.current.exit if @queue.empty?
|
98
|
-
post,path = @queue.pop
|
99
|
-
m = String.new
|
100
|
-
path.split("/")[0,2].each do |d|
|
101
|
-
m += "#{d}/"
|
102
|
-
Dir.mkdir(m) unless File.exists?(m)
|
103
|
-
end
|
104
|
-
tries = 0
|
105
|
-
begin
|
106
|
-
post.download(path)
|
107
|
-
rescue
|
108
|
-
raise if tries > 8
|
109
|
-
tries += 1
|
110
|
-
sleep 2
|
111
|
-
retry
|
112
|
-
end
|
113
|
-
data = @cols.map do |x|
|
114
|
-
y=post.__send__(x.to_sym)
|
115
|
-
y = y.to_i if x == "created_at"
|
116
|
-
y = y.join(" ") if x == "artist"
|
117
|
-
y != nil ? @db.escape_string(y.to_s) : "NULL"
|
118
|
-
end
|
119
|
-
if !@db.exec("SELECT id FROM e621.posts WHERE id = #{post.id};").first then
|
120
|
-
query = "INSERT INTO e621.posts (#{@cols.join(",")}) VALUES ('#{data.join("','")}');".gsub("'NULL'","NULL")
|
121
|
-
@db.exec(query)
|
122
|
-
@mt.synchronize do
|
123
|
-
@log.info("Added post ##{post.id.pad(6," ")} to library.")
|
124
|
-
end
|
125
|
-
end
|
126
|
-
end
|
127
|
-
end
|
128
|
-
sync = Sync.new
|
129
|
-
posts = Thread.new do
|
130
|
-
sync.worker("post")
|
131
|
-
end
|
132
|
-
sleep 4
|
133
|
-
downloads = Array.new
|
134
|
-
10.times do
|
135
|
-
downloads << Thread.new do
|
136
|
-
loop do
|
137
|
-
sync.download
|
138
|
-
end
|
139
|
-
end
|
140
|
-
end
|
141
|
-
|
142
|
-
posts.join
|
143
|
-
downloads.each{|d|d.join}
|
data/lib/examples/sync.rb
DELETED
@@ -1,187 +0,0 @@
|
|
1
|
-
=begin
|
2
|
-
Copyright 2014 Maxine Red <maxine_red1@yahoo.com>
|
3
|
-
|
4
|
-
This file is part of rubyhexagon.
|
5
|
-
|
6
|
-
rubyhexagon is free software: you can redistribute it and/or modify
|
7
|
-
it under the terms of the GNU General Public License as published by
|
8
|
-
the Free Software Foundation, either version 3 of the License, or
|
9
|
-
(at your option) any later version.
|
10
|
-
|
11
|
-
rubyhexagon is distributed in the hope that it will be useful,
|
12
|
-
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
-
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14
|
-
GNU General Public License for more details.
|
15
|
-
|
16
|
-
You should have received a copy of the GNU General Public License
|
17
|
-
along with rubyhexagon. If not, see <http://www.gnu.org/licenses/>.
|
18
|
-
=end
|
19
|
-
|
20
|
-
require "logger"
|
21
|
-
|
22
|
-
include E621
|
23
|
-
|
24
|
-
mod = ARGV.shift
|
25
|
-
|
26
|
-
$form = "%b %e, %Y %I:%M:%S %p"
|
27
|
-
|
28
|
-
require mod
|
29
|
-
|
30
|
-
class Sync
|
31
|
-
def initialize
|
32
|
-
E621::Config.config = File.expand_path("~/.hexagon/conf.json")
|
33
|
-
if $stdout.tty? then
|
34
|
-
@log = Logger.new($stdout)
|
35
|
-
@log.level = Logger::DEBUG
|
36
|
-
else
|
37
|
-
@log = Logger.new(File.expand_path(E621::Config.paths["logging"]))
|
38
|
-
@log.level = Logger::INFO
|
39
|
-
end
|
40
|
-
@log.formatter = proc do |sev,dat,prog,msg|
|
41
|
-
"#{Time.now.strftime($form)} [#{sev.pad(5)}] #{msg}#$/"
|
42
|
-
end
|
43
|
-
api = API.new("user") # Used for login
|
44
|
-
@log.info("Program #$0 started.")
|
45
|
-
@uid = api.get("index",{"name"=>api.user}).first["id"]
|
46
|
-
@max_wait = 1
|
47
|
-
end
|
48
|
-
|
49
|
-
def worker(mod)
|
50
|
-
@mod = mod
|
51
|
-
Dir.chdir(File.expand_path("~/Pictures/e621/#{mod}s")) do
|
52
|
-
sets = Array.new
|
53
|
-
File.open(File.expand_path(E621::Config.paths["j#{mod}s"])) do |f|
|
54
|
-
sets = f.read.parse
|
55
|
-
end
|
56
|
-
@set_files = File.expand_path(E621::Config.paths["#{mod}s"])
|
57
|
-
api = API.new(mod)
|
58
|
-
sets.each do |oset|
|
59
|
-
id = mod == "set" ? oset["id"] : oset
|
60
|
-
if mod == "set" then
|
61
|
-
set = Set.new(id)
|
62
|
-
elsif mod == "pool" then
|
63
|
-
set = Pool.new(id)
|
64
|
-
end
|
65
|
-
begin
|
66
|
-
set.name = set.name.gsub("_"," ")
|
67
|
-
rescue
|
68
|
-
@log.error("Error on #{mod} #{id}")
|
69
|
-
net = Net::HTTP.new("e621.net",443)
|
70
|
-
net.use_ssl = true
|
71
|
-
body = net.get("/#{mod}/show/#{id}").body
|
72
|
-
File.open("/tmp/e621.html","w"){|f|f.print body}
|
73
|
-
if body.match("ActiveRecord::RecordNotFound")
|
74
|
-
pools_f, pools = File.expand_path("~/.hexagon/#{mod}s.json"), Array.new
|
75
|
-
File.open(pools_f) do |f|
|
76
|
-
pools = f.read.parse
|
77
|
-
end
|
78
|
-
pools.delete(id)
|
79
|
-
File.open(pools_f,"w") do |f|
|
80
|
-
f.print pools.to_json
|
81
|
-
end
|
82
|
-
@log.info("Removed: #{mod} ##{id} doesn't exist anymore.")
|
83
|
-
puts "Removed: #{mod} ##{id} doesn't exist anymore."
|
84
|
-
end
|
85
|
-
next
|
86
|
-
end
|
87
|
-
@log.info("Fetching #{mod} \"#{set.name}\"")
|
88
|
-
set.name = "Love_Can_Be_Different" if set.name == "Love_can_be_different"
|
89
|
-
set.name = set.name.gsub("_"," ").encode("us-ascii", :invalid => :replace, :undef => :replace, :replace => "")
|
90
|
-
set.name = set.name.gsub(/[^0-9, ,_,a-z,\-]/i,"").sub(/\s+$/,"")
|
91
|
-
name = mod == "set" ? set.shortname : id.pad(5)
|
92
|
-
if !File.exists?(@set_files+"/#{name}.json") then
|
93
|
-
File.open(@set_files+"/#{name}.json","w"){|f|f.print "{\"downloads\":[],\"updated_at\":0}"}
|
94
|
-
end
|
95
|
-
File.open(@set_files+"/#{name}.json"){|f|@posts = f.read.parse}
|
96
|
-
@posts.store("updated_at",0) if !@posts.has_key?("updated_at")
|
97
|
-
@posts.store("downloads",@posts["posts"]) if @posts["posts"]
|
98
|
-
next if set.updated_at.to_i <= @posts["updated_at"].to_i
|
99
|
-
dname = mod == "pool" ? set.name : name
|
100
|
-
Dir.mkdir(dname) unless File.exist?(dname)
|
101
|
-
i = 0
|
102
|
-
set.each_post do |post|
|
103
|
-
i += 1
|
104
|
-
next if @posts["downloads"].include?(post.id)
|
105
|
-
download(post,dname,set,i)
|
106
|
-
end
|
107
|
-
advanced_set(oset,name,set) if mod == "set"
|
108
|
-
@posts["updated_at"] = set.updated_at.to_i
|
109
|
-
jposts = @posts.to_json
|
110
|
-
File.open(@set_files+"/#{name}.json","w"){|f|f.print jposts}
|
111
|
-
end
|
112
|
-
end
|
113
|
-
end
|
114
|
-
|
115
|
-
def advanced_set(set,name,s)
|
116
|
-
sid, owner, query = set["id"], set["owner"], set["search"]
|
117
|
-
if owner == @uid then
|
118
|
-
Search.new("fav:maxine_red #{query} order:id".split(" ")).each_post do |post|
|
119
|
-
next if @posts["downloads"].include?(post.id)
|
120
|
-
download(post,name,s)
|
121
|
-
end
|
122
|
-
api = API.new("set")
|
123
|
-
set = api.get("show", {"id"=>sid})
|
124
|
-
posts = set["posts"].map{|post|Post.new(post).id}
|
125
|
-
name = set["shortname"]
|
126
|
-
local = Dir["#{name}/*"].reject{|x|x.match(/db$/)}.map{|x|x.split(".")[1].to_i}.sort.uniq
|
127
|
-
(posts-local).each do |id|
|
128
|
-
post = Post.new({"id"=>id})
|
129
|
-
f = post.remove_from_set(sid)
|
130
|
-
if f["success"] then
|
131
|
-
s = "Removed Post #{" "*(6-post.id.to_s.length)}#{post.id} from \"#{set["name"]}\""
|
132
|
-
puts "#{Time.now.strftime($form)}: \e[1;33m#{s}\e[0m"
|
133
|
-
@log.info(s)
|
134
|
-
else
|
135
|
-
s = "#{f["reason"].to_s.gsub(/<.+?>/,"")}."
|
136
|
-
puts "#{Time.now.strftime($form)}: \e[1;31m#{s}\e[0m"
|
137
|
-
@log.info(s)
|
138
|
-
end
|
139
|
-
end
|
140
|
-
(local-posts).each do |id|
|
141
|
-
next if id == 0
|
142
|
-
post = Post.new({"id"=>id})
|
143
|
-
f = post.add_to_set(sid)
|
144
|
-
if f["success"] then
|
145
|
-
s = "Added Post #{" "*(6-post.id.to_s.length)}#{post.id} to \"#{set["name"]}\"."
|
146
|
-
puts "#{Time.now.strftime($form)}: #{s}"
|
147
|
-
@log.info(s)
|
148
|
-
else
|
149
|
-
s = "#{f["reason"].gsub(/<.+?>/,"")}. Removing local file."
|
150
|
-
puts "#{Time.now.strftime($form)}: #{s}"
|
151
|
-
@log.info(s)
|
152
|
-
File.unlink(Dir["#{set["shortname"]}/*.#{"0"*(8-post.id.to_s.length)}#{post.id}.*"].first)
|
153
|
-
end
|
154
|
-
end
|
155
|
-
end
|
156
|
-
end
|
157
|
-
def download(post,name,set,id=0)
|
158
|
-
artist = post.artist.first
|
159
|
-
if @mod == "set" then
|
160
|
-
string = [post.created_at.to_i,post.id.pad(8),artist+"_"+name,post.file_ext]
|
161
|
-
elsif @mod == "pool" then
|
162
|
-
string = [set.id.pad(5),id.pad(4),post.id.pad(8),artist,name.downcase.gsub(/\s/,"_"),post.file_ext]
|
163
|
-
end
|
164
|
-
string = string.join(".")
|
165
|
-
tries = 0
|
166
|
-
begin
|
167
|
-
post.download("#{name}/#{string}")
|
168
|
-
rescue
|
169
|
-
raise if tries > 4
|
170
|
-
tries += 1
|
171
|
-
puts "#{Time.now.strftime($form)}: #$!"
|
172
|
-
@log.info("#$!")
|
173
|
-
sleep 1
|
174
|
-
retry
|
175
|
-
end
|
176
|
-
File.utime(post.created_at,post.created_at,"#{name}/#{string}")
|
177
|
-
@posts["downloads"] << post.id
|
178
|
-
jposts = @posts.to_json
|
179
|
-
File.open(@set_files+"/#{name}.json","w"){|f|f.print jposts}
|
180
|
-
s = "Downloaded post #{" "*(6-post.id.to_s.length)}#{post.id} from \"#{set.name}\"."
|
181
|
-
puts "#{Time.now.strftime($form)}: #{s}"
|
182
|
-
sleep(rand*@max_wait)
|
183
|
-
@log.info(s)
|
184
|
-
end
|
185
|
-
end
|
186
|
-
sync = Sync.new
|
187
|
-
sync.worker(mod)
|