rubyhexagon 0.4.3 → 1.0.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.
@@ -0,0 +1,256 @@
1
+ # Copyright 2014-2018 Maxine Michalski <maxine@furfind.net>
2
+ #
3
+ # This file is part of rubyhexagon.
4
+ #
5
+ # rubyhexagon is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU General Public License as published by
7
+ # the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # rubyhexagon is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU General Public License for more details.
14
+ # You should have received a copy of the GNU General Public License
15
+ # along with rubyhexagon. If not, see <http://www.gnu.org/licenses/>.
16
+
17
+ module E621
18
+ # This class holds post information, fetched from e621, and gives access in a
19
+ # more Ruby like manner.
20
+ #
21
+ # @author Maxine Michalski
22
+ # @since 1.0.0
23
+ class Post
24
+ # @return [Integer] id of post information
25
+ attr_reader :id
26
+
27
+ # @return [User] user object of who uploaded this post
28
+ attr_reader :author
29
+
30
+ # @return [Time] creation time of post
31
+ attr_reader :created_at
32
+
33
+ # @return [Symbol] status of post, can be :active, :flagged, :pending or
34
+ # :deleted
35
+ attr_reader :status
36
+
37
+ # @return [Array<String>] array of sources. This can contain URI in string
38
+ # form
39
+ attr_reader :sources
40
+
41
+ # @return [Array<Artist>] array of artists, that work on the image in this
42
+ # post
43
+ attr_reader :artists
44
+
45
+ # @return [String] description that's associated with this post
46
+ attr_reader :description
47
+
48
+ # @return [Integer] number of people, who favorited this post
49
+ attr_reader :favorites
50
+
51
+ # @return [Integer] vote score this post holds
52
+ attr_reader :score
53
+
54
+ # @return [Symbol] rating of this post. Can be one of :safe,
55
+ # :questionable, :explicit
56
+ attr_reader :rating
57
+
58
+ # @return [Post] parent of this post
59
+ # @return [NilClass]
60
+ attr_reader :parent
61
+
62
+ # @return [Array<Post>] Array of child posts
63
+ attr_reader :children
64
+
65
+ # @return [String] MD5 checksum associated with this post
66
+ attr_reader :md5
67
+
68
+ # @return [E621::Image] file content of this post
69
+ attr_reader :image
70
+
71
+ # @return [E621::Sample] sample data in E621::Sample format
72
+ attr_reader :sample
73
+
74
+ # @return [E621::Preview] preview data in E621::Preview format
75
+ attr_reader :preview
76
+
77
+ # @author Maxine Michalski
78
+ #
79
+ # Initializer for Post.
80
+ #
81
+ # @param id [Integer] post id on e621
82
+ #
83
+ # @return the object
84
+ def initialize(id)
85
+ id = id.to_i
86
+ unless id.is_a?(Integer) && id > 0
87
+ raise InvalidIDError, "ID out of range: #{id}"
88
+ end
89
+ @id = id
90
+ end
91
+
92
+ # @author Maxine Michalski
93
+ #
94
+ # @param post [Hash] post data, if present
95
+ #
96
+ # Fetch data from e621 to current post id
97
+ def show!(post = nil)
98
+ post = API.new.fetch('post', 'show', id: @id) if post.nil?
99
+ @created_at = Time.at(post[:created_at][:s].to_i)
100
+ @status = post[:status].to_sym
101
+ setup_author(post)
102
+ setup_relatives(post)
103
+ setup_file_data(post)
104
+ setup_additional_data(post)
105
+ end
106
+
107
+ # @author Maxine Michalski
108
+ #
109
+ # @param post [Hash] post data, if present
110
+ #
111
+ # Fetch data from e621 to current post id
112
+ def show(post = nil)
113
+ post = API.new.fetch('post', 'show', id: @id) if post.nil?
114
+ tmp = Post.new(post[:id].to_i)
115
+ tmp.show!(post)
116
+ tmp
117
+ end
118
+
119
+ # @author Maxine Michalski
120
+ #
121
+ # Retrieve an Array of this post's tags
122
+ #
123
+ # @return [Array<Tag>] array of tags
124
+ def tags
125
+ API.new.fetch('post', 'tags', id: @id).map do |tag|
126
+ Tag.new(tag[:id]).show(tag)
127
+ end
128
+ end
129
+
130
+ # @author Maxine Michalski
131
+ #
132
+ # Test status with an optional parameter. This is more meant to be used by
133
+ # alias methods
134
+ #
135
+ # @return [TrueClass]
136
+ # @return [FalseClass]
137
+ def test_status(status = nil)
138
+ status ||= __callee__.to_s.sub(/\?/, '').to_sym
139
+ @status == status
140
+ end
141
+ alias active? test_status
142
+ alias flagged? test_status
143
+ alias pending? test_status
144
+ alias deleted? test_status
145
+
146
+ # @author Maxine Michalski
147
+ #
148
+ # Check a post for a certain rating. This is rather meant to be used via
149
+ # alias methids.
150
+ #
151
+ # @return [TrueClass]
152
+ # @return [FalseClass]
153
+ def test_rating(rating = nil)
154
+ rating ||= __callee__.to_s.sub(/\?/, '').to_sym
155
+ @rating == rating
156
+ end
157
+ alias safe? test_rating
158
+ alias questionable? test_rating
159
+ alias explicit? test_rating
160
+
161
+ # @author Maxine Michalski
162
+ #
163
+ # Comparison method for posts
164
+ #
165
+ # @return [TrueClass, FalseClass]
166
+ def ==(other)
167
+ other.is_a?(Post) && @id == other.id
168
+ end
169
+
170
+ private
171
+
172
+ # @author Maxine Michalski
173
+ #
174
+ # Helper function, to setup post file data
175
+ def setup_file_data(post)
176
+ @md5 = post[:md5]
177
+ @image = E621::Image.new(url: post[:file_url], ext: post[:file_ext],
178
+ width: post[:width], height: post[:height])
179
+ setup_sample(post)
180
+ setup_preview(post)
181
+ end
182
+
183
+ # @author Maxine Michalski
184
+ #
185
+ # Helper function, to setup post sample data
186
+ def setup_sample(post)
187
+ @sample = E621::Sample.new(url: post[:sample_url], ext: post[:file_ext],
188
+ width: post[:sample_width],
189
+ height: post[:sample_height])
190
+ end
191
+
192
+ # @author Maxine Michalski
193
+ #
194
+ # Helper function, to setup post preview data
195
+ def setup_preview(post)
196
+ @preview = E621::Preview.new(url: post[:preview_url], ext: 'jpg',
197
+ width: post[:preview_width],
198
+ height: post[:preview_height])
199
+ end
200
+
201
+ # @author Maxine Michalski
202
+ #
203
+ # Helper function to add additional post data
204
+ def setup_additional_data(post)
205
+ @sources = post[:source].nil? ? [] : post[:sources]
206
+ @artists = post[:artist].map { |a| Artist.new(a) }
207
+ @description = post[:description]
208
+ @favorites = post[:fav_count].to_i
209
+ @score = post[:score].to_i
210
+ @rating = case post[:rating]
211
+ when 's' then :safe
212
+ when 'q' then :questionable
213
+ when 'e' then :explicit
214
+ end
215
+ end
216
+
217
+ # @author Maxine Michalski
218
+ #
219
+ # Helper function to related posts (children, parent)
220
+ def setup_relatives(post)
221
+ @children = post[:children].split(',').map { |i| Post.new(i) }
222
+ @parent = post[:parent_id].nil? ? nil : Post.new(post[:parent_id])
223
+ end
224
+
225
+ # @author Maxine Michalski
226
+ #
227
+ # Helper function to set author of a post
228
+ def setup_author(post)
229
+ @author = User.new(id: post[:creator_id], name: post[:author])
230
+ end
231
+ end
232
+
233
+ # This class holds post information, fetched from e621, and gives access in a
234
+ # more Ruby like manner.
235
+ # This is only for deleted posts.
236
+ #
237
+ # @author Maxine Michalski
238
+ # @since 1.0.0
239
+ class DeletedPost < Post
240
+ # @return [String] deletion reason, when available
241
+ attr_reader :reason
242
+
243
+ # @author Maxine Michalski
244
+ #
245
+ # Initializer for DeletedPost.
246
+ #
247
+ # @param id [Integer] post id on e621
248
+ # @param delreason [String] reason of deletion
249
+ #
250
+ # @return the object
251
+ def initialize(id, delreason)
252
+ super(id)
253
+ @reason = delreason
254
+ end
255
+ end
256
+ end
@@ -0,0 +1,99 @@
1
+ # Copyright 2014-2018 Maxine Michalski <maxine@furfind.net>
2
+ #
3
+ # This file is part of rubyhexagon.
4
+ #
5
+ # rubyhexagon is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU General Public License as published by
7
+ # the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # rubyhexagon is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU General Public License for more details.
14
+ # You should have received a copy of the GNU General Public License
15
+ # along with rubyhexagon. If not, see <http://www.gnu.org/licenses/>.
16
+
17
+ module E621
18
+ # Module to hold search classes
19
+ #
20
+ # @author Maxine Michalski
21
+ # @since 1.0.0
22
+ module Search
23
+ # Class to hold methods for Post searches.
24
+ #
25
+ # @author Maxine Michalski
26
+ # @since 1.0.0
27
+ class Posts
28
+ # @author Maxine Michalski
29
+ #
30
+ # Retrieve a list of deleted post, with deletion reason. Only id and
31
+ # del_reason is present.
32
+ # This method accepts blocks and only returns one page without blocks
33
+ #
34
+ # @param page [Integer] page of deleted posts to return
35
+ #
36
+ # @return [Array<Post>] an array of deleted posts
37
+ def self.deleted(page = 1)
38
+ d = fetch_deleted(page)
39
+ while block_given? && d != []
40
+ d.each { |del| yield del }
41
+ d = fetch_deleted(page)
42
+ page += 1
43
+ end
44
+ d
45
+ end
46
+
47
+ # @author Maxine Michalski
48
+ #
49
+ # Retrieve a list of post data, which is filtered by arguments.
50
+ # This method requires a block to be passed to it!
51
+ #
52
+ # @param tags [String] this can be any request that can be done on e621
53
+ # too
54
+ # @param limit [Integer] number of posts to return. This has a hard limit
55
+ # of 320
56
+ # @param before_id [Integer] start post ID is lesser than this ID
57
+ #
58
+ # This method accepts blocks and only returns one page without blocks
59
+ #
60
+ # @return [Array<Post>] an array of posts
61
+ def self.list(tags, limit = 320, before_id = 2_000_000)
62
+ parameters = { tags: tags, limit: limit, before_id: before_id }
63
+ posts = fetch_posts(parameters)
64
+ while block_given? && posts != []
65
+ posts.each { |post| yield post }
66
+ posts = fetch_posts(parameters)
67
+ parameters[:before_id] = posts.last.nil? ? 0 : posts.last.id
68
+ end
69
+ posts
70
+ end
71
+
72
+ # @author Maxine Michalski
73
+ #
74
+ # Helper function for deleted posts
75
+ #
76
+ # @return [Array<Post>] array of deleted posts
77
+ def self.fetch_deleted(page)
78
+ api = API.new
79
+ api.fetch('post', 'deleted_index', page: page).map do |post|
80
+ DeletedPost.new(post[:id], post[:delreason])
81
+ end
82
+ end
83
+ private_class_method :fetch_deleted
84
+
85
+ # @author Maxine Michalski
86
+ #
87
+ # Helper function for posts
88
+ #
89
+ # @return [Array<Post>] array of posts
90
+ def self.fetch_posts(parameters)
91
+ api = API.new
92
+ api.fetch('post', 'index', parameters).map do |data|
93
+ Post.new(data[:id]).show(data)
94
+ end
95
+ end
96
+ private_class_method :fetch_deleted
97
+ end
98
+ end
99
+ end
@@ -0,0 +1,65 @@
1
+ # Copyright 2014-2018 Maxine Michalski <maxine@furfind.net>
2
+ #
3
+ # This file is part of rubyhexagon.
4
+ #
5
+ # rubyhexagon is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU General Public License as published by
7
+ # the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # rubyhexagon is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU General Public License for more details.
14
+ # You should have received a copy of the GNU General Public License
15
+ # along with rubyhexagon. If not, see <http://www.gnu.org/licenses/>.
16
+
17
+ module E621
18
+ # Module to hold search classes
19
+ #
20
+ # @author Maxine Michalski
21
+ # @since 1.0.0
22
+ module Search
23
+ # Class to hold methods for Tag searches.
24
+ #
25
+ # @author Maxine Michalski
26
+ # @since 1.0.0
27
+ class Tags
28
+ # @author Maxine Michalski
29
+ #
30
+ # Retrieve a list of post data, which is filtered by arguments.
31
+ # This method accepts a block and returns only one page without one.
32
+ #
33
+ # @param name [String] name pattern to search tags with
34
+ # @param limit [Integer] number of tags to return. This has a hard limit
35
+ # of 500
36
+ # @param after_id [Integer] only look for tags after this ID
37
+ #
38
+ # @return [Array<Tag>] array of tags
39
+ def self.list(name, limit = 500, page = 1)
40
+ params = { name_pattern: name, order: :date, limit: limit,
41
+ page: page }
42
+ t = fetch_tags(params)
43
+ while block_given? && t != []
44
+ t.each { |tag| yield tag }
45
+ t = fetch_tags(params)
46
+ params[:page] += 1
47
+ end
48
+ t
49
+ end
50
+
51
+ # @author Maxine Michalski
52
+ #
53
+ # Helper function to get Tag data
54
+ #
55
+ # @return [Array<Tag>] array of tags
56
+ def self.fetch_tags(params)
57
+ api = API.new
58
+ api.fetch('tag', 'index', params).map do |data|
59
+ Tag.new(data[:id]).show(data)
60
+ end
61
+ end
62
+ private_class_method :fetch_tags
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,89 @@
1
+ # Copyright 2014-2018 Maxine Michalski <maxine@furfind.net>
2
+ #
3
+ # This file is part of rubyhexagon.
4
+ #
5
+ # rubyhexagon is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU General Public License as published by
7
+ # the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # rubyhexagon is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU General Public License for more details.
14
+ # You should have received a copy of the GNU General Public License
15
+ # along with rubyhexagon. If not, see <http://www.gnu.org/licenses/>.
16
+
17
+ module E621
18
+ # Class to hold tag information.
19
+ #
20
+ # @author Maxine Michalski
21
+ # @since 1.0.0
22
+ class Tag
23
+ # @return [Integer] id of tag
24
+ attr_reader :id
25
+
26
+ # @return [String] name of tag
27
+ attr_reader :name
28
+
29
+ # @return [Integer] number of posts that have this tag assigned to them
30
+ attr_reader :count
31
+
32
+ # @return [Type] type of this tag
33
+ attr_reader :type
34
+
35
+ # @author Maxine Michalski
36
+ #
37
+ # Initializer for Tag.
38
+ #
39
+ # @raise InvalidIDError
40
+ #
41
+ # @param tag [Integer] tag data, fetched from e621
42
+ #
43
+ # @return the object
44
+ def initialize(id)
45
+ unless id.is_a?(Integer) && id > 0
46
+ raise InvalidIDError, "ID out of range: #{id}"
47
+ end
48
+ @id = id
49
+ end
50
+
51
+ # @author Maxine Michalski
52
+ #
53
+ # Bang method to fill tag data. If data is already available at creation,
54
+ # use the initializer!
55
+ def show!(tag = nil)
56
+ tag = API.new.fetch('tag', 'show', id: @id) if tag.nil?
57
+ @name = tag[:name]
58
+ @count = tag[:count].to_i
59
+ @type = (Type.new(tag[:type], tag[:type_locked]) unless tag[:type].nil?)
60
+ end
61
+
62
+ # @author Maxine Michalski
63
+ #
64
+ # Bang method to fill tag data. If data is already available at creation,
65
+ # use the initializer!
66
+ def show(tag = nil)
67
+ new_tag = Tag.new(@id)
68
+ new_tag.show!(tag)
69
+ new_tag
70
+ end
71
+
72
+ # @author Maxine Michalski
73
+ #
74
+ # Comparison operator for Tag, to override the default one.
75
+ # @note This method looks for same id and same name only.
76
+ # @note If there is only a an ID set with one argument, then only compare
77
+ # IDs
78
+ #
79
+ # @return [TrueClass, FalseClass]
80
+ def ==(other)
81
+ return false unless other.is_a?(Tag)
82
+ if @name.nil? || other.name.nil?
83
+ @id == other.id
84
+ else
85
+ @id == other.id && @name == other.name
86
+ end
87
+ end
88
+ end
89
+ end