rubyhexagon 0.0.6 → 0.1.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/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