rubyhexagon 0.0.6 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/bin/e621 ADDED
@@ -0,0 +1,23 @@
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
+ require "rubyhexahon"
22
+
23
+ require "examples/#{ARGV.shift}"
data/lib/rubyhexagon.rb CHANGED
@@ -30,5 +30,5 @@ require "pool"
30
30
 
31
31
  module E621
32
32
  Name = "rubyhexagon"
33
- Version = "0.0.6"
33
+ Version = "0.1.0"
34
34
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubyhexagon
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.6
4
+ version: 0.1.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -14,10 +14,7 @@ dependencies: []
14
14
  description: Rubyhexagon provides Ruby bindings for the e621 [dot] net API.
15
15
  email: maxine_red1@yahoo.com
16
16
  executables:
17
- - fav-sync
18
- - set-sync
19
- - e621_search
20
- - e621_server
17
+ - e621
21
18
  extensions: []
22
19
  extra_rdoc_files: []
23
20
  files:
@@ -36,10 +33,7 @@ files:
36
33
  - lib/config.rb
37
34
  - lib/api.rb
38
35
  - lib/set.rb
39
- - bin/fav-sync
40
- - bin/set-sync
41
- - bin/e621_search
42
- - bin/e621_server
36
+ - bin/e621
43
37
  homepage: https://github.com/maxine-red/rubyhexagon
44
38
  licenses:
45
39
  - GPL-3.0
data/bin/e621_search DELETED
@@ -1,116 +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 rubyhexagon.
6
-
7
- rubyhexagon 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
- rubyhexagon 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 rubyhexagon. If not, see <http://www.gnu.org/licenses/>.
19
- =end
20
-
21
- file = File.symlink?(__FILE__) ? File.readlink(__FILE__) : __FILE__
22
- $:.unshift(File.expand_path(File.dirname(file)+"/../lib"))
23
-
24
- require "rubyhexagon"
25
- require "readline"
26
- require "socket"
27
- require "base64"
28
-
29
- include E621
30
-
31
- E621::Config.config = File.expand_path("~/.hexagon/conf.json")
32
- tags = Array.new
33
- File.open(File.expand_path(E621::Config.paths["tags"])) do |f|
34
- tags = f.read.parse
35
- end
36
- Readline.completion_proc = proc do |s|
37
- add = s[0] if s.match(/^\-|\~/)
38
- add = s[0,2] if s.match(/^\*_/)
39
- s.sub!(/^\-|\~|(\*_)/,"")
40
- s = Regexp.escape(s)
41
- words = Array.new
42
- words += Dir["*"].reject{|d|!File.directory?(d)}.map{|d|"name:#{File.basename(d)}"}
43
- words += ["rating:s","rating:q","rating:e"]
44
- words += ["id:","md5:","description:","desc:","pool:","set:","width:",\
45
- "height:","score:","favcount:","views:","ratio:","parent:"]
46
- words += ["type:jpg","type:png","type:gif","type:swf"]
47
- bools = ["hassource","hasdescription","ischild","idparent","inpool"]
48
- words += bools.map{|b|["#{b}:true","#{b}:false"]}.flatten
49
- # Make this a one dimensional array again!
50
- words += ["order:random"]
51
- orders = ["id","score","views","set","favcount","tagcount","comments",\
52
- "mpixels","filesize","ratio","desclength"]
53
- words += orders.map{|b|["#{b}_asc","#{b}_desc"]}.flatten.map{|b|"order:#{b}"}
54
- # Here we make all orders in both directions and keep it as just an one
55
- # dimensional array.
56
- words += tags.map{|t|t["name"]}
57
- words = words.grep(/^#{s}/)
58
- words.map!{|w|"#{add}#{w}"}
59
- s = "#{add}#{s}"
60
- words
61
- end
62
- Readline.completer_word_break_characters = " "
63
- Readline.completion_append_character = " "
64
- history = File.open(File.expand_path(E621::Config.paths["history"]),"a+")
65
- history.read.split($/).each do |l|
66
- Readline::HISTORY << l
67
- end
68
-
69
- def net_send(query)
70
- socket = TCPSocket.new(E621::Config.config["server"],5621)
71
- socket.puts query.to_json
72
- res = socket.read.parse
73
- if res["error"] then
74
- $stderr.puts "Server error: #{res["message"]}"
75
- abort
76
- end
77
- socket.close
78
- return res
79
- end
80
-
81
- api = API.new("user")
82
- prompt = "#{api.user}@e621.net/posts> "
83
- Dir.chdir(File.expand_path(E621::Config.paths["posts"])) do
84
- while buff = Readline.readline(prompt.bold("yellow"), false) do
85
- next if buff == String.new
86
- if !(buff == String.new || buff == Readline::HISTORY.to_a.last) then
87
- Readline::HISTORY << buff
88
- history.puts buff
89
- end
90
- buff = buff.split(/\s+/)
91
- name = buff.shift.sub("name:","")
92
- query = {"action"=>"search","name"=>name,"query"=>buff}
93
- rid = net_send(query)["rid"]
94
- posts,page,num = Array.new,{"posts"=>[2]},1
95
- while page["posts"] != Array.new do
96
- print "Fetching page #{num.pad(3," ")} (#{posts.length.pad(6," ")} posts fetched).\r"
97
- page = net_send({"action"=>"page","page"=>num,"rid"=>rid})
98
- posts += page["posts"] if page["posts"]
99
- num += 1
100
- end
101
- puts
102
- Dir.mkdir(name) unless File.exist?(name)
103
- Dir.chdir(name) do
104
- count = 1
105
- posts.reverse.each do |post|
106
- print "Downloading post #{count.pad(6," ")} of #{posts.length.pad(6, " ")}.\r"
107
- query = {"action"=>"show", "post"=>post}
108
- res = net_send(query)
109
- File.open(res["name"],"w"){|f|f.print Base64.decode64(res["data"])}
110
- count += 1
111
- end
112
- end
113
- puts
114
- end
115
- end
116
- puts
data/bin/e621_server DELETED
@@ -1,185 +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 rubyhexagon.
6
-
7
- rubyhexagon 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
- rubyhexagon 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 rubyhexagon. If not, see <http://www.gnu.org/licenses/>.
19
- =end
20
-
21
- $:.unshift(File.expand_path(File.dirname(__FILE__)+"/../lib"))
22
-
23
- require "rubyhexagon"
24
- require "openssl"
25
- require "thread"
26
- require "logger"
27
- require "socket"
28
- require "digest"
29
- require "base64"
30
-
31
- include E621
32
-
33
- Thread.abort_on_exception = true
34
-
35
- E621::Config.config = File.expand_path("~/.hexagon/conf.json")
36
- api = API.new
37
- tasks = Hash.new
38
- mt = Mutex.new
39
- Process.daemon
40
- $0 = "e621 Proxy Server"
41
- Dir.chdir(File.expand_path("~/.hexagon")) do
42
- @log = Logger.new(File.expand_path(E621::Config.paths["logging"]))
43
- @log.formatter = proc do |sev,dat,prog,msg|
44
- "#{Time.now.strftime("%b %e, %Y %I:%M:%S %p")} [#{sev.pad(5)}] #{msg}#$/"
45
- end
46
- begin
47
- begin
48
- File.open("run"){|f|Process.kill("TERM",f.read.to_i)}
49
- rescue
50
- end
51
- sleep 2
52
- File.open("run","w"){|f|f.puts $$}
53
- server = TCPServer.new(5621)
54
- #@log = Logger.new(STDOUT)
55
- #@log.level = Logger::DEBUG
56
- queue = Queue.new
57
- 10.times do
58
- Thread.new do
59
- loop do
60
- post = queue.pop
61
- next if File.exist?("cache/#{post.md5[0,2]}/#{post.md5}")
62
- mt.synchronize do
63
- Dir.mkdir("cache") unless File.exist?("cache")
64
- Dir.mkdir("cache/#{post.md5[0,2]}") unless File.exist?("cache/#{post.md5[0,2]}")
65
- end
66
- body = post.download_data
67
- mt.synchronize do
68
- File.open("cache/#{post.md5[0,2]}/#{post.md5}","w") do |f|
69
- f.print body
70
- end
71
- end
72
- end
73
- end
74
- end
75
-
76
- @log.level = Logger::INFO
77
- @log.info("New server instance started.")
78
- Thread.new do
79
- loop do
80
- files,size,tm = Dir["cache/**/*"].reject{|x|!File.file?(x)},0,Array.new
81
- files.each do |f|
82
- size += File.size(f)
83
- end
84
- if size > 30*2**30 then
85
- files.each do |f|
86
- tm << {"file"=>f,"time"=>File.atime(f),"size"=>File.size(f)}
87
- end
88
- tm = tm.sort{|f1,f2|f1["time"]<=>f2["time"]}
89
- while size > 30*2**30 do
90
- unlink = tm.shift
91
- size -= unlink["size"]
92
- File.unlink(unlink["file"])
93
- end
94
- end
95
- sleep 3600
96
- end
97
- end
98
- Dir["searches/*"].each{|f|File.unlink(f)}
99
- loop do
100
- client = server.accept
101
- Thread.new(client) do |c|
102
- begin
103
- begin
104
- query = c.gets.parse
105
- rescue
106
- @log.error("[#{c.remote_address.ip_address}]: Error #$!.")
107
- next
108
- end
109
- case query["action"]
110
- when "search" then
111
- name,query = query["name"],query["query"]
112
- @log.info("[#{c.remote_address.ip_address}]: Search init #{name}/#{query.join("+")}.")
113
- Dir.mkdir("searches") unless File.exist?("searches")
114
- rid = Digest::SHA2.hexdigest(name+Time.now.strftime("%s"))
115
- Thread.new do
116
- s = Search.new(query)
117
- s.each_post do |post|
118
- queue << post
119
- end
120
- end
121
- File.open("searches/#{rid}.json","w") do |f|
122
- search = {"name"=>name,"query"=>query}
123
- f.print search.to_json
124
- end
125
- rid = {"rid"=>rid}.to_json
126
- c.print rid
127
- when "page" then
128
- page, rid = query["page"],query["rid"]
129
- File.open("searches/#{rid}.json"){|f|query=f.read.parse}
130
- @log.info("[#{c.remote_address.ip_address}]: Search page #{query["name"]}/#{page}.")
131
- search = Search.new(query["query"])
132
- search.page = page
133
- posts = {"posts"=>search.posts}.to_json
134
- c.print posts
135
- when "show" then
136
- post = Post.new(query["post"])
137
- body = String.new
138
- mt.synchronize do
139
- Dir.mkdir("cache") unless File.exist?("cache")
140
- Dir.mkdir("cache/#{post.md5[0,2]}") unless File.exist?("cache/#{post.md5[0,2]}")
141
- end
142
- if File.exist?("cache/#{post.md5[0,2]}/#{post.md5}") then
143
- cached = " (cached)"
144
- mt.synchronize do
145
- File.open("cache/#{post.md5[0,2]}/#{post.md5}") do |f|
146
- body = f.read
147
- end
148
- end
149
- else
150
- cached = ""
151
- body = post.download_data
152
- mt.synchronize do
153
- File.open("cache/#{post.md5[0,2]}/#{post.md5}","w") do |f|
154
- f.print body
155
- end
156
- end
157
- end
158
- @log.info("[#{c.remote_address.ip_address}]: Show post #{query["post"]["id"].pad(6," ")}#{cached}.")
159
- file = {"name"=>"#{post.id.pad(8)}.#{post.md5}.#{post.file_ext}","data"=>Base64.encode64(body)}
160
- c.print file.to_json
161
- end
162
- rescue
163
- @log.error("Error: #$!!")
164
- raise
165
- if c && !c.closed? then
166
- err = {"error"=>true,"message"=> $!.to_s}
167
- c.puts err.to_json
168
- end
169
- ensure
170
- if c && !c.closed? then
171
- c.close
172
- end
173
- end
174
- end
175
- end
176
- rescue Errno
177
- @log.error("Error: #$!!")
178
- rescue => e
179
- p e.class
180
- @log.fatal("Fatal Error: #$!!")
181
- raise
182
- ensure
183
- @log.info("Server instance terminated.")
184
- end
185
- end
data/bin/fav-sync DELETED
@@ -1,82 +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 rubyhexagon.
6
-
7
- rubyhexagon 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
- rubyhexagon 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 rubyhexagon. If not, see <http://www.gnu.org/licenses/>.
19
- =end
20
-
21
- loader = File.symlink?(__FILE__) ? File.readlink(__FILE__) : __FILE__
22
- $:.unshift(File.expand_path(File.dirname(loader))+"/../lib")
23
-
24
- require "rubyhexagon"
25
-
26
- include E621
27
-
28
- max_wait = 5
29
- E621::Config.config = File.expand_path("~/.hexagon/conf.json")
30
- api = API.new("user")
31
- uid = api.get("index",{"name"=>api.user}).first["id"]
32
- Dir.chdir(File.expand_path("~/pictures/e621/favorites"))
33
- remote = Array.new
34
- Search.new("fav:maxine_red order:id".split(" ")).each_post do |post|
35
- string = ["0"*(7-post.id.to_s.length)+post.id.to_s,post.md5,post.file_ext].join(".")
36
- remote << Array.new
37
- if !File.exist?(string) then
38
- post.download(string)
39
- else
40
- md5 = String.new
41
- File.open(string){|f|md5 = Digest::MD5.hexdigest(f.read)}
42
- next if md5 == post.md5
43
- post.download(string)
44
- end
45
- puts "Downloaded post #{" "*(7-post.id.to_s.length)}#{post.id}."
46
- sleep(rand*max_wait)
47
- end
48
- local = Dir["*"].reject{|x|x.match(/db$/)}.map{|x|x.sub(/\..+/,"").to_i}.sort.uniq
49
- (remote-local).each do |id|
50
- post = Post.new({"id"=>id})
51
- f = post.unfavorite
52
- if f["success"] then
53
- print "\e[1;33mRemoved favorite on post #{" "*(7-post.id.to_s.length)}#{post.id}.\e[0m "
54
- else
55
- print "\e[1;31m#{f["reason"].to_s.gsub(/<.+?>/,"")}.\e[0m "
56
- end
57
- f = post.vote(1)
58
- if f["success"] then
59
- puts "\e[1;33mScored post #{" "*(7-post.id.to_s.length)}#{post.id} down.\e[0m"
60
- else
61
- puts "\e[1;31m#{f["reason"].to_s.gsub(/<.+?>/,"")}.\e[0m"
62
- end
63
- sleep(rand*max_wait)
64
- end
65
- (local-remote).each do |id|
66
- next if id == 0
67
- post = Post.new({"id"=>id})
68
- f = post.favorite
69
- if f["success"] then
70
- print "\e[1;32mFavorited #{" "*(7-post.id.to_s.length)}#{post.id}.\e[0m "
71
- else
72
- print "\e[1;31m#{f["reason"].gsub(/<.+?>/,"")}.\e[0m "
73
- #File.unlink(Dir["#{set["shortname"]}/*.#{"0"*(8-post.id.to_s.length)}#{post.id}.*"].first)
74
- end
75
- f = post.vote(1)
76
- if f["success"] then
77
- puts "\e[1;32mScored post #{" "*(7-post.id.to_s.length)}#{post.id} up.\e[0m"
78
- else
79
- puts "\e[1;31m#{f["reason"].to_s.gsub(/<.+?>/,"")}.\e[0m"
80
- end
81
- sleep(rand*max_wait)
82
- end
data/bin/set-sync DELETED
@@ -1,261 +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 rubyhexagon.
6
-
7
- rubyhexagon 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
- rubyhexagon 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 rubyhexagon. If not, see <http://www.gnu.org/licenses/>.
19
- =end
20
-
21
- loader = File.symlink?(__FILE__) ? File.readlink(__FILE__) : __FILE__
22
- $:.unshift(File.expand_path(File.dirname(loader))+"/../lib")
23
-
24
- require "rubyhexagon"
25
- require "logger"
26
-
27
- include E621
28
-
29
- $0 = "E621 Set-sync"
30
- $form = "%b %e, %Y %I:%M:%S %p"
31
-
32
- def download(post,name,set)
33
- artist = post.tags.split(/\s+/).map do |t|
34
- @tags[@tags.index(t)] if @tags.index(t)
35
- end
36
- begin
37
- artist = artist.compact.first.sub("_(artist)","")
38
- rescue
39
- artist = "unknown"
40
- end
41
- string = [post.created_at.to_i,post.id.pad(8),artist+"_"+name,post.file_ext]
42
- string = string.join(".")
43
- tries = 0
44
- begin
45
- api = API.new("post")
46
- post = Post.new(api.post("show",{"id"=>post.id}))
47
- post.download("#{name}/#{string}")
48
- rescue
49
- raise if tries > 4
50
- tries += 1
51
- puts "#{Time.now.strftime($form)}: #$!"
52
- @log.info("#$!")
53
- sleep 1
54
- retry
55
- end
56
- File.utime(post.created_at,post.created_at,"#{name}/#{string}")
57
- @posts["downloads"] << post.id
58
- jposts = @posts.to_json
59
- set_files = File.expand_path("~/.hexagon/sets")
60
- File.open(set_files+"/#{name}.json","w"){|f|f.print jposts}
61
- s = "Downloaded post #{" "*(6-post.id.to_s.length)}#{post.id} from \"#{set["name"]}\"."
62
- puts "#{Time.now.strftime($form)}: #{s}"
63
- @log.info(s)
64
- end
65
- begin
66
- run,running = (File.expand_path("~/.hexagon/sets.run")),false
67
- if File.exist?(run) then
68
- running = true
69
- else
70
- File.open(run,"w"){|f|f.print $$}
71
- end
72
- max_wait = 2.5
73
- E621::Config.config = File.expand_path("~/.hexagon/conf.json")
74
- api = API.new("user")
75
- if $stdout.tty? then
76
- @log = Logger.new($stdout)
77
- @log.level = Logger::DEBUG
78
- else
79
- @log = Logger.new(File.expand_path(E621::Config.paths["logging"]))
80
- @log.level = Logger::INFO
81
- end
82
- @log.formatter = proc do |sev,dat,prog,msg|
83
- "#{Time.now.strftime("%b %e, %Y %I:%M:%S %p")} [#{sev.pad(5)}] #{msg}#$/"
84
- end
85
- @log.info("Program #$0 started.")
86
- uid = api.get("index",{"name"=>api.user}).first["id"]
87
- tags = File.expand_path("~/.hexagon/tags.json")
88
- if !File.exist?(tags) then
89
- @tags = Array.new
90
- else
91
- File.open(tags) do |f|
92
- @tags = f.read.parse
93
- end
94
- end
95
- @tags = @tags.sort{|k1,k2|k1["id"]<=>k2["id"]}
96
- net = Net::HTTP.new("e621.net",443)
97
- net.use_ssl = true
98
- body,page = [2],1
99
- until body == Array.new do
100
- body = net.get("/tag/index.json?limit=0&order=count&after_id=#{@tags.last["id"]}&page=#{page}").body.parse
101
- body = body.map{|x|x["name"] = x["name"].encode("us-ascii", :invalid => :replace, :undef => :replace, :replace => "");x}
102
- @tags += body
103
- page += 1
104
- end
105
- jtags = @tags.to_json
106
- File.open(tags,"w"){|f|f.print jtags}
107
- @tags = @tags.reject{|x|x["type"]!=1}.map{|x|x["name"]}
108
- Dir.chdir(File.expand_path("~/Dropbox/Furry/e621/sets")) do
109
- sets = Array.new
110
- File.open(File.expand_path("~/.hexagon/sets.json")) do |f|
111
- sets = f.read.parse
112
- end
113
- sets = sets.sort{|s1,s2|s1["id"]<=>s2["id"]}
114
- set_files = File.expand_path("~/.hexagon/sets")
115
- api = API.new("set")
116
- sets.each do |set|
117
- sid, owner, query = set["id"], set["owner"], set["search"]
118
- set = api.get("show", {"id"=>sid})
119
- @log.info("Fetching set #{set["name"]}")
120
- posts = set["posts"].map{|post|Post.new(post)}
121
- name = set["shortname"]
122
- if !File.exists?(set_files+"/#{name}.json") then
123
- File.open(set_files+"/#{name}.json","w"){|f|f.print "{\"downloads\":[]}"}
124
- end
125
- File.open(set_files+"/#{name}.json"){|f|@posts = f.read.parse}
126
- Dir.mkdir(name) unless File.exist?(name)
127
- posts.each do |post|
128
- next if @posts["downloads"].include?(post.id)
129
- download(post,name,set)
130
- end
131
- next if owner != uid
132
- Search.new("fav:maxine_red #{query} order:id".split(" ")).each_post do |post|
133
- next if @posts["downloads"].include?(post.id)
134
- download(post,name,set)
135
- sleep(rand*max_wait)
136
- end
137
- end
138
- sets.each do |set|
139
- sid, owner, query = set["id"], set["owner"], set["search"]
140
- next if owner != uid
141
- set = api.get("show", {"id"=>sid})
142
- posts = set["posts"].map{|post|Post.new(post).id}
143
- name = set["shortname"]
144
- local = Dir["#{name}/*"].reject{|x|x.match(/db$/)}.map{|x|x.split(".")[1].to_i}.sort.uniq
145
- (posts-local).each do |id|
146
- post = Post.new({"id"=>id})
147
- f = post.remove_from_set(sid)
148
- if f["success"] then
149
- s = "Removed Post #{" "*(6-post.id.to_s.length)}#{post.id} from \"#{set["name"]}\""
150
- puts "#{Time.now.strftime($form)}: \e[1;33m#{s}\e[0m"
151
- @log.info(s)
152
- else
153
- s = "#{f["reason"].to_s.gsub(/<.+?>/,"")}."
154
- puts "#{Time.now.strftime($form)}: \e[1;31m#{s}\e[0m"
155
- @log.info(s)
156
- end
157
- sleep(rand*max_wait)
158
- end
159
- (local-posts).each do |id|
160
- next if id == 0
161
- post = Post.new({"id"=>id})
162
- f = post.add_to_set(sid)
163
- if f["success"] then
164
- s = "Added Post #{" "*(6-post.id.to_s.length)}#{post.id} to \"#{set["name"]}\"."
165
- puts "#{Time.now.strftime($form)}: #{s}"
166
- @log.info(s)
167
- else
168
- s = "#{f["reason"].gsub(/<.+?>/,"")}. Removing local file."
169
- puts "#{Time.now.strftime($form)}: #{s}"
170
- @log.info(s)
171
- File.unlink(Dir["#{set["shortname"]}/*.#{"0"*(8-post.id.to_s.length)}#{post.id}.*"].first)
172
- end
173
- sleep(rand*max_wait)
174
- end
175
- end
176
- end
177
- Dir.chdir(File.expand_path("~/Dropbox/Furry/e621/pools")) do
178
- pools = Array.new
179
- File.open(File.expand_path("~/.hexagon/pools.json")) do |f|
180
- pools = f.read.parse.sort.uniq
181
- end
182
- pool_files = File.expand_path("~/.hexagon/pools")
183
- api = API.new("pool")
184
- pools = pools-(1..600).to_a
185
- pools.each do |id|
186
- spool = {"updated_at"=>0, "posts"=>[]}
187
- npool = api.get("show",{"id"=>id})
188
- begin
189
- pool = Pool.new(npool)
190
- @log.debug("Fetched pool \"#{pool.name.gsub("_"," ")}\"")
191
- rescue
192
- #$stderr.puts "#{pool.inspect}"
193
- puts "#{Time.now.strftime($form)}: #{id} raised an error!"
194
- @log.debug("Pool object: #{pool.inspect}")
195
- next
196
- end
197
- begin
198
- pfile = pool_files+"/#{pool.id.pad(5)}.json"
199
- rescue
200
- @log.error("Error occured: #{npool.inspect}")
201
- raise
202
- end
203
- if !File.exists?(pfile) then
204
- File.open(pfile,"w"){|f|f.print spool.to_json}
205
- spool = Pool.new(spool)
206
- else
207
- File.open(pfile){|f|spool = Pool.new(f.read.parse)}
208
- end
209
- posts = Array.new
210
- @log.debug("Skipping pool \"#{pool.name.gsub("_"," ")}\" (#{pool.id.pad(4)})")
211
- next if pool.updated_at.to_i <= spool.updated_at.to_i
212
- (pool.post_count/24.0).ceil.times do |page|
213
- posts += pool.posts.map{|post|Post.new(post)}
214
- pool = Pool.new(api.get("show",{"id"=>pool.id,"page"=>page+2}))
215
- end
216
- pool.name = "Love_Can_Be_Different" if pool.name == "Love_can_be_different"
217
- pool.name = pool.name.gsub("_"," ").encode("us-ascii", :invalid => :replace, :undef => :replace, :replace => "")
218
- name = pool.name.gsub(/[^0-9, ,_,a-z,\-]/i,"").sub(/\s+$/,"")
219
- Dir.mkdir(name) unless File.exist?(name)
220
- @log.info("Fetching pool #{pool.name}")
221
- posts.each_with_index do |post,id|
222
- id = id.succ
223
- next if spool.posts.include?(post.id)
224
- artist = post.tags.split(/\s+/).map do |t|
225
- @tags[@tags.index(t)] if @tags.index(t)
226
- end
227
- begin
228
- artist = artist.compact.first.sub("_(artist)","")
229
- rescue
230
- artist = "unknown"
231
- end
232
- string = [pool.id.pad(5),id.pad(4),post.id.pad(8),artist,name.downcase.gsub(/\s/,"_"),post.file_ext]
233
- string = string.join(".")
234
- tries = 0
235
- begin
236
- post.download("#{name}/#{string}")
237
- rescue
238
- raise if tries > 4
239
- tries += 1
240
- puts "#{Time.now.strftime($form)}: #$!"
241
- @log.info("#$!")
242
- sleep 1
243
- retry
244
- end
245
- File.utime(post.created_at,post.created_at,"#{name}/#{string}")
246
- spool.posts << post.id
247
- jposts = spool.to_json
248
- File.open(pfile,"w"){|f|f.print jposts}
249
- s = "Downloaded post #{post.id.pad(6," ")} (#{id.pad(posts.length.to_s.length," ")}/#{posts.length}) from \"#{pool.name}\"."
250
- puts "#{Time.now.strftime($form)}: #{s}"
251
- @log.info(s)
252
- sleep(rand*max_wait)
253
- end
254
- spool.updated_at = pool.updated_at
255
- jposts = spool.to_json
256
- File.open(pfile,"w"){|f|f.print jposts}
257
- end
258
- end
259
- ensure
260
- File.unlink(run) unless running
261
- end