pixiv_api 0.0.4

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.
Files changed (65) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +9 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +4 -0
  5. data/Gemfile +8 -0
  6. data/Guardfile +14 -0
  7. data/LICENSE.txt +21 -0
  8. data/README.md +33 -0
  9. data/Rakefile +6 -0
  10. data/lib/pixiv_api.rb +22 -0
  11. data/lib/pixiv_api/array_response.rb +23 -0
  12. data/lib/pixiv_api/authentication.rb +60 -0
  13. data/lib/pixiv_api/client.rb +72 -0
  14. data/lib/pixiv_api/configuration.rb +48 -0
  15. data/lib/pixiv_api/pixiv_blob.rb +41 -0
  16. data/lib/pixiv_api/request.rb +18 -0
  17. data/lib/pixiv_api/request/favorite_users.rb +19 -0
  18. data/lib/pixiv_api/request/friends.rb +9 -0
  19. data/lib/pixiv_api/request/novels.rb +21 -0
  20. data/lib/pixiv_api/request/profiles.rb +9 -0
  21. data/lib/pixiv_api/request/promotions.rb +20 -0
  22. data/lib/pixiv_api/request/ranking.rb +9 -0
  23. data/lib/pixiv_api/request/search.rb +10 -0
  24. data/lib/pixiv_api/request/signup.rb +25 -0
  25. data/lib/pixiv_api/request/trends.rb +16 -0
  26. data/lib/pixiv_api/request/upload_work.rb +27 -0
  27. data/lib/pixiv_api/request/users.rb +13 -0
  28. data/lib/pixiv_api/request/util.rb +38 -0
  29. data/lib/pixiv_api/request/version.rb +9 -0
  30. data/lib/pixiv_api/request/works.rb +21 -0
  31. data/lib/pixiv_api/response.rb +134 -0
  32. data/lib/pixiv_api/response/action.rb +23 -0
  33. data/lib/pixiv_api/response/friend.rb +25 -0
  34. data/lib/pixiv_api/response/identity.rb +12 -0
  35. data/lib/pixiv_api/response/illustration.rb +6 -0
  36. data/lib/pixiv_api/response/manga.rb +6 -0
  37. data/lib/pixiv_api/response/novel.rb +15 -0
  38. data/lib/pixiv_api/response/pagination.rb +25 -0
  39. data/lib/pixiv_api/response/promotion.rb +11 -0
  40. data/lib/pixiv_api/response/request.rb +26 -0
  41. data/lib/pixiv_api/response/signup_validation_result.rb +7 -0
  42. data/lib/pixiv_api/response/tag.rb +9 -0
  43. data/lib/pixiv_api/response/ugoira.rb +18 -0
  44. data/lib/pixiv_api/response/upload_status.rb +7 -0
  45. data/lib/pixiv_api/response/upload_token.rb +7 -0
  46. data/lib/pixiv_api/response/user.rb +15 -0
  47. data/lib/pixiv_api/response/version.rb +7 -0
  48. data/lib/pixiv_api/response/work.rb +46 -0
  49. data/lib/pixiv_api/version.rb +3 -0
  50. data/pixiv_api.gemspec +32 -0
  51. data/spec/pixiv_api/authentication_spec.rb +57 -0
  52. data/spec/pixiv_api/client_spec.rb +28 -0
  53. data/spec/pixiv_api/configuration_spec.rb +41 -0
  54. data/spec/pixiv_api/pixiv_blob_spec.rb +23 -0
  55. data/spec/pixiv_api/request/favorite_users_spec.rb +47 -0
  56. data/spec/pixiv_api/request/friends_spec.rb +14 -0
  57. data/spec/pixiv_api/request/novels_spec.rb +37 -0
  58. data/spec/pixiv_api/request/profiles_spec.rb +13 -0
  59. data/spec/pixiv_api/request/signup_spec.rb +76 -0
  60. data/spec/pixiv_api/request/upload_work_spec.rb +41 -0
  61. data/spec/pixiv_api/request/users_spec.rb +32 -0
  62. data/spec/pixiv_api/request/works_spec.rb +16 -0
  63. data/spec/pixiv_api/version_spec.rb +7 -0
  64. data/spec/pixiv_api_spec.rb +8 -0
  65. metadata +275 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 961ad581d6a5b885d569658d903f45de1e6ef087
4
+ data.tar.gz: a56caea6f1ab24fcdda97b62e20f98aedbc8835b
5
+ SHA512:
6
+ metadata.gz: 9bb6d66208eeed8bdd055a34f14a1246790e88f32fa10f8018c648626990dc99c1306fb69b9260e2d529581e1c7d0e107941a19c306d2d8bfee44ec7d2700ece
7
+ data.tar.gz: 6647a7baca1df1e35315598b2f05dd52b26dba0845e359f3dd343d2f61c808450e52bad47ac59b8c702bb425b04a9c014df5bcae295f4fb15d41ede80bdb36a7
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.2.2
4
+ before_install: gem install bundler -v 1.10.3
data/Gemfile ADDED
@@ -0,0 +1,8 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem 'oauth2'
4
+ gem 'memoizable'
5
+ gem 'activesupport'
6
+ gem 'mime-types'
7
+
8
+ gemspec
@@ -0,0 +1,14 @@
1
+ guard :rspec, cmd: 'bundle exec rspec' do
2
+ require 'guard/rspec/dsl'
3
+ dsl = Guard::RSpec::Dsl.new(self)
4
+
5
+ # RSpec files
6
+ rspec = dsl.rspec
7
+ watch(rspec.spec_helper) { rspec.spec_dir }
8
+ watch(rspec.spec_support) { rspec.spec_dir }
9
+ watch(rspec.spec_files)
10
+
11
+ # Ruby files
12
+ ruby = dsl.ruby
13
+ dsl.watch_spec_files_for(ruby.lib_files)
14
+ end
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2015 alpaca-tc
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,33 @@
1
+ # PixivApi
2
+
3
+ ## Installation
4
+
5
+ Add this line to your application's Gemfile:
6
+
7
+ ```ruby
8
+ gem 'pixiv_api', github: 'pixiv/pixiv-api-ruby'
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ```
14
+ # Setup
15
+ PixivApi.configure do |config|
16
+ config[:client_id] = '...'
17
+ config[:client_secret] = '...'
18
+ config[:site] = '...'
19
+ config[:authorize_url] = '...'
20
+ config[:token_url] = '...'
21
+ end
22
+
23
+ user = User.first # Sign in with Oauth2
24
+
25
+ client = PixivApi::Client.new(
26
+ access_token: user.access_token,
27
+ refresh_token: user.refresh_token,
28
+ expires_at: user.expires_at
29
+ )
30
+
31
+ client.me # => return '/v1/me.json'
32
+ client.work(id: 1) # => '/v1/works/:id.json'
33
+ ```
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -0,0 +1,22 @@
1
+ require 'active_support/core_ext/array/extract_options'
2
+ require 'active_support/core_ext/hash/deep_merge'
3
+
4
+ module PixivApi
5
+ autoload :VERSION, 'pixiv_api/version'
6
+ autoload :Client, 'pixiv_api/client'
7
+ autoload :Authentication, 'pixiv_api/authentication'
8
+ autoload :ArrayResponse, 'pixiv_api/array_response'
9
+ autoload :Configuration, 'pixiv_api/configuration'
10
+ autoload :Identity, 'pixiv_api/identity'
11
+ autoload :Request, 'pixiv_api/request'
12
+ autoload :Response, 'pixiv_api/response'
13
+ autoload :PixivBlob, 'pixiv_api/pixiv_blob'
14
+
15
+ def self.configure
16
+ yield(configuration)
17
+ end
18
+
19
+ def self.configuration
20
+ @configuration ||= Configuration.new
21
+ end
22
+ end
@@ -0,0 +1,23 @@
1
+ require 'memoizable'
2
+ require 'active_support/core_ext/hash/indifferent_access'
3
+
4
+ module PixivApi
5
+ class ArrayResponse < Array
6
+ def self.from_response(response, klass, array)
7
+ new(response).tap do |array_response|
8
+ array.each do |attributes|
9
+ array_response << klass.from_response(response, attributes)
10
+ end
11
+ end
12
+ end
13
+
14
+ def initialize(response)
15
+ super()
16
+ @response = response
17
+ end
18
+
19
+ def pagination
20
+ @pagination ||= Response::Pagination.new(@response, @response.parsed['pagination'])
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,60 @@
1
+ require 'faraday'
2
+ require 'json'
3
+
4
+ module PixivApi
5
+ class Authentication
6
+ # Authentication provides password authentication for development.
7
+ class InvalidAuthError < StandardError; end
8
+
9
+ def initialize(id:, password:)
10
+ connection = Faraday.new(default_options) do |conn|
11
+ # Set default middleware
12
+ conn.request :multipart
13
+ conn.request :url_encoded
14
+ conn.adapter Faraday.default_adapter
15
+ end
16
+
17
+ @response = connection.post(
18
+ URI(configuration[:token_url]).path,
19
+ client_id: configuration[:client_id],
20
+ client_secret: configuration[:client_secret],
21
+ grant_type: 'password',
22
+ username: id,
23
+ password: password
24
+ )
25
+
26
+ raise InvalidAuthError, body['errors'].to_s unless success?
27
+ end
28
+
29
+ def body
30
+ @body ||= JSON.parse(@response.body).freeze
31
+ end
32
+
33
+ def to_client
34
+ PixivApi::Client.new(
35
+ access_token: body['access_token'],
36
+ refresh_token: body['refresh_token'],
37
+ expires_at: Time.now.to_i + body['expires_in']
38
+ )
39
+ end
40
+
41
+ def success?
42
+ @response.success?
43
+ end
44
+
45
+ private
46
+
47
+ def configuration
48
+ PixivApi.configuration.tap(&:require_keys!)
49
+ end
50
+
51
+ def default_options
52
+ {
53
+ headers: {
54
+ 'Host' => URI(configuration[:token_url]).host,
55
+ },
56
+ url: configuration[:site],
57
+ }
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,72 @@
1
+ require 'forwardable'
2
+ require 'oauth2'
3
+
4
+ module PixivApi
5
+ class Client
6
+ class UnsupportedApiError < NotImplementedError; end
7
+
8
+ extend Forwardable
9
+
10
+ include Request::FavoriteUsers
11
+ include Request::Friends
12
+ include Request::Novels
13
+ include Request::Profiles
14
+ include Request::Promotions
15
+ include Request::Ranking
16
+ include Request::Search
17
+ include Request::Trends
18
+ include Request::Users
19
+ include Request::Util
20
+ include Request::Version
21
+ include Request::Works
22
+ include Request::UploadWork
23
+ include Request::Signup
24
+
25
+ attr_reader :client, :access_token
26
+
27
+ def_delegators :@access_token, :get, :post, :put, :patch, :delete
28
+
29
+ # For development
30
+ def self.from_account(id:, password:)
31
+ PixivApi::Authentication.new(id: id, password: password).to_client
32
+ end
33
+
34
+ def initialize(access_token:, refresh_token:, expires_at:)
35
+ token_hash = {
36
+ access_token: access_token,
37
+ refresh_token: refresh_token,
38
+ expires_at: expires_at.to_i
39
+ }
40
+
41
+ @client = OAuth2::Client.new(*client_configuration) do |builder|
42
+ builder.request :multipart
43
+ builder.request :url_encoded
44
+ builder.adapter Faraday.default_adapter
45
+ end
46
+ @access_token = OAuth2::AccessToken.from_hash(client, token_hash)
47
+ end
48
+
49
+ def refresh!
50
+ @access_token = @access_token.refresh!
51
+ end
52
+
53
+ private
54
+
55
+ def unsupported!(path)
56
+ raise PixivApi::Client::UnsupportedApiError, "route of #{path} is not supported."
57
+ end
58
+
59
+ def client_configuration
60
+ configuration = PixivApi.configuration
61
+ configuration.require_keys! # 必要な設定がなされているかチェック
62
+
63
+ [
64
+ configuration.client_id,
65
+ configuration.client_secret,
66
+ site: configuration.site,
67
+ authorize_url: configuration.authorize_url,
68
+ token_url: configuration.token_url
69
+ ]
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,48 @@
1
+ require 'tmpdir'
2
+
3
+ module PixivApi
4
+ class Configuration < Hash
5
+ class MissingConfigurationError < StandardError; end
6
+ class InvalidKeyError < StandardError; end
7
+
8
+ REQUIRED_KEYS = %i(
9
+ client_id client_secret site authorize_url token_url
10
+ )
11
+
12
+ OPTIONAL_KEYS = %i(
13
+ cache_dir
14
+ )
15
+
16
+ (REQUIRED_KEYS + OPTIONAL_KEYS).each do |key|
17
+ define_method key do
18
+ self[key]
19
+ end
20
+ end
21
+
22
+ def cache_dir
23
+ self[:cache_dir] || Dir.mktmpdir('pixiv-api')
24
+ end
25
+
26
+ def []=(key, value)
27
+ if allowed_keys.include?(key)
28
+ super
29
+ else
30
+ raise InvalidKeyError, "#{key} is not configuration key."
31
+ end
32
+ end
33
+
34
+ def require_keys!
35
+ REQUIRED_KEYS.each do |key|
36
+ raise MissingConfigurationError, "configuration requires '#{key}'" unless self[key]
37
+ end
38
+
39
+ self
40
+ end
41
+
42
+ private
43
+
44
+ def allowed_keys
45
+ REQUIRED_KEYS + OPTIONAL_KEYS
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,41 @@
1
+ require 'open-uri'
2
+ require 'securerandom'
3
+
4
+ module PixivApi
5
+ class PixivBlob
6
+ REFERER = 'https://www.pixiv.net/'
7
+
8
+ attr_accessor :url
9
+
10
+ def initialize(url)
11
+ @url = url
12
+ end
13
+
14
+ def read
15
+ open(&:read)
16
+ end
17
+
18
+ def open(&block)
19
+ File.open(filepath, &block)
20
+ end
21
+
22
+ def to_path
23
+ filepath
24
+ end
25
+
26
+ private
27
+
28
+ def filepath
29
+ File.join(PixivApi.configuration.cache_dir, filename).tap do |filepath|
30
+ OpenURI.open_uri(url, 'Referer' => REFERER) do |uri|
31
+ File.open(filepath, 'wb') { |f| f.write(uri.read) }
32
+ end
33
+ end
34
+ end
35
+
36
+ def filename
37
+ extname = File.extname(@url).downcase
38
+ "#{SecureRandom.uuid}#{extname}"
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,18 @@
1
+ module PixivApi
2
+ module Request
3
+ require 'pixiv_api/request/favorite_users'
4
+ require 'pixiv_api/request/friends'
5
+ require 'pixiv_api/request/novels'
6
+ require 'pixiv_api/request/profiles'
7
+ require 'pixiv_api/request/promotions'
8
+ require 'pixiv_api/request/ranking'
9
+ require 'pixiv_api/request/search'
10
+ require 'pixiv_api/request/signup'
11
+ require 'pixiv_api/request/trends'
12
+ require 'pixiv_api/request/upload_work'
13
+ require 'pixiv_api/request/users'
14
+ require 'pixiv_api/request/util'
15
+ require 'pixiv_api/request/version'
16
+ require 'pixiv_api/request/works'
17
+ end
18
+ end
@@ -0,0 +1,19 @@
1
+ module PixivApi
2
+ module Request
3
+ module FavoriteUsers
4
+ def favorite_users(*args)
5
+ objects_from_response(Response::User, :get, '/v1/me/favorite-users.json', args.extract_options!)
6
+ end
7
+
8
+ def delete_favorite_users(user_ids: [], **args)
9
+ options = args.deep_merge(params: { delete_ids: user_ids.join(',') })
10
+ action_from_response(:delete, '/v1/me/favorite-users.json', options)
11
+ end
12
+
13
+ def favorite_user(user_id:, publicity:, **args)
14
+ options = args.deep_merge(params: { target_user_id: user_id, publicity: publicity })
15
+ action_from_response(:post, '/v1/me/favorite-users.json', options)
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,9 @@
1
+ module PixivApi
2
+ module Request
3
+ module Friends
4
+ def friends(*args)
5
+ objects_from_response(Response::Friend, :get, '/v1/me/friends.json', *args)
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,21 @@
1
+ module PixivApi
2
+ module Request
3
+ module Novels
4
+ def my_novels(*args)
5
+ unsupported!('/v1/me/novels.json')
6
+ end
7
+
8
+ def novels(*args)
9
+ unsupported!('/v1/novels.json')
10
+ end
11
+
12
+ def user_novels(user_id:, **args)
13
+ unsupported!('/v1/users/:user_id/novels.json')
14
+ end
15
+
16
+ def novel(id:, **args)
17
+ unsupported!('/v1/novels/:id.json')
18
+ end
19
+ end
20
+ end
21
+ end