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 +23 -0
- data/lib/rubyhexagon.rb +1 -1
- metadata +3 -9
- data/bin/e621_search +0 -116
- data/bin/e621_server +0 -185
- data/bin/fav-sync +0 -82
- data/bin/set-sync +0 -261
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
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
|
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
|
-
-
|
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/
|
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
|