pixiv_api 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
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