pixiv 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -2,6 +2,14 @@
2
2
 
3
3
  A client library for [pixiv](http://www.pixiv.net/)
4
4
 
5
+ [![Build Status](https://secure.travis-ci.org/uasi/pixiv.png?branch=master)][travis]
6
+ [![Dependency Status](https://gemnasium.com/uasi/pixiv.png?travis)][gemnasium]
7
+ [![Code Climate](https://codeclimate.com/badge.png)][codeclimate]
8
+
9
+ [travis]: http://travis-ci.org/uasi/pixiv
10
+ [gemnasium]: https://gemnasium.com/uasi/pixiv
11
+ [codeclimate]: https://codeclimate.com/github/uasi/pixiv
12
+
5
13
  ## Important Note
6
14
 
7
15
  The pixiv Guidelines [[en][Guidelines.en], [ja][Guidelines.ja]] prohibit to
@@ -16,23 +16,45 @@ def init
16
16
  require 'bundler/setup'
17
17
  Bundler.require
18
18
 
19
- $pixiv = Pixiv.new(id, password) do |agent|
19
+ $pixiv = Pixiv.client(id, password) do |agent|
20
20
  agent.user_agent_alias = 'Mac Safari'
21
21
  agent.set_proxy(*proxy) if proxy
22
22
  end
23
23
 
24
24
  Kernel.const_set(:P, $pixiv)
25
25
  Kernel.const_set(:M, $pixiv.member)
26
+ Kernel.const_set(:WL, $pixiv.work_list)
27
+ Kernel.const_set(:BL, $pixiv.bookmark_list)
28
+ Kernel.const_set(:PBL, $pixiv.private_bookmark_list)
29
+ Kernel.const_set(:Ws, $pixiv.works)
30
+ Kernel.const_set(:Bs, $pixiv.bookmarks)
31
+ Kernel.const_set(:PBs, $pixiv.private_bookmarks)
32
+ end
33
+
34
+ def M(id)
35
+ $pixiv.member(id)
26
36
  end
27
37
 
28
38
  def I(id)
29
39
  $pixiv.illust(id)
30
40
  end
31
41
 
32
- def M(id)
33
- $pixiv.member(id)
42
+ def WL(member, p = 1)
43
+ $pixiv.work_list(member, p)
44
+ end
45
+
46
+ def BL(member, p = 1)
47
+ $pixiv.bookmark_list(member, p)
48
+ end
49
+
50
+ def PBL(p = 1)
51
+ $pixiv.private_bookmark_list(p)
52
+ end
53
+
54
+ def Ws(member)
55
+ $pixiv.works(member)
34
56
  end
35
57
 
36
- def BL(member_id, p = 1)
37
- $pixiv.bookmark_list(member_id, p)
58
+ def Bs(member)
59
+ $pixiv.bookmarks(member)
38
60
  end
@@ -1,17 +1,29 @@
1
1
  require 'mechanize'
2
- require 'pixiv/error'
3
- require 'pixiv/client'
4
- require 'pixiv/page'
5
- require 'pixiv/illust'
6
- require 'pixiv/member'
7
- require 'pixiv/page_collection'
8
- require 'pixiv/bookmark_list'
9
2
 
10
3
  module Pixiv
4
+ autoload :BookmarkList, 'pixiv/bookmark_list'
5
+ autoload :Client, 'pixiv/client'
6
+ autoload :Error, 'pixiv/error'
7
+ autoload :Illust, 'pixiv/illust'
8
+ autoload :IllustList, 'pixiv/illust_list'
9
+ autoload :Member, 'pixiv/member'
10
+ autoload :OwnedIllustList, 'pixiv/owned_illust_list'
11
+ autoload :Page, 'pixiv/page'
12
+ autoload :PageCollection, 'pixiv/page_collection'
13
+ autoload :PrivateBookmarkList, 'pixiv/bookmark_list'
14
+ autoload :WorkList, 'pixiv/work_list'
15
+
11
16
  ROOT_URL = 'http://www.pixiv.net'
12
17
 
18
+ # @deprecated Use {.client} instead. Will be removed in 0.1.0.
13
19
  # Delegates to {Pixiv::Client#initialize}
14
20
  def self.new(*args, &block)
15
21
  Pixiv::Client.new(*args, &block)
16
22
  end
23
+
24
+ # See {Pixiv::Client#initialize}
25
+ # @return [Pixiv::Client]
26
+ def self.client(*args, &block)
27
+ Pixiv::Client.new(*args, &block)
28
+ end
17
29
  end
@@ -1,50 +1,28 @@
1
1
  module Pixiv
2
- class BookmarkList < Page
3
- include PageCollection
4
-
5
- # Returns the URL for given +member_id+ and +page_num+
6
- # @param [Integer] member_id
7
- # @param [Integer] page_num
8
- # @return [String]
9
- def self.url(member_id, page_num = 1)
10
- "#{ROOT_URL}/bookmark.php?id=#{member_id}&rest=show&p=#{page_num}"
2
+ class BookmarkList < OwnedIllustList
3
+ # (see super.url)
4
+ def self.url(member_id, page = 1)
5
+ "#{ROOT_URL}/bookmark.php?id=#{member_id}&rest=show&p=#{page}"
11
6
  end
12
7
 
13
8
  # @return [Integer]
14
- lazy_attr_reader(:bookmarks_count) { at!('a[href="/bookmark.php?type=illust_all"]').inner_text.match(/(\d+)/).to_a[1].to_i }
15
- # @return [Integer]
16
- lazy_attr_reader(:page_num) { at!('li.pages-current').inner_text.to_i }
17
- # @return [Boolean]
18
- lazy_attr_reader(:last?) { at!('li.pages-current').next_element.inner_text.to_i == 0 }
19
- # @return [Integer]
20
- lazy_attr_reader(:member_id) { doc.body.match(/pixiv\.context\.userId = '(\d+)'/).to_a[1].to_i }
21
- # @return [Array<Integer>]
22
- lazy_attr_reader(:illust_ids) { search!('li[id^="li_"] a[href^="member_illust.php?mode=medium"]').map {|n| n['href'].match(/illust_id=(\d+)$/).to_a[1].to_i } }
9
+ lazy_attr_reader(:total_count) {
10
+ node = at!('a[href="/bookmark.php?type=illust_all"]')
11
+ node.inner_text.match(/\d+/).to_s.to_i
12
+ }
23
13
  # @return [Array<Hash{Symbol=>Object}, nil>]
24
- lazy_attr_reader(:illust_hashes) {
25
- search!('li[id^="li_"]').map {|node| illust_hash_from_bookmark_item(node) }
14
+ lazy_attr_reader(:page_hashes) {
15
+ search!('li[id^="li_"]').map {|n| hash_from_list_item(n) }
26
16
  }
27
17
 
28
- alias page_hashes illust_hashes
29
-
30
- # @return [String]
31
- def url; self.class.url(member_id, page_num) end
32
- # @return [Boolean]
33
- def first?; page_num == 1 end
34
- # @return [String]
35
- def next_url; last? ? nil : self.class.url(member_id, page_num + 1) end
36
- # @return [String]
37
- def prev_url; first? ? nil : self.class.url(member_id, page_num - 1) end
38
- # @return [Class<Pixiv::Page>]
39
- def page_class; Illust end
40
- # @return [Array<String>]
41
- def page_urls; illust_ids.map {|illust_id| Illust.url(illust_id) } end
18
+ # @deprecated Use {#total_count} instead.
19
+ alias bookmarks_count total_count
42
20
 
43
21
  private
44
22
 
45
- # @param [Nokogiri::HTML::Node] node
23
+ # @param [Nokogiri::XML::Node] node
46
24
  # @return [Hash{Symbol=>Object}] illust_hash
47
- def illust_hash_from_bookmark_item(node)
25
+ def hash_from_list_item(node)
48
26
  return nil if node.at('img[src*="limit_unknown_s.png"]')
49
27
  member_node = node.at('a[href^="member_illust.php?id="]')
50
28
  illust_node = node.at('a')
@@ -59,4 +37,11 @@ module Pixiv
59
37
  }
60
38
  end
61
39
  end
40
+
41
+ class PrivateBookmarkList < BookmarkList
42
+ # (see super.url)
43
+ def self.url(member_id, page = 1)
44
+ "#{ROOT_URL}/bookmark.php?id=#{member_id}&rest=hide&p=#{page}"
45
+ end
46
+ end
62
47
  end
@@ -52,6 +52,14 @@ module Pixiv
52
52
  @member_id = member_id_from_mypage(doc)
53
53
  end
54
54
 
55
+ # @param [Integer] member_id
56
+ # @return [Pixiv::Member] member bound to +self+
57
+ def member(member_id = member_id)
58
+ attrs = {member_id: member_id}
59
+ member = Member.lazy_new(attrs) { agent.get(Member.url(member_id)) }
60
+ member.bind(self)
61
+ end
62
+
55
63
  # @param [Integer] illust_id
56
64
  # @return [Pixiv::Illust] illust bound to +self+
57
65
  def illust(illust_id)
@@ -60,37 +68,60 @@ module Pixiv
60
68
  illust.bind(self)
61
69
  end
62
70
 
63
- # @param [Integer] member_id
64
- # @return [Pixiv::Member] member bound to +self+
65
- def member(member_id = member_id)
66
- attrs = {member_id: member_id}
67
- member = Member.lazy_new(attrs) { agent.get(Member.url(member_id)) }
68
- member.bind(self)
71
+ # @param [Pixiv::Member, Integer] member_or_id
72
+ # @param [Integer] page
73
+ # @return [Pixiv::WorkList] work list bound to +self+
74
+ def work_list(member_or_id = member_id, page = 1)
75
+ illust_list_with_class(WorkList, member_or_id, page)
76
+ end
77
+
78
+ # @param [Pixiv::Member, Integer] member_or_id
79
+ # @param [Integer] page
80
+ # @return [Pixiv::BookmarkList] bookmark list bound to +self+
81
+ def bookmark_list(member_or_id = member_id, page = 1)
82
+ illust_list_with_class(BookmarkList, member_or_id, page)
69
83
  end
70
84
 
71
- # @param [Pixiv::Member, Integer] member_or_member_id
85
+ # @param [Pixiv::Member, Integer] member_or_id
72
86
  # @param [Integer] page_num
73
- def bookmark_list(member_or_member_id = member_id, page_num = 1)
74
- x = member_or_member_id
75
- member_id = x.is_a?(Member) ? x.member_id : x
76
- attrs = {member_id: member_id, page_num: page_num}
77
- BookmarkList.lazy_new(attrs) { agent.get(BookmarkList.url(member_id, page_num)) }
78
- end
79
-
80
- # @param [Pixiv::BookmarkList, Pixiv::Member, Integer] list_or_member
81
- # @param [Hash] opts
82
- # @option opts [Boolean] :include_deleted (false)
83
- # whether the returning enumerator yields deleted illust as +nil+ or not
84
- # @return [Pixiv::PageCollection::Enumerator]
85
- def bookmarks(list_or_member, opts = {})
86
- list = list_or_member.is_a?(BookmarkList) ? list_or_member
87
- : bookmark_list(list_or_member)
87
+ # @return [Pixiv::PrivateBookmarkList] private bookmark list bound to +self+
88
+ def private_bookmark_list(member_or_id = member_id, page = 1)
89
+ illust_list_with_class(PrivateBookmarkList, member_or_id, page)
90
+ end
91
+
92
+ # @param [Pixiv::IllustList] list
93
+ # @!macro [new] opts_and_return
94
+ # @param [Hash] opts
95
+ # @option opts [Boolean] :include_deleted (false)
96
+ # whether the returning enumerator yields deleted illust as +nil+ or not
97
+ # @return [Pixiv::PageCollection::Enumerator]
98
+ def illusts(list, opts = {})
88
99
  PageCollection::Enumerator.new(self, list, !!opts[:include_deleted])
89
100
  end
90
101
 
102
+ # @param [Pixiv::Member, Integer] member_or_id
103
+ # @param [Integer] page
104
+ # @!macro opts_and_return
105
+ def works(member_or_id = member_id, page = 1, opts = {})
106
+ illusts(work_list(member_or_id, page), opts)
107
+ end
108
+
109
+ # @param [Pixiv::Member, Integer] member_or_id
110
+ # @param [Integer] page
111
+ # @!macro opts_and_return
112
+ def bookmarks(member_or_id = member_id, page = 1, opts = {})
113
+ illusts(bookmark_list(member_or_id, page), opts)
114
+ end
115
+
116
+ # @param [Integer] page
117
+ # @!macro opts_and_return
118
+ def private_bookmarks(page = 1, opts = {})
119
+ illusts(private_bookmark_list(member_id, page), opts)
120
+ end
121
+
91
122
  # Downloads the image to +io_or_filename+
92
123
  # @param [Pixiv::Illust] illust
93
- # @param [#write, String, Array<String, Symbol, #call>] io_or_filename io or filename or pattern (see {#filename_from_pattern})
124
+ # @param [#write, String, Array<String, Symbol, #call>] io_or_filename io or filename or pattern for {#filename_from_pattern}
94
125
  # @param [Symbol] size image size (+:small+, +:medium+, or +:original+)
95
126
  def download_illust(illust, io_or_filename, size = :original)
96
127
  size = {:s => :small, :m => :medium, :o => :original}[size] || size
@@ -111,7 +142,7 @@ module Pixiv
111
142
 
112
143
  # Downloads the images to +pattern+
113
144
  # @param [Pixiv::Illust] illust the manga to download
114
- # @param [Array<String, Symbol, #call>] pattern pattern (see {#filename_from_pattern})
145
+ # @param [Array<String, Symbol, #call>] pattern pattern for {#filename_from_pattern}
115
146
  # @note +illust#manga?+ must be +true+
116
147
  # @todo Document +&block+
117
148
  def download_manga(illust, pattern, &block)
@@ -129,20 +160,9 @@ module Pixiv
129
160
  end
130
161
  end
131
162
 
132
- protected
133
-
134
- def ensure_logged_in
135
- doc = agent.get("#{ROOT_URL}/mypage.php")
136
- raise Error::LoginFailed unless doc.body =~ /logout/
137
- @member_id = member_id_from_mypage(doc)
138
- end
139
-
140
- def member_id_from_mypage(doc)
141
- doc.at('.profile_area a')['href'].match(/(\d+)$/).to_a[1].to_i
142
- end
143
-
144
163
  # Generate filename from +pattern+ in context of +illust+ and +url+
145
164
  #
165
+ # @api private
146
166
  # @param [Array<String, Symbol, #call>] pattern
147
167
  # @param [Pixiv::Illust] illust
148
168
  # @param [String] url
@@ -153,7 +173,7 @@ module Pixiv
153
173
  # the +pattern+ is concatenated as the returning +filename+.
154
174
  #
155
175
  # * +:image_name+ in the +pattern+ is replaced with the base name of the +url+
156
- # * Any other symbol is replaced with the value of +illust.__send__(the_symbol)+
176
+ # * Any other symbol is replaced with the value of +illust.send(the_symbol)+
157
177
  # * +#call+-able object is replaced with the value of +the_object.call(illust)+
158
178
  # * String is left as-is
159
179
  def filename_from_pattern(pattern, illust, url)
@@ -164,12 +184,33 @@ module Pixiv
164
184
  name += '.' + $1
165
185
  end
166
186
  name
167
- elsif i.is_a?(Symbol) then illust.__send__(i)
187
+ elsif i.is_a?(Symbol) then illust.send(i)
168
188
  elsif i.respond_to?(:call) then i.call(illust)
169
189
  else i
170
190
  end
171
191
  }.join('')
172
192
  end
193
+
194
+ protected
195
+
196
+ def illust_list_with_class(list_class, member_or_id, page)
197
+ it = member_or_id
198
+ id = it.is_a?(Member) ? it.member_id : it.to_i
199
+ attrs = {member_id: id} # Don't set page or it will prevent checking bounds.
200
+ list_class.lazy_new(attrs) {
201
+ agent.get(list_class.url(id, page))
202
+ }.bind(self)
203
+ end
204
+
205
+ def ensure_logged_in
206
+ doc = agent.get("#{ROOT_URL}/mypage.php")
207
+ raise Error::LoginFailed unless doc.body =~ /logout/
208
+ @member_id = member_id_from_mypage(doc)
209
+ end
210
+
211
+ def member_id_from_mypage(doc)
212
+ doc.at('.profile_area a')['href'].match(/\d+$/).to_s.to_i
213
+ end
173
214
  end
174
215
 
175
216
  # @private
@@ -32,10 +32,11 @@ module Pixiv
32
32
  }
33
33
  # @return [String]
34
34
  lazy_attr_reader(:title) { at!('.work-info h1.title').inner_text }
35
- # @return [Integer]
35
+ # @return [Integer, nil]
36
36
  lazy_attr_reader(:num_pages) {
37
- n = doc.at('//ul[@class="meta"]/li[2]')
38
- n && n.inner_text.match(/(\d+)P$/).to_a[1].to_i
37
+ node = doc.at('//ul[@class="meta"]/li[2]')
38
+ n = node ? node.inner_text.match(/(\d+)P$/).to_a[1] : nil
39
+ n && n.to_i
39
40
  }
40
41
  # @return [Array<String>]
41
42
  lazy_attr_reader(:tag_names) { search!('ul.tags a.text').map {|n| n.inner_text } }
@@ -71,4 +72,23 @@ module Pixiv
71
72
  @image_url_components ||= small_image_url.match(%r{^(.+)_s(\.\w+(?:\?\d+)?)$}).to_a[1, 3]
72
73
  end
73
74
  end
75
+
76
+ module Illust::WithClient
77
+ include Page::WithClient
78
+
79
+ # @return [Pixiv::Member]
80
+ def member
81
+ client.member(member_id)
82
+ end
83
+
84
+ # (see Pixiv::Client#download_illust)
85
+ def download_illust(io_or_filename, size = :original)
86
+ client.download_illust(self, io_or_filename, size)
87
+ end
88
+
89
+ # (see Pixiv::Client#download_manga)
90
+ def download_manga(pattern, &block)
91
+ client.download_manga(self, pattern, &block)
92
+ end
93
+ end
74
94
  end
@@ -0,0 +1,46 @@
1
+ module Pixiv
2
+ # @abstract
3
+ class IllustList < Page
4
+ include PageCollection
5
+
6
+ # @return [Integer]
7
+ attr_reader :page
8
+ # @return [Integer]
9
+ attr_reader :total_count
10
+
11
+ def page_class
12
+ Illust
13
+ end
14
+
15
+ # Don't just do `alias illust_hashes page_hashes`;
16
+ # the illust_hashes intends to call the page_hashes
17
+ # overridden in a subclass.
18
+
19
+ # An array of illust attrs extracted from doc
20
+ # @return [Array<{Symbol=>Object}, nil>]
21
+ def illust_hashes
22
+ page_hashes
23
+ end
24
+
25
+ # Ditto.
26
+
27
+ # URLs extracted from doc
28
+ # @return [Array<{Symbol=>Object}, nil>]
29
+ def illust_urls
30
+ page_urls
31
+ end
32
+ end
33
+
34
+ module IllustList::WithClient
35
+ include Page::WithClient
36
+ include Enumerable
37
+
38
+ # @yieldparam [Illust] illust
39
+ def each
40
+ illust_hashes.each do |attrs|
41
+ url = attrs.delete(:url)
42
+ yield Illust.lazy_new(attrs) { client.agent.get(url) }
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,58 @@
1
+ module Pixiv
2
+ # Illust list owned by a member
3
+ #
4
+ # @abstract
5
+ #
6
+ # Implements common methods for bookmark.php and member_illust.php.
7
+ class OwnedIllustList < IllustList
8
+ # Returns the URL for given +member_id+ and +page+
9
+ # @param [Integer] member_id
10
+ # @param [Integer] page
11
+ # @return [String]
12
+ def self.url(member_id, page = 1)
13
+ raise NotImplementError
14
+ end
15
+
16
+ # @return [Integer]
17
+ lazy_attr_reader(:page) {
18
+ at!('li.pages-current').inner_text.to_i
19
+ }
20
+ # @return [Boolean]
21
+ lazy_attr_reader(:last?) {
22
+ at!('li.pages-current').next_element.inner_text.to_i == 0
23
+ }
24
+ # @return [Integer]
25
+ lazy_attr_reader(:member_id) {
26
+ doc.body.match(/pixiv\.context\.userId = '(\d+)'/).to_a[1].to_i
27
+ }
28
+
29
+ # @return [String]
30
+ def url
31
+ self.class.url(member_id, page)
32
+ end
33
+
34
+ # @return [Boolean]
35
+ def first?
36
+ page == 1
37
+ end
38
+
39
+ # @return [String]
40
+ def next_url
41
+ last? ? nil : self.class.url(member_id, page + 1)
42
+ end
43
+
44
+ # @return [String]
45
+ def prev_url
46
+ first? ? nil : self.class.url(member_id, page - 1)
47
+ end
48
+ end
49
+
50
+ module OwnedIllustList::WithClient
51
+ include IllustList::WithClient
52
+
53
+ # @return [Pixiv::Member]
54
+ def member
55
+ client.member(member_id)
56
+ end
57
+ end
58
+ end
@@ -2,13 +2,13 @@ module Pixiv
2
2
  class Page
3
3
  # A new Page
4
4
  # @param [Hash{Symbol=>Object}] attrs
5
- # @yieldreturn [Nokogiri::HTML::Document]
5
+ # @yieldreturn [Nokogiri::XML::Document]
6
6
  def self.lazy_new(attrs = {}, &doc_creator)
7
7
  self.new(doc_creator, attrs)
8
8
  end
9
9
 
10
10
  # @overload initialize(doc, attrs = {})
11
- # @param [Nokogiri::HTTP::Document] doc
11
+ # @param [Nokogiri::XML::Document] doc
12
12
  # @param [Hash{Symbol=>Object}] attrs
13
13
  # @overload initialize(doc_creator, attrs = {})
14
14
  # @param [#call] doc_creator
@@ -27,10 +27,10 @@ module Pixiv
27
27
  # @param [String, Symbol] attr_name
28
28
  # @return [Boolean]
29
29
  def fetched?(attr_name = :doc)
30
- instance_variable_get(:"@#{attr_name}") != nil
30
+ instance_variable_defined?(:"@#{attr_name}")
31
31
  end
32
32
 
33
- # @return [Nokogiri::HTTP::Document]
33
+ # @return [Nokogiri::XML::Document]
34
34
  def doc
35
35
  @doc ||= begin
36
36
  doc = @doc_creator.call
@@ -50,6 +50,7 @@ module Pixiv
50
50
  end
51
51
 
52
52
  # Bind +self+ to +client+
53
+ # @api private
53
54
  # @return self
54
55
  def bind(client)
55
56
  if self.class.const_defined?(:WithClient)
@@ -98,14 +99,14 @@ module Pixiv
98
99
 
99
100
  # +node.at(path)+ or raise error
100
101
  # @param [String] path XPath or CSS path
101
- # @return [Nokogiri::HTML::Node]
102
+ # @return [Nokogiri::XML::Node]
102
103
  def at!(path, node = doc)
103
104
  node.at(path) or raise Error::NodeNotFound, "node for `#{path}` not found"
104
105
  end
105
106
 
106
107
  # +node.search(path) or raise error
107
108
  # @param [String] path XPath or CSS path
108
- # @return [Array<Nokogiri::HTML::Node>]
109
+ # @return [Array<Nokogiri::XML::Node>]
109
110
  def search!(path, node = doc)
110
111
  node.search(path) or raise Error::NodeNotFound, "node for `#{path}` not found"
111
112
  end
@@ -1,31 +1,43 @@
1
1
  module Pixiv
2
2
  module PageCollection
3
3
  def first?
4
- raise NotImplementError
4
+ next_url.nil?
5
5
  end
6
6
 
7
7
  def last?
8
- raise NotImplementError
8
+ prev_url.nil?
9
9
  end
10
10
 
11
+ private
12
+ def not_implemented!
13
+ name = caller[0][/`([^']*)'/, 1]
14
+ raise NotImplementedError,
15
+ "unimplemented method `#{name}' for #{self}"
16
+ end
17
+ public
18
+
11
19
  def next_url
12
- raise NotImplementError
20
+ not_implemented!
13
21
  end
14
22
 
15
23
  def prev_url
16
- raise NotImplementError
24
+ not_implemented!
17
25
  end
18
26
 
19
27
  def page_class
20
- raise NotImplementError
28
+ not_implemented!
29
+ end
30
+
31
+ def page_hashes
32
+ not_implemented!
21
33
  end
22
34
 
23
35
  def page_urls
24
- raise NotImplementError
36
+ page_hashes.map {|h| h[:url] }
25
37
  end
26
38
 
27
- def page_hash
28
- page_urls.map {|url| {url: url} }
39
+ def size
40
+ page_hashes.size
29
41
  end
30
42
  end
31
43
 
@@ -67,6 +79,23 @@ module Pixiv
67
79
  end
68
80
  end
69
81
 
82
+ def each_collection
83
+ collection = @collection
84
+ loop do
85
+ yield collection
86
+ next_url = collection.next_url or break
87
+ collection = collection.class.lazy_new { @client.agent.get(next_url) }
88
+ end
89
+ end
90
+
91
+ def count(*item)
92
+ if item.empty? && !block_given? && @collection.respond_to?(:total_count)
93
+ @collection.total_count
94
+ else
95
+ super
96
+ end
97
+ end
98
+
70
99
  private
71
100
 
72
101
  def pages_from_collection(collection)
@@ -77,13 +106,5 @@ module Pixiv
77
106
  end
78
107
  }
79
108
  end
80
-
81
- def each_collection(collection = @collection)
82
- loop do
83
- yield collection
84
- break unless collection.next_url
85
- collection = collection.class.new(@client.agent.get(collection.next_url))
86
- end
87
- end
88
109
  end
89
110
  end
@@ -1,3 +1,3 @@
1
1
  module Pixiv
2
- VERSION = "0.0.3"
2
+ VERSION = "0.0.4"
3
3
  end
@@ -0,0 +1,37 @@
1
+ module Pixiv
2
+ class WorkList < OwnedIllustList
3
+ # (see super.url)
4
+ def self.url(member_id, page = 1)
5
+ "#{ROOT_URL}/member_illust.php?id=#{member_id}&p=#{page}"
6
+ end
7
+
8
+ # @return [Integer]
9
+ lazy_attr_reader(:total_count) {
10
+ node = at!('.layout-cell .count-badge')
11
+ node.inner_text.match(/\d+/).to_s.to_i
12
+ }
13
+ # @return [Array<Hash{Symbol=>Object}, nil>]
14
+ lazy_attr_reader(:page_hashes) {
15
+ node = search!('.display_works li') \
16
+ .xpath('self::node()[not(starts-with(a[1]/@href, "/bookmark"))]')
17
+ node.map {|n| hash_from_list_item(n) }
18
+ }
19
+
20
+ private
21
+
22
+ # @param [Nokogiri::XML::Node] node
23
+ # @return [Hash{Symbol=>Object}] illust_hash
24
+ def hash_from_list_item(node)
25
+ return nil if node.at('img[src*="limit_unknown_s.png"]')
26
+ illust_node = node.at('a')
27
+ illust_id = illust_node['href'].match(/illust_id=(\d+)/).to_a[1].to_i
28
+ {
29
+ url: Illust.url(illust_id),
30
+ illust_id: illust_id,
31
+ title: illust_node.inner_text,
32
+ member_id: member_id,
33
+ small_image_url: illust_node.at('img')['src'],
34
+ }
35
+ end
36
+ end
37
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pixiv
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.4
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-12-25 00:00:00.000000000 Z
12
+ date: 2012-12-26 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: mechanize
@@ -94,10 +94,13 @@ files:
94
94
  - lib/pixiv/client.rb
95
95
  - lib/pixiv/error.rb
96
96
  - lib/pixiv/illust.rb
97
+ - lib/pixiv/illust_list.rb
97
98
  - lib/pixiv/member.rb
99
+ - lib/pixiv/owned_illust_list.rb
98
100
  - lib/pixiv/page.rb
99
101
  - lib/pixiv/page_collection.rb
100
102
  - lib/pixiv/version.rb
103
+ - lib/pixiv/work_list.rb
101
104
  - pixiv.gemspec
102
105
  - spec/fixtures/empty.html
103
106
  - spec/fixtures/illust_345.html
@@ -118,18 +121,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
118
121
  - - ! '>='
119
122
  - !ruby/object:Gem::Version
120
123
  version: '0'
121
- segments:
122
- - 0
123
- hash: -1798318064021145738
124
124
  required_rubygems_version: !ruby/object:Gem::Requirement
125
125
  none: false
126
126
  requirements:
127
127
  - - ! '>='
128
128
  - !ruby/object:Gem::Version
129
129
  version: '0'
130
- segments:
131
- - 0
132
- hash: -1798318064021145738
133
130
  requirements: []
134
131
  rubyforge_project:
135
132
  rubygems_version: 1.8.24
@@ -144,3 +141,4 @@ test_files:
144
141
  - spec/pixiv/member_spec.rb
145
142
  - spec/pixiv/page_spec.rb
146
143
  - spec/spec_helper.rb
144
+ has_rdoc: