shutterstock-v2 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (136) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +27 -0
  3. data/.rspec +3 -0
  4. data/.rubocop.yml +6 -0
  5. data/.travis.yml +6 -0
  6. data/Dockerfile +17 -0
  7. data/Gemfile +3 -0
  8. data/Guardfile +9 -0
  9. data/README.md +377 -0
  10. data/Rakefile +19 -0
  11. data/lib/client/auth.rb +48 -0
  12. data/lib/client/categories.rb +11 -0
  13. data/lib/client/category.rb +16 -0
  14. data/lib/client/client.rb +72 -0
  15. data/lib/client/collection.rb +151 -0
  16. data/lib/client/collections.rb +16 -0
  17. data/lib/client/configuration.rb +20 -0
  18. data/lib/client/contributor.rb +15 -0
  19. data/lib/client/driver.rb +38 -0
  20. data/lib/client/error.rb +20 -0
  21. data/lib/client/image.rb +139 -0
  22. data/lib/client/image_assets.rb +56 -0
  23. data/lib/client/image_size_details.rb +26 -0
  24. data/lib/client/images.rb +27 -0
  25. data/lib/client/license.rb +67 -0
  26. data/lib/client/licenses.rb +23 -0
  27. data/lib/client/model.rb +15 -0
  28. data/lib/client/models.rb +11 -0
  29. data/lib/client/request.rb +41 -0
  30. data/lib/client/subscription.rb +35 -0
  31. data/lib/client/subscription_allotment.rb +19 -0
  32. data/lib/client/subscription_license_format.rb +16 -0
  33. data/lib/client/subscription_license_formats.rb +12 -0
  34. data/lib/client/subscription_price.rb +13 -0
  35. data/lib/client/subscriptions.rb +37 -0
  36. data/lib/client/thumbnail.rb +17 -0
  37. data/lib/client/user.rb +68 -0
  38. data/lib/client/version.rb +3 -0
  39. data/lib/shutterstock-v2.rb +31 -0
  40. data/shutterstock-v2.gemspec +30 -0
  41. data/spec/cassettes/Shutterstock_Auth_get_access_token/returns_hash_with_access_token.yml +86 -0
  42. data/spec/cassettes/Shutterstock_Auth_get_authorize_url/returns_URL_to_redirect_user_to_passing_redirect_url_an.yml +48 -0
  43. data/spec/cassettes/Shutterstock_Categories/parses_params_correctly.yml +53 -0
  44. data/spec/cassettes/Shutterstock_Categories/returns_all_cats_for_an_image.yml +53 -0
  45. data/spec/cassettes/Shutterstock_Collection/add_image_adds_image_using_Image_new.yml +48 -0
  46. data/spec/cassettes/Shutterstock_Collection/add_image_adds_image_using_id.yml +48 -0
  47. data/spec/cassettes/Shutterstock_Collection/add_image_error_raises_error_if_collection_does_not_exist.yml +52 -0
  48. data/spec/cassettes/Shutterstock_Collection/create_creates_a_collection.yml +52 -0
  49. data/spec/cassettes/Shutterstock_Collection/destroy_destroys_a_collection.yml +93 -0
  50. data/spec/cassettes/Shutterstock_Collection/find_adds_an_image.yml +97 -0
  51. data/spec/cassettes/Shutterstock_Collection/find_converts_list_to_images.yml +101 -0
  52. data/spec/cassettes/Shutterstock_Collection/find_finds_a_collection_given_an_id.yml +52 -0
  53. data/spec/cassettes/Shutterstock_Collection/find_raises_error_for_invalid_collection_id.yml +50 -0
  54. data/spec/cassettes/Shutterstock_Collection/find_removes_an_image.yml +95 -0
  55. data/spec/cassettes/Shutterstock_Collection/list_returns_all_collections_for_the_current_user.yml +53 -0
  56. data/spec/cassettes/Shutterstock_Collection/remove_image_removes_image_using_Image_new.yml +46 -0
  57. data/spec/cassettes/Shutterstock_Collection/remove_image_removes_image_using_id.yml +46 -0
  58. data/spec/cassettes/Shutterstock_Collection/update_changes_the_name_of_a_collection.yml +97 -0
  59. data/spec/cassettes/Shutterstock_Collections/returns_all_collections_for_current_user.yml +53 -0
  60. data/spec/cassettes/Shutterstock_Image/fill_fills_all_details_of_current_image.yml +109 -0
  61. data/spec/cassettes/Shutterstock_Image/fills_all_details_of_current_image.yml +109 -0
  62. data/spec/cassettes/Shutterstock_Image/find_places_image_data_into_correct_fields.yml +56 -0
  63. data/spec/cassettes/Shutterstock_Image/find_places_more_image_data_into_correct_fields.yml +53 -0
  64. data/spec/cassettes/Shutterstock_Image/find_returns_an_Image_object.yml +56 -0
  65. data/spec/cassettes/Shutterstock_Image/finds_similar_images_given_an_image.yml +125 -0
  66. data/spec/cassettes/Shutterstock_Image/returns_an_Image_object.yml +56 -0
  67. data/spec/cassettes/Shutterstock_Image/returns_similar_images.yml +72 -0
  68. data/spec/cassettes/Shutterstock_Image/search_searches_for_images_based_on_searchterm.yml +73 -0
  69. data/spec/cassettes/Shutterstock_Image/search_searches_using_more_than_one_parameter.yml +77 -0
  70. data/spec/cassettes/Shutterstock_Image/searches_for_images_based_on_searchterm.yml +73 -0
  71. data/spec/cassettes/Shutterstock_Image/searches_using_more_than_one_parameter.yml +77 -0
  72. data/spec/cassettes/Shutterstock_Image/similar_finds_similar_images_given_an_image.yml +125 -0
  73. data/spec/cassettes/Shutterstock_Image/similar_returns_similar_images.yml +72 -0
  74. data/spec/cassettes/Shutterstock_ImageAssets/find_calculates_fields_correctly.yml +53 -0
  75. data/spec/cassettes/Shutterstock_ImageAssets/find_places_image_data_into_correct_fields.yml +53 -0
  76. data/spec/cassettes/Shutterstock_Images/fill_fills_details_of_all_images_in_list_all_images_now_have_keywords.yml +1144 -0
  77. data/spec/cassettes/Shutterstock_Images/returns_similar_images.yml +126 -0
  78. data/spec/cassettes/Shutterstock_License/license_editorial_acknowledgement_returns_error_if_requesting_an_image.yml +53 -0
  79. data/spec/cassettes/Shutterstock_License/license_editorial_acknowledgement_returns_licenced_image_if_ed_ack_is_.yml +52 -0
  80. data/spec/cassettes/Shutterstock_License/license_license_from_image_object_sends_editorial_acknowledgement_when.yml +160 -0
  81. data/spec/cassettes/Shutterstock_License/license_license_from_image_object_using_found_subscription.yml +108 -0
  82. data/spec/cassettes/Shutterstock_License/license_license_from_image_object_vector_image.yml +108 -0
  83. data/spec/cassettes/Shutterstock_License/license_multiple_licenses_multiple_images.yml +52 -0
  84. data/spec/cassettes/Shutterstock_License/license_multiple_licenses_multiple_images_from_Image_new.yml +52 -0
  85. data/spec/cassettes/Shutterstock_License/license_multiple_returns_error_in_Licenses_when_incorrect_image_used.yml +53 -0
  86. data/spec/cassettes/Shutterstock_License/license_single_licencing_same_image_twice_does_not_give_error.yml +101 -0
  87. data/spec/cassettes/Shutterstock_License/license_single_license_fails_when_subscription_doesn_t_allow.yml +49 -0
  88. data/spec/cassettes/Shutterstock_License/license_single_licenses_single_image.yml +52 -0
  89. data/spec/cassettes/Shutterstock_License/license_single_licenses_single_image_from_Image_new.yml +52 -0
  90. data/spec/cassettes/Shutterstock_License/license_single_licenses_single_image_from_hash.yml +52 -0
  91. data/spec/cassettes/Shutterstock_License/license_single_licenses_single_image_with_smaller_size.yml +52 -0
  92. data/spec/cassettes/Shutterstock_License/license_single_licenses_vector_image.yml +52 -0
  93. data/spec/cassettes/Shutterstock_License/license_single_licensing_same_image_twice_does_not_give_error.yml +101 -0
  94. data/spec/cassettes/Shutterstock_License/license_single_returns_error_when_incorrect_image_used.yml +103 -0
  95. data/spec/cassettes/Shutterstock_License/license_single_returns_error_when_incorrect_subscription_used.yml +53 -0
  96. data/spec/cassettes/Shutterstock_Models/parses_params_correctly.yml +53 -0
  97. data/spec/cassettes/Shutterstock_Models/returns_all_models_for_an_image.yml +53 -0
  98. data/spec/cassettes/Shutterstock_Subscription/allows_image_size_download_correctly_finds_if_image_size_is_possi.yml +59 -0
  99. data/spec/cassettes/Shutterstock_Subscription/new_parses_info_on_user_correctly.yml +59 -0
  100. data/spec/cassettes/Shutterstock_Subscription/new_returns_a_subscription_for_current_user.yml +59 -0
  101. data/spec/cassettes/Shutterstock_SubscriptionLicenseFormat/new_parses_info_correctly.yml +59 -0
  102. data/spec/cassettes/Shutterstock_SubscriptionLicenseFormat/new_returns_a_subscription_license_format_for_curren.yml +59 -0
  103. data/spec/cassettes/Shutterstock_Subscriptions/subscriptions_active_expired_total_subscriptions.yml +59 -0
  104. data/spec/cassettes/Shutterstock_Subscriptions/subscriptions_active_returns_only_active_subscriptions.yml +59 -0
  105. data/spec/cassettes/Shutterstock_Subscriptions/subscriptions_downloads_left_only_subscriptions_with_downloads_l.yml +59 -0
  106. data/spec/cassettes/Shutterstock_Subscriptions/subscriptions_expired_returns_only_expired_subscriptions.yml +59 -0
  107. data/spec/cassettes/Shutterstock_Subscriptions/subscriptions_find_subscription_for_image_size_finds_subs_to_use.yml +59 -0
  108. data/spec/cassettes/Shutterstock_Subscriptions/subscriptions_returns_all_subscriptions_for_current_user.yml +59 -0
  109. data/spec/cassettes/Shutterstock_User/find_parses_info_on_user_correctly.yml +52 -0
  110. data/spec/cassettes/Shutterstock_User/find_returns_object_for_current_user.yml +52 -0
  111. data/spec/client/auth_spec.rb +36 -0
  112. data/spec/client/categories_spec.rb +26 -0
  113. data/spec/client/category_spec.rb +16 -0
  114. data/spec/client/client_spec.rb +32 -0
  115. data/spec/client/collection_spec.rb +159 -0
  116. data/spec/client/collections_spec.rb +18 -0
  117. data/spec/client/configuration_spec.rb +10 -0
  118. data/spec/client/contributor_spec.rb +14 -0
  119. data/spec/client/driver_spec.rb +20 -0
  120. data/spec/client/image_assets_spec.rb +51 -0
  121. data/spec/client/image_size_details_spec.rb +33 -0
  122. data/spec/client/image_spec.rb +102 -0
  123. data/spec/client/images_spec.rb +31 -0
  124. data/spec/client/license_spec.rb +234 -0
  125. data/spec/client/model_spec.rb +14 -0
  126. data/spec/client/models_spec.rb +23 -0
  127. data/spec/client/request_spec.rb +79 -0
  128. data/spec/client/subscription_allotment_spec.rb +25 -0
  129. data/spec/client/subscription_license_format_spec.rb +29 -0
  130. data/spec/client/subscription_price_spec.rb +17 -0
  131. data/spec/client/subscription_spec.rb +60 -0
  132. data/spec/client/subscriptions_spec.rb +54 -0
  133. data/spec/client/thumbnail_spec.rb +21 -0
  134. data/spec/client/user_spec.rb +37 -0
  135. data/spec/spec_helper.rb +88 -0
  136. metadata +467 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: e4872bf6fbbe740553693206c9deed1348c5c7eb
4
+ data.tar.gz: c8f43a8f5a5c1bb05fe20c6f724be8ad81a7428f
5
+ SHA512:
6
+ metadata.gz: ba33e6cc67b0b3929c6e57d527be97d485a965d7a7617162e7099431066719d3fad7dbad736ae18f411845eb4669a5d28467a80c3c1329469da7919281e13ae8
7
+ data.tar.gz: d38bc5675ca6223227f98685efe12cfb17366f26037e1aceecb5d2ed78c4a74563d4a20b72666127ac9c91ec5e8bc7f198228cd29ffccb4799d9d91d66029b7c
@@ -0,0 +1,27 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ coverage
6
+ InstalledFiles
7
+ lib/bundler/man
8
+ pkg
9
+ rdoc
10
+ spec/reports
11
+ test/tmp
12
+ test/version_tmp
13
+ tmp
14
+
15
+ Gemfile.lock
16
+
17
+ # YARD artifacts
18
+ .yardoc
19
+ _yardoc
20
+ doc/
21
+ vendor
22
+ *.swp
23
+ *.swo
24
+
25
+ .env
26
+ auth_sequence.txt
27
+ run-docker.sh
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --color
2
+ --format progress
3
+ -I.
@@ -0,0 +1,6 @@
1
+ Documentation:
2
+ Enabled: false
3
+
4
+ MethodLength:
5
+ Max: 20
6
+
@@ -0,0 +1,6 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.1
4
+ - 2.2
5
+ - 2.3
6
+ - 2.4
@@ -0,0 +1,17 @@
1
+ FROM ruby:2.4
2
+ MAINTAINER dp@vivitec.com.au
3
+
4
+ RUN apt-get update && apt-get install -y \
5
+ build-essential
6
+
7
+ RUN mkdir -p /app
8
+ WORKDIR /app
9
+
10
+ RUN mkdir -p /app/lib/client
11
+ COPY Gemfile Gemfile.lock shutterstock.gemspec ./
12
+ COPY lib/client/version.rb ./lib/client
13
+ RUN gem install bundler && bundle install --jobs 20 --retry 5
14
+
15
+ ENV RAKE_ENV development
16
+
17
+ CMD ["bundle", "exec", "rake", "test"]
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec
@@ -0,0 +1,9 @@
1
+ # A sample Guardfile
2
+ # More info at https://github.com/guard/guard#readme
3
+
4
+ guard :rspec, cmd: 'bundle exec rspec' do
5
+ watch(%r{^spec/.+_spec\.rb$})
6
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
7
+ watch('spec/spec_helper.rb') { "spec" }
8
+ end
9
+
@@ -0,0 +1,377 @@
1
+ ## Description
2
+
3
+ This client provides an easy way to interact with [version 2 of the Shutterstock, Inc. API](http://api.shutterstock.com) which gives you access to millions of photos, illustrations and footage clips. You will need a [Client ID and Client Secret from Shutterstock](https://developers.shutterstock.com/applications) to use this client.
4
+
5
+ The API operations are done within the context of a specific user/account. Below are some examples of how to use the API client.
6
+
7
+ **Currently, this API only supports Images, not videos or music.**
8
+
9
+ ## Installation
10
+
11
+ Add this line to your application's Gemfile:
12
+
13
+ gem 'shutterstock-v2'
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install shutterstock-v2
22
+
23
+ ## Quick Start
24
+
25
+ First, see the Authentication section to generate a client_id, client_secret and access_token
26
+
27
+ ```ruby
28
+ require 'shutterstock-v2'
29
+
30
+ Shutterstock::Client.instance.configure do |config|
31
+ config.client_id = "xxx"
32
+ config.client_secret = "xxx"
33
+ config.access_token = "xxx"
34
+ end
35
+
36
+ images = Shutterstock::Image.search("blue rose")
37
+ images.total_count
38
+ # => 170416
39
+ images.count # Only returns first page of results
40
+ # => 20
41
+
42
+ image = images.first
43
+ image.id
44
+ # => 353732165
45
+ image.description
46
+ # => "close-up blue rose isolated on white background macro"
47
+
48
+ # License image for download, finding appropriate license from user's subscriptions
49
+ license = image.license
50
+
51
+ if !license.error
52
+ `wget #{license.url}`
53
+ end
54
+
55
+ # Create a collection
56
+ collection = Shutterstock::Collection.create("blue rose")
57
+ # Add first page of results from our search to the collection
58
+ collection.add_image(images)
59
+ # Delete the collection
60
+ collection.destroy
61
+
62
+ ```
63
+
64
+
65
+ ## Configuration
66
+
67
+ Configuration is through a call to the `Shutterstock::Client` singleton. All subsequent calls will use these configuration options.
68
+
69
+ You can receive a [Client ID and Client Secret from Shutterstock](https://developers.shutterstock.com/applications). A non-expiring access_token can be generated through API calls. See the Authentication section below.
70
+
71
+ ```ruby
72
+ require 'shutterstock-v2'
73
+
74
+ Shutterstock::Client.instance.configure do |config|
75
+ config.client_id = "xxx"
76
+ config.client_secret = "xxx"
77
+ config.access_token = "xxx"
78
+ end
79
+ ```
80
+
81
+
82
+ # Image
83
+
84
+ ```ruby
85
+ image = Shutterstock::Image.find(118139110)
86
+ # => #<Shutterstock::Image>
87
+ image.assets
88
+ # => #<Shutterstock::ImageAssets>
89
+ image.assets.preview.url
90
+ # => "https://image.shutterstock.com/display_pic_with_logo/1306729/118139110/stock-photo-adorable-labrador-puppy-playing-with-a-chew-toy-on-white-backdrop-118139110.jpg
91
+ image.assets.huge.height
92
+ # => 3090
93
+
94
+ image.keywords
95
+ # => ["animal", "animal themes", "backgrounds", "cute", "dog", ...]
96
+
97
+ image.description
98
+ # => "Adorable Labrador Puppy Playing with a Chew Toy on White Backdrop"
99
+
100
+ image.adult?
101
+ # => false
102
+
103
+ # Requires editorial consent before licenseing
104
+ image.editorial?
105
+ # => false
106
+
107
+ image.similar
108
+ # => #<Shutterstock::Images>, an array of #<Shutterstock::Image>
109
+ # Currently only returns first page of results
110
+
111
+ image.similar.total_count # total count of similar images
112
+ ```
113
+
114
+ ### Retrieving all image data
115
+
116
+ Some queries don't return full image data. Use `fill` to retrieve all data for a `Shutterstock::Image`
117
+
118
+ ```ruby
119
+ # collection.items only returns image id's
120
+ first_collection_of_user = Shutterstock::Collection.list.first
121
+ image = first_collection_of_user.items.first
122
+
123
+ # Description isn't downloaded by default
124
+ image.description
125
+ # => nil
126
+
127
+ image.fill
128
+
129
+ image.description
130
+ # => "Rose Garden"
131
+ image.assets.preview.url
132
+ # => "http://...."
133
+
134
+ # .fill returns self, to help with chaining
135
+ image.fill.description
136
+
137
+ # .fill can also be used on a image list
138
+ images = Shutterstock::Collection.list.fill
139
+ images.first.description
140
+ ```
141
+
142
+ ## Searching for Images
143
+
144
+ ```ruby
145
+ purple_cats = Shutterstock::Image.search("purple cat")
146
+ purple_cats.first.id
147
+ # => 431931730
148
+ ```
149
+
150
+ Shutterstock has a strong searching capability. Pass a hash to utilize [all search parameters available](https://developers.shutterstock.com/api/v2/images/search).
151
+
152
+ ```ruby
153
+ # one older japanese male teenager with a garden with a model release in landscape format
154
+ images = Shutterstock::Image.search({
155
+ query: 'garden',
156
+ people_number: 1,
157
+ people_ethnicity: 'japanese',
158
+ people_gender: 'male',
159
+ people_age: 'teenagers',
160
+ people_model_released: true,
161
+ orientation: 'horizontal'})
162
+
163
+ images.first.assets.preview.url
164
+ ```
165
+
166
+ ![Image 529426645](https://image.shutterstock.com/display_pic_with_logo/692713/529426645/stock-photo-man-who-plant-a-garden-529426645.jpg)
167
+
168
+ ## Image Licencing
169
+
170
+ To license an image for use, call `license` on a `Shutterstock::Image`. You'll receive a `Shutterstock::License` object back with any errors, the allotment from your plan, and the download url. `license` will find a valid subscription for the image size, and use that to purchase the image. Optionally specify the size (small, medium, huge, vector) and format (jpg, eps).
171
+
172
+ If an image requires editorial approval, `license` requests it.
173
+
174
+ ```ruby
175
+ licensed = Image.find(553180399).license
176
+ licensed.allotment_charge # 1 if not previously licensed, otherwise 0
177
+ licensed.url
178
+ # => "https://download.shutterstock.com/gatekeeper/abc/original.jpg"
179
+
180
+ # License the smallest asset of the image. Supports: small, medium, huge, vector. Default: huge.
181
+ licensed = Image.find(553180399).license(size: 'small')
182
+
183
+ # License the vector image
184
+ licensed = Image.find(553956103).license(size: 'vector', format: 'eps')
185
+ ```
186
+
187
+ You can choose a specific subscription, or license multiple images through `Shutterstock::License`. See Subscriptions below.
188
+
189
+
190
+ # Collections
191
+
192
+ ```ruby
193
+ collection = Shutterstock::Collection.find(21722255) # get a collection
194
+ collection.items # array of Shutterstock::Images
195
+
196
+ # metadata
197
+ collection.name # name of collection
198
+ collection.cover_item # Shutterstock::Image of cover image
199
+
200
+ ## Create Collection
201
+ new_collection = Shutterstock::Collection.create("mynewcollection")
202
+
203
+ ## Update Collection
204
+ new_collection.update(name: "updatename")
205
+
206
+ ## Destroy Collection
207
+ new_collection.destroy
208
+
209
+ ## Add Image to Collection
210
+ collection.add_image(987654321)
211
+ # or use any Shutterstock::Image object
212
+ collection.add_image(Image.find(12345))
213
+ # Can add multiple images
214
+ collection.add_image([1234, 2345, 3456])
215
+
216
+ ## Remove image from Collection
217
+ collection.remove_image(987654321)
218
+
219
+ ## Show all collections for current user (linked to access_token)
220
+ result = Shutterstock::Collection.list
221
+
222
+ ```
223
+
224
+ If you don't have a `Shutterstock::Collection` object handy, call the class with a collection ID
225
+
226
+ ```ruby
227
+ new_collection = Shutterstock::Collection.create("mynewcollection")
228
+ collection_id = new_collection.id
229
+ Shutterstock::Collection.update(id: collection_id, name: "updatename")
230
+ Shutterstock::Collection.destroy(id: collection_id)
231
+ Shutterstock::Collection.add_image(id: collection_id, image_id: 987654321)
232
+ Shutterstock::Collection.remove_image({id: collection_id, image_id: 987654321})
233
+ ```
234
+
235
+ # Subscriptions
236
+
237
+ ```ruby
238
+ # Find active (not expired) subscriptions for current user
239
+ subscriptions = Shutterstock::User.subscriptions.active
240
+ sub = subscriptions.first
241
+
242
+ sub.description
243
+ # => "Monthly Subscription"
244
+ sub.allotment.downloads_limit
245
+ # => 350
246
+ sub.allotment.downloads_left
247
+ # => 314
248
+ sub.has_downloads_left?
249
+ # => true
250
+
251
+ # Find a subscription for a specific image size
252
+ # Searches active subscriptions with downloads left
253
+ sub_id = Shutterstock::User.subscriptions.find_subscription_for_image_size('small').id
254
+ # => "s9999999"
255
+
256
+ # Images can be licensed using a subscription id
257
+ Shutterstock::License.license(subscription_id: sub_id, image_id: 1234)
258
+ Shutterstock::License.license(subscription_id: sub_id, image_id: Shutterstock::Image.find(1234))
259
+
260
+ # Optionally choose the size, format, or acknowledge the image will be used for editorial purposes
261
+ Shutterstock::License.license(subscription_id: sub_id, image_id: 1234, format: 'jpg', size: 'huge', editorial_acknowledgement: true)
262
+
263
+ # To specify metadata with the license request, use a hash
264
+ license_request = { image_id: 1234, metadata: { job: "job1", purchase_order: 'purchase order 1'}}
265
+ Shutterstock::License.license(subscription_id: sub_id, image_id: license_request)
266
+
267
+ # License multiple images by sending an array of image_ids, Shutterstock::Image objects, or hashes to license_multiple
268
+ licenses = Shutterstock::License.license_multiple(subscription_id: sub_id, image_id: [1234, 2345, 3456])
269
+ if !licenses.errors
270
+ `wget #{licenses.first.url}`
271
+ end
272
+ ```
273
+
274
+
275
+ # Authentication
276
+
277
+ To use this library, first [register an application at Shutterstock](https://developers.shutterstock.com/applications).
278
+
279
+ An access_token is needed. If your integration uses only one user account, you can follow the [single user integration](https://developers.shutterstock.com/guides/authentication#single-user-integration) directions to find the access_token.
280
+
281
+ Specify a `scope` to limit the queries that can be run by this token.
282
+
283
+ ## Manually retrieve an access_token
284
+
285
+ ```ruby
286
+ require 'shutterstock-v2'
287
+
288
+ puts "Retrieves access_token from Shutterstock API"
289
+ puts "First, create an application from this page:"
290
+ puts "https://developers.shutterstock.com/applications"
291
+ puts
292
+ puts "Enter Client ID"
293
+ client_id = gets.strip
294
+ puts
295
+ puts "Enter Client Secret"
296
+ client_secret = gets.strip
297
+
298
+ # Create configuration
299
+ Shutterstock::Client.instance.configure do |config|
300
+ config.client_id = client_id
301
+ config.client_secret = client_secret
302
+ end
303
+
304
+ puts "Requesting auth from Shutterstock..."
305
+ url = Shutterstock::Auth.get_authorize_url(redirect_uri: 'http://localhost',
306
+ state: 'my_state',
307
+ scope: 'licenses.create licenses.view purchases.view collections.view collections.edit')
308
+
309
+ puts
310
+ puts "Open this url in your process to complete the authication process :"
311
+ puts url
312
+ puts
313
+ puts "Authorize with your Shutterstock username/password."
314
+ puts
315
+ puts "You will be redirected to a localhost URL. Find the code= parameter in the URI"
316
+ puts "For example: http://localhost/?code=Dc4nSMazdKkFtk7AyBkSG3&state=my_state"
317
+ puts "Code is Dc4nSMazdKkFtk7AyBkSG3"
318
+ puts
319
+ puts "Enter the code= parameter here:"
320
+ code = gets.strip
321
+
322
+ begin
323
+ result = Shutterstock::Auth.get_access_token(code: code)
324
+ puts "You are now authenticated."
325
+ puts
326
+ puts "access_token is : #{result["access_token"]}"
327
+ puts "Use this in the config section:"
328
+
329
+ puts "Shutterstock::Client.instance.configure do |config|"
330
+ puts " config.client_id = '#{client_id}'"
331
+ puts " config.client_secret = '#{client_secret}'"
332
+ puts " config.access_token = '#{result["access_token"]}'"
333
+ puts "end"
334
+ puts
335
+ rescue Shutterstock::FailedResponse => e
336
+ puts "Authentication failed : #{e.msg}"
337
+ end
338
+
339
+ ```
340
+
341
+
342
+ # Tests
343
+
344
+ To run the tests using mocked responses, use
345
+ ```ruby
346
+ rspec
347
+ ```
348
+
349
+ To run the tests using making real API requests, use
350
+ ```ruby
351
+ VCR_OFF=1 SSTK_CLIENT_ID=<clientid> SSTK_CLIENT_SECRET=<secret> SSTK_ACCESS_TOKEN=<token> rspec
352
+ ```
353
+
354
+ Note: some tests will fail because they rely on new IDs supplied when the mocks were created.
355
+
356
+ When adding new test, uncomment options[:record] = :new_episodes line in `spec/spec-helper.rb`. And delete existing yml file
357
+
358
+ ## Automation
359
+
360
+ If you would like to automatically run tests when files are chaged, run `bundle exec guard`.
361
+ This will monitor `lib` and `spec` and will run the appropriate tests. After a test runs, hit `ENTER` to re-run all tests.
362
+
363
+
364
+ # Based on v1 code
365
+
366
+ The structure of this API code was based on the [Shutterstock API Version 1](https://github.com/shutterstock/ruby-shutterstock-api).
367
+
368
+ Major changes:
369
+ - Using version 2 of the Shutterstock API
370
+ - switched to Faraday for http requests
371
+ - used rspec 3 expect format
372
+ - added objects to support Image class
373
+ - added subscriptions and purchasing
374
+
375
+ Limitations:
376
+
377
+ - Currently limited to first page of results