smeevil / cloudex Goto Github PK
View Code? Open in Web Editor NEWAn elixir library which helps with uploading image files or urls to cloudinary
License: Do What The F*ck You Want To Public License
An elixir library which helps with uploading image files or urls to cloudinary
License: Do What The F*ck You Want To Public License
Since you mention Phoenix support thought I'd ask if there's room for leniency on the poison and timex dependencies. Phoenix 1.2.1 has a hard limit that is lower which is going to be fixed for poison on their next release but doesn't look like timex. I got around it without a problem like so:
{:timex, "~> 3.1.0", override: true},
{:poison, "~> 3.0.0", override: true},
{:timex_ecto, "~> 3.1.0", override: true}, # required for timex v3+
If you don't feel that's an issue feel free to close this of course
This option is supported via public_id
, but it's not clearn in the documentation if I can customise it.
The requirement is ~> 3.1.7
which is quite strict, timex is 3.2
now.
Mix dependency requires 0.11.0, but current version of HTTPoison is 0.13.0.
When trying to install, I'm already using timex 3.3.0
I get an error
Failed to use "timex" (version 3.3.0) because
cloudex (versions 1.0.0 and 1.0.1) requires ~> 3.1.7
mix.lock specifies 3.3.0
defp deps do
[
{:phoenix, "~> 1.3.2"},
{:phoenix_pubsub, "~> 1.0"},
{:phoenix_ecto, "~> 3.2"},
{:postgrex, ">= 0.0.0"},
{:phoenix_html, "~> 2.10"},
{:phoenix_live_reload, "~> 1.0", only: :dev},
{:gettext, "~> 0.11"},
{:cowboy, "~> 1.0"},
{:comeonin, "~> 4.0"},
{:argon2_elixir, "~> 1.2"},
{:timex, "~> 3.1"},
{:ex_debug_toolbar, "~> 0.4.0"},
{:earmark, "~> 1.1"},
{:ecto_autoslug_field, "~> 0.5"},
{:cloudex, "~> 1.0.0"}
]
end
Hi,
Is there going to be support for fetching remote images?
As documented in https://cloudinary.com/documentation/fetch_remote_images
To support image moderation, could you please add 'moderation' type in lib/cloudex/uploaded_image.ex
moderation: [String.t] | [] | nil,
https://cloudinary.com/documentation/aws_rekognition_ai_moderation_addon#moderation_response
Thank you very much!
From the documentation I was expecting Cloudex.upload
to return a traditional {:ok, %Cloudex.UploadedImage{}}
. However, the code is returning a list as [ok: %Cloudex.UploadImage{}]
.
Is this expected? I can understand returning a list if a list was passed as input to the upload method, but not in that form.
Currently the duration for an upload request is limited to hackney's default, which is 5 seconds. This means we're seeing a lot of timeouts for uploading large images (or running a dev server on not-the-world's-best-internet).
This code:
https://github.com/smeevil/cloudex/blob/master/lib/cloudex.ex#L33
looks like it should set it to 60 seconds, but it doesn't.
The timeout can be manually overridden by adding timeout
and/or recv_timeout
options here:
https://github.com/smeevil/cloudex/blob/master/lib/cloudex/cloudinary_api.ex#L116-L122
But ideally should be configurable from the calling application.
I suspect this will also affect any of the other API operations that have the manual 60-second Task.await call.
After pulling down a fork of this repo and running mix test
we get 6 test failures:
1) test upload multiple image files (CloudexTest)
test/cloudex/cloudex_test.exs:23
match (=) failed
code: assert [ok: %Cloudex.UploadedImage{}, ok: %Cloudex.UploadedImage{}, ok: %Cloudex.UploadedImage{}] = Cloudex.upload("test/assets/multiple")
right: [
error: "Invalid Signature 9c7baa55fde6dac9e588a15c55d6e08e9805e7ae. String to sign - 'timestamp=1518601215'.",
error: "Invalid Signature 9c7baa55fde6dac9e588a15c55d6e08e9805e7ae. String to sign - 'timestamp=1518601215'.",
error: "Invalid Signature 9c7baa55fde6dac9e588a15c55d6e08e9805e7ae. String to sign - 'timestamp=1518601215'."
]
stacktrace:
test/cloudex/cloudex_test.exs:25: (test)
.
2) test mixed files / urls (CloudexTest)
test/cloudex/cloudex_test.exs:47
match (=) failed
code: assert [ok: %Cloudex.UploadedImage{}, ok: %Cloudex.UploadedImage{}, error: "File nonexistent.png does not exist."] = Cloudex.upload(["./test/assets/test.jpg", "nonexistent.png", "https://cdn.mhpbooks.com/uploads/2014/10/shutterstock_172896005.jpg"])
right: [
error: "Invalid Signature c01b58a90364ab87c87c644d775656cc73acb20b. String to sign - 'timestamp=1518601220'.",
error: "Invalid Signature c01b58a90364ab87c87c644d775656cc73acb20b. String to sign - 'timestamp=1518601220'.",
error: "File nonexistent.png does not exist."
]
stacktrace:
test/cloudex/cloudex_test.exs:49: (test)
3) test upload with tags (CloudexTest)
test/cloudex/cloudex_test.exs:62
** (MatchError) no match of right hand side value: {:error, "Invalid Signature 5aa78950587ba5b644b2013d839533867a4c588b. String to sign - 'tags=foo,bar×tamp=1518601223'."}
code: {:ok, %Cloudex.UploadedImage{tags: ^tags}} =
stacktrace:
test/cloudex/cloudex_test.exs:66: (test)
4) test upload single image file (CloudexTest)
test/cloudex/cloudex_test.exs:17
match (=) failed
code: assert {:ok, %Cloudex.UploadedImage{}} = Cloudex.upload("test/assets/test.jpg")
right: {:error,
"Invalid Signature 9df6d242c28f0ca2c69e8de07dded0667a74ba5e. String to sign - 'timestamp=1518601221'."}
stacktrace:
test/cloudex/cloudex_test.exs:19: (test)
.
5) test upload image url (CloudexTest)
test/cloudex/cloudex_test.exs:33
match (=) failed
code: assert {:ok, %Cloudex.UploadedImage{}} = Cloudex.upload("http://cdn.mhpbooks.com/uploads/2014/10/shutterstock_172896005.jpg")
right: {:error,
"Invalid Signature 2a35268695868d218519042e520d65f7b9a1796a. String to sign - 'timestamp=1518601223'."}
stacktrace:
test/cloudex/cloudex_test.exs:35: (test)
...
6) test upload with phash (CloudexTest)
test/cloudex/cloudex_test.exs:75
** (MatchError) no match of right hand side value: {:error, "Invalid Signature b523ad9a26a6c1f495deb7d4f7162aae2ac465eb. String to sign - 'phash=true×tamp=1518601222'."}
code: {:ok, uploaded_image} = Cloudex.upload(["./test/assets/test.jpg"], %{phash: "true"})
stacktrace:
test/cloudex/cloudex_test.exs:77: (test)
We use cloudex in our phoenix application (it's been very handy, by the way) and a few weeks a go we found a problem trying out phoenix_live_dashboard , more information in:
https://github.com/phoenixframework/phoenix_live_dashboard/issues/156
despite it was a problem with phoenix_live_dashboard the main reason was that cloudex first process is a GenServer instead of a supervisor, is there any plan to change this?
additional information:
Trying to use the phoenix helper snippet I get a compile error:
== Compilation error in file lib/my_app_web/views/cloudex_image_helper.ex ==
** (CompileError) lib/my_app_web/views/cloudex_image_helper.ex:15: undefined function picture/0
I guess that's a leftover and is meant to actually read options[:width]
instead of picture.width
etc.?
Or is picture
some convenience function of Phoenix that I'm missing?
For async delete operations it is necessary to capture the delete event from the Cloudinary webhook notification. Although notification_url
is a supported attribute for the delete url, it is not currently applied when generating the delete url.
I noticed here:
cloudex/lib/cloudex/cloudinary_api.ex
Line 107 in 2245f14
That the upload was done over HTTP and not HTTPS, is there a reason to it?
Do you have any plans to add support for retrieving a resource, in particular from the Admin API? I could certainly just do some quick hacking on my side to make an HTTPoison
request (in my case, to try and retrieve the colors
histogram). But I wanted to see if this was on your radar since I could ostensibly submit a more fully-featured PR here.
Hello, I'm receiving this error and I don't know why.
[info] Running LinkService.Endpoint with Cowboy using http://localhost:4000
Interactive Elixir (1.4.1) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> 08 Mar 16:05:55 - info: compiled 6 files into 2 files, copied 3 in 1.6 sec
[debug] Tzdata polling for update.
[error] GenServer :tzdata_release_updater terminating
** (ArgumentError) argument error
:erlang.hd([])
(tzdata) lib/tzdata/data_loader.ex:29: Tzdata.DataLoader.content_length_from_headers/1
(tzdata) lib/tzdata/data_loader.ex:51: Tzdata.DataLoader.do_latest_file_size/1
(tzdata) lib/tzdata/release_updater.ex:48: Tzdata.ReleaseUpdater.loaded_tzdata_matches_iana_file_size?/0
(tzdata) lib/tzdata/release_updater.ex:36: Tzdata.ReleaseUpdater.poll_for_update/0
(tzdata) lib/tzdata/release_updater.ex:17: Tzdata.ReleaseUpdater.handle_info/2
(stdlib) gen_server.erl:601: :gen_server.try_dispatch/4
(stdlib) gen_server.erl:667: :gen_server.handle_msg/5
(stdlib) proc_lib.erl:247: :proc_lib.init_p_do_apply/3
Last message: :check_if_time_to_update
State: []
Thank you
I need to upload audio file instead of image. Can I do that with cloudex?
I am calling Cloudex.delete(public_id)
and my asset is not deleted. Subsequent calls also return the same success tuple, which seems strange as well.
I looked into the code and it seems like the delete_url
function might be incorrect - Cloudinary's api shows a destroy
slug in the API endpoint.
In regards to PR-45, "Support for videos", I am still seeing this issue - was this PR merged back to master?
And in regards to PR-1, "Upload Audio FIle", Cloudinary's documentation states that we should use resource_type = video
when uploading audio files, such as mp3
files.
Despite my config being as follows
iex(4)> Application.get_env(:cloudex, :cloud_name)
"my_app"
when I run
Cloudex.upload(image_url)
I get {:error, "Invalid cloud_name bmfay"}
What am I missing here?
I was just test driving Cloudex and encountered the following issue:
iex> Cloudex.Url.for("public_id", %{sign_url: true})
** (ArgumentError) argument error
(cloudex) lib/cloudex/url.ex:67: Cloudex.Url.signature_for/3
(cloudex) lib/cloudex/url.ex:52: Cloudex.Url.for/2
It works when I pass it some valid transformation option:
iex> Cloudex.Url.for("public_id", %{fetch_format: "auto", sign_url: true})
"//res.cloudinary.com/...."
I haven't been able to upload images using eager transformations. For my application, I just want to resize images to a certain width by default. Cloudinary seems to support this, and while I understand how to fetch images with certain dimensions using Cloudex.URL.for
, I haven't been able to get resizing to work on upload.
I might be missing something obvious.
Hey all,
I'm unable to upload images from a Plug.Upload struct coming from a multipart form. The error I'm getting is {:error, {:invalid, "<"}}
when using the live api, and [error: {:invalid, "<"}]
when using Cloudex.upload
. Is uploading via Plug.Upload supported or do I need to do something like send it to S3 first and then use that URL?
Hey, this package looks great so far, are there any plans to include Cloudex.delete(public_id)
?
New versions of Phoenix and Ecto are using Jason as the default JSON library. Any interest in making the JSON library configurable? Something like...
config :cloudex, :json_library, Jason
Then, whenever we are calling it, we can do something like...
@json_library Application.get_evn(:cloudex, :json_library)
def foo do
@json_library.decode!(...)
end
According to the documentation, resource_type
should not be included in the signature.
All parameters added to the method call should be included except:
file
,resource_type
and yourapi_key
.
https://cloudinary.com/documentation/upload_images#generating_authentication_signatures
However, currently the API only removes :file
from the data in sign/1
.
Cloudinary has support for video uploads by passing the parameter `"resource_type" => "video".
This requires a different URL for the POST request:
https://api.cloudinary.com/v1_1/<cloud_name>/video/upload
I'm in the process of adding this in our fork, and will push a PR as soon as there is a working version.
If I'm not mistaken https://github.com/smeevil/cloudex/blob/master/lib/cloudex.ex#L6 will not match JPG, GIF, etc.
I'm also curious what the reasoning is for checking that the file has an extension. I'm going to have workaround this in when using Phoenix upload mechanism where the temp file doesn't have an extension.
Correct me if I'm wrong, but it seems that pattern matching for Cloudex.upload/2
departs from Elixir conventions.
Normally, in Elixir we do something like this:
case func do
{:ok, result} ->
# ...
{:error, reason} ->
# ...
end
Cloudex returns a list, however. How come?
case Cloudex.upload("foo.jpg") do
[ok: result] ->
# ...
[error: reason} ->
# ...
end
On this line:
Line 19 in fa1e09b
We return an %Cloudex.UploadedImage{}
when there's only one item.
I do think there may be some deeper issues here, too. For example, the Enum.count(result)
is operating on upload_results ++ invalid_list
.
Great library, thanks! ๐ ๐
Would you consider a PR to accept the cloud name as a parameter to Cloudex.Url.for/2
, leaving the configured value as the default?
I'm currently working around not having this by replacing the cloud name in the returned URL.
[start, rest] = Regex.split(
~r/(http|https):\/\/res.cloudinary.com\/(?<cloud_name>\w+)\/.*/,
url, on: [:cloud_name]
)
Enum.join([start, desired_cloud_name, rest])
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.