cloudinary 1.26.0 → 1.27.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9bb33366a739a067a66cbcaf66534e48663e726d57f4d4b3657c44ec43f092e7
4
- data.tar.gz: 0dd05a5beabf06fc8d1914c7375fa7a6d37fce532edca0021919e13d9b28d318
3
+ metadata.gz: 46b21a3d7dd2411acaaeb35016f2ff7b648aeae5c1d077870f38e858ce1abedf
4
+ data.tar.gz: 5825bea0988e97e71df1d93fde04739b502230cda987f90415cb46f55df8b6b7
5
5
  SHA512:
6
- metadata.gz: 64cb7b27cd9909da6fbbaaf98777d4f05046098a6adb1572998323fd7517bf30c73095844683c83da59808f5945c93e90f1e2c685e06ff156b682fe92e902878
7
- data.tar.gz: f098206a8c9f6c73609ad2415cfc90f8359c678461d0bb22f5164aba57111fe55129eed6e98767c6242387ee6294bf4139b034848a1ff9b792cf1dba9fa3ef77
6
+ metadata.gz: 24c1334398c9c24ce9b0b536e991fb76aa633e1bda93b5e8dcccc1d2ac2f747e4645f52b61ad3b6db7bb9a59a092df602c35b964a05661c151fb6026cd1954c0
7
+ data.tar.gz: f8f3cdbe7b7374532f5dae2f5dca3543697a2fb2398050b4a7874d6527b3e87ffc84970684aefe25c65f255ba9ec89e15470e28658c28287df781e4ee2144799
data/CHANGELOG.md CHANGED
@@ -1,3 +1,14 @@
1
+ 1.27.0 / 2023-07-31
2
+ ==================
3
+
4
+ New functionality and features
5
+ ------------------------------
6
+
7
+ * Add support for `visual_search` Admin API
8
+ * Add support for Search URL
9
+ * Add support for `SearchFolders` API
10
+ * Add support for `media_metadata` API parameter
11
+
1
12
  1.26.0 / 2023-06-01
2
13
  ==================
3
14
 
@@ -207,6 +207,19 @@ class Cloudinary::Api
207
207
  call_api(:get, uri, params, options)
208
208
  end
209
209
 
210
+ # Find images based on their visual content.
211
+ #
212
+ # @param [Hash] options The optional parameters.
213
+ #
214
+ # @return [Cloudinary::Api::Response]
215
+ #
216
+ # @raise [Cloudinary::Api::Error]
217
+ def self.visual_search(options = {})
218
+ uri = "resources/visual_search"
219
+ params = only(options, :image_url, :image_asset_id, :text)
220
+ call_api(:get, uri, params, options)
221
+ end
222
+
210
223
  # Returns the details of the specified asset and all its derived assets.
211
224
  #
212
225
  # Note that if you only need details about the original asset,
@@ -1293,6 +1306,7 @@ class Cloudinary::Api
1293
1306
  :faces,
1294
1307
  :quality_analysis,
1295
1308
  :image_metadata,
1309
+ :media_metadata,
1296
1310
  :phash,
1297
1311
  :pages,
1298
1312
  :cinemagraph_analysis,
@@ -1,15 +1,23 @@
1
1
  class Cloudinary::Search
2
+ ENDPOINT = 'resources'
3
+
2
4
  SORT_BY = :sort_by
3
5
  AGGREGATE = :aggregate
4
6
  WITH_FIELD = :with_field
5
7
  KEYS_WITH_UNIQUE_VALUES = [SORT_BY, AGGREGATE, WITH_FIELD].freeze
6
8
 
9
+ TTL = 300 # Used for search URLs
10
+
7
11
  def initialize
8
12
  @query_hash = {
9
13
  SORT_BY => {},
10
14
  AGGREGATE => {},
11
15
  WITH_FIELD => {}
12
16
  }
17
+
18
+ @endpoint = self.class::ENDPOINT
19
+
20
+ @ttl = self.class::TTL
13
21
  end
14
22
 
15
23
  ## implicitly generate an instance delegate the method
@@ -69,11 +77,21 @@ class Cloudinary::Search
69
77
  self
70
78
  end
71
79
 
80
+ # Sets the time to live of the search URL.
81
+ #
82
+ # @param [Object] ttl The time to live in seconds.
83
+ #
84
+ # @return [Cloudinary::Search]
85
+ def ttl(ttl)
86
+ @ttl = ttl
87
+ self
88
+ end
89
+
72
90
  # Returns the query as an hash.
73
91
  #
74
92
  # @return [Hash]
75
93
  def to_h
76
- @query_hash.each_with_object({}) do |(key, value), query|
94
+ @query_hash.sort.each_with_object({}) do |(key, value), query|
77
95
  next if value.nil? || ((value.is_a?(Array) || value.is_a?(Hash)) && value.blank?)
78
96
 
79
97
  query[key] = KEYS_WITH_UNIQUE_VALUES.include?(key) ? value.values : value
@@ -82,7 +100,44 @@ class Cloudinary::Search
82
100
 
83
101
  def execute(options = {})
84
102
  options[:content_type] = :json
85
- uri = 'resources/search'
103
+ uri = "#{@endpoint}/search"
86
104
  Cloudinary::Api.call_api(:post, uri, to_h, options)
87
105
  end
106
+
107
+ # Creates a signed Search URL that can be used on the client side.
108
+ #
109
+ # @param [Integer] ttl The time to live in seconds.
110
+ # @param [String] next_cursor Starting position.
111
+ # @param [Hash] options Additional url delivery options.
112
+ #
113
+ # @return [String] The resulting Search URL
114
+ def to_url(ttl = nil, next_cursor = nil, options = {})
115
+ api_secret = options[:api_secret] || Cloudinary.config.api_secret || raise(CloudinaryException, "Must supply api_secret")
116
+
117
+ ttl = ttl || @ttl
118
+ query = self.to_h
119
+
120
+ _next_cursor = query.delete(:next_cursor)
121
+ next_cursor = _next_cursor if next_cursor.nil?
122
+
123
+ b64query = Base64.urlsafe_encode64(JSON.generate(query))
124
+
125
+ prefix = Cloudinary::Utils.build_distribution_domain(options)
126
+
127
+ signature = Cloudinary::Utils.hash("#{ttl}#{b64query}#{api_secret}", :sha256, :hexdigest)
128
+
129
+ next_cursor = "/#{next_cursor}" if !next_cursor.nil? && !next_cursor.empty?
130
+
131
+ "#{prefix}/search/#{signature}/#{ttl}/#{b64query}#{next_cursor}"
132
+ end
133
+
134
+ # Sets the API endpoint.
135
+ #
136
+ # @param [String] endpoint the endpoint to set.
137
+ #
138
+ # @return [Cloudinary::Search]
139
+ def endpoint(endpoint)
140
+ @endpoint = endpoint
141
+ self
142
+ end
88
143
  end
@@ -0,0 +1,5 @@
1
+ # The Cloudinary API folders search method allows you fine control on filtering and retrieving information on all the
2
+ # folders in your cloud with the help of query expressions in a Lucene-like query language.
3
+ class Cloudinary::SearchFolders < Cloudinary::Search
4
+ ENDPOINT = 'folders'
5
+ end
@@ -47,6 +47,7 @@ class Cloudinary::Uploader
47
47
  :filename_override => options[:filename_override],
48
48
  :headers => build_custom_headers(options[:headers]),
49
49
  :image_metadata => Cloudinary::Utils.as_safe_bool(options[:image_metadata]),
50
+ :media_metadata => Cloudinary::Utils.as_safe_bool(options[:media_metadata]),
50
51
  :invalidate => Cloudinary::Utils.as_safe_bool(options[:invalidate]),
51
52
  :moderation => options[:moderation],
52
53
  :notification_url => options[:notification_url],
@@ -62,6 +63,7 @@ class Cloudinary::Uploader
62
63
  :responsive_breakpoints => Cloudinary::Utils.generate_responsive_breakpoints_string(options[:responsive_breakpoints]),
63
64
  :return_delete_token => Cloudinary::Utils.as_safe_bool(options[:return_delete_token]),
64
65
  :similarity_search => options[:similarity_search],
66
+ :visual_search => Cloudinary::Utils.as_safe_bool(options[:visual_search]),
65
67
  :tags => options[:tags] && Cloudinary::Utils.build_array(options[:tags]).join(","),
66
68
  :timestamp => (options[:timestamp] || Time.now.to_i),
67
69
  :transformation => Cloudinary::Utils.generate_transformation_string(options.clone),
@@ -524,18 +524,10 @@ class Cloudinary::Utils
524
524
  version = options.delete(:version)
525
525
  force_version = config_option_consume(options, :force_version, true)
526
526
  format = options.delete(:format)
527
- cloud_name = config_option_consume(options, :cloud_name) || raise(CloudinaryException, "Must supply cloud_name in tag or in configuration")
528
527
 
529
- secure = options.delete(:secure)
530
- ssl_detected = options.delete(:ssl_detected)
531
- secure = ssl_detected || Cloudinary.config.secure if secure.nil?
532
- private_cdn = config_option_consume(options, :private_cdn)
533
- secure_distribution = config_option_consume(options, :secure_distribution)
534
- cname = config_option_consume(options, :cname)
535
528
  shorten = config_option_consume(options, :shorten)
536
529
  force_remote = options.delete(:force_remote)
537
- cdn_subdomain = config_option_consume(options, :cdn_subdomain)
538
- secure_cdn_subdomain = config_option_consume(options, :secure_cdn_subdomain)
530
+
539
531
  sign_url = config_option_consume(options, :sign_url)
540
532
  secret = config_option_consume(options, :api_secret)
541
533
  sign_version = config_option_consume(options, :sign_version) # Deprecated behavior
@@ -558,7 +550,7 @@ class Cloudinary::Utils
558
550
  type = type.to_s unless type.nil?
559
551
  resource_type ||= "image"
560
552
  source = source.to_s
561
- if !force_remote
553
+ unless force_remote
562
554
  static_support = Cloudinary.config.static_file_support || Cloudinary.config.static_image_support
563
555
  return original_source if !static_support && type == "asset"
564
556
  return original_source if (type.nil? || type == "asset") && source.match(%r(^https?:/)i)
@@ -594,7 +586,9 @@ class Cloudinary::Utils
594
586
  signature = "s--#{signature[0, long_url_signature ? LONG_URL_SIGNATURE_LENGTH : SHORT_URL_SIGNATURE_LENGTH ]}--"
595
587
  end
596
588
 
597
- prefix = unsigned_download_url_prefix(source, cloud_name, private_cdn, cdn_subdomain, secure_cdn_subdomain, cname, secure, secure_distribution)
589
+ options[:source] = source
590
+ prefix = build_distribution_domain(options)
591
+
598
592
  source = [prefix, resource_type, type, signature, transformation, version, source].reject(&:blank?).join("/")
599
593
  if sign_url && auth_token && !auth_token.empty?
600
594
  auth_token[:url] = URI.parse(source).path
@@ -707,6 +701,22 @@ class Cloudinary::Utils
707
701
  prefix
708
702
  end
709
703
 
704
+ def self.build_distribution_domain(options = {})
705
+ cloud_name = config_option_consume(options, :cloud_name) || raise(CloudinaryException, "Must supply cloud_name in tag or in configuration")
706
+
707
+ source = options.delete(:source)
708
+ secure = options.delete(:secure)
709
+ ssl_detected = options.delete(:ssl_detected)
710
+ secure = ssl_detected || Cloudinary.config.secure if secure.nil?
711
+ private_cdn = config_option_consume(options, :private_cdn)
712
+ secure_distribution = config_option_consume(options, :secure_distribution)
713
+ cname = config_option_consume(options, :cname)
714
+ cdn_subdomain = config_option_consume(options, :cdn_subdomain)
715
+ secure_cdn_subdomain = config_option_consume(options, :secure_cdn_subdomain)
716
+
717
+ unsigned_download_url_prefix(source, cloud_name, private_cdn, cdn_subdomain, secure_cdn_subdomain, cname, secure, secure_distribution)
718
+ end
719
+
710
720
  # Creates a base URL for the cloudinary api
711
721
  #
712
722
  # @param [Object] path Resource name
@@ -1373,6 +1383,4 @@ class Cloudinary::Utils
1373
1383
  algorithm = ALGORITHM_SIGNATURE[signature_algorithm] || raise("Unsupported algorithm '#{signature_algorithm}'")
1374
1384
  algorithm.public_send(hash_method, input)
1375
1385
  end
1376
-
1377
- private_class_method :hash
1378
1386
  end
@@ -1,4 +1,4 @@
1
1
  # Copyright Cloudinary
2
2
  module Cloudinary
3
- VERSION = "1.26.0"
3
+ VERSION = "1.27.0"
4
4
  end
data/lib/cloudinary.rb CHANGED
@@ -28,6 +28,7 @@ module Cloudinary
28
28
  autoload :Static, "cloudinary/static"
29
29
  autoload :CarrierWave, "cloudinary/carrier_wave"
30
30
  autoload :Search, "cloudinary/search"
31
+ autoload :SearchFolders, "cloudinary/search_folders"
31
32
 
32
33
  CF_SHARED_CDN = "d3jpl91pxevbkh.cloudfront.net"
33
34
  AKAMAI_SHARED_CDN = "res.cloudinary.com"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cloudinary
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.26.0
4
+ version: 1.27.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nadav Soferman
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2023-06-01 00:00:00.000000000 Z
13
+ date: 2023-07-31 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: aws_cf_signer
@@ -235,6 +235,7 @@ files:
235
235
  - lib/cloudinary/railtie.rb
236
236
  - lib/cloudinary/responsive.rb
237
237
  - lib/cloudinary/search.rb
238
+ - lib/cloudinary/search_folders.rb
238
239
  - lib/cloudinary/static.rb
239
240
  - lib/cloudinary/uploader.rb
240
241
  - lib/cloudinary/utils.rb