Current section
Files
Jump to
Current section
Files
lib/cloud_api/media.ex
defmodule Wax.CloudAPI.Media do
@moduledoc """
Media managment via the Cloud API
"""
alias Wax.CloudAPI
alias Wax.CloudAPI.{Auth, ResponseParser}
@doc """
Downloads a media file from the Whatsapp Cloud server
"""
@spec download(String.t(), Auth.t()) ::
{:ok, file_binary_data :: binary()} | {:error, String.t()}
def download(media_id, %Auth{} = auth) do
with {:ok, media_url} <- get_media_url(media_id, auth) do
download_media(media_url, auth)
end
end
@spec get_media_url(String.t(), Auth.t()) :: {:ok, String.t()} | {:error, String.t()}
defp get_media_url(media_id, auth) do
headers = [Auth.build_header(auth)]
media_id
|> CloudAPI.build_url()
|> HTTPoison.get(headers)
|> case do
{:ok, response} ->
ResponseParser.parse(response, :media_data)
{:error, error} ->
{:error, "Obtaining media URL failed: #{inspect(error)}"}
end
end
@spec download_media(String.t(), Auth.t()) :: {:ok, term()} | {:error, String.t()}
defp download_media(media_url, auth) do
headers = [Auth.build_header(auth)]
media_url
|> HTTPoison.get(headers)
|> case do
{:ok, response} ->
ResponseParser.parse(response, :media_download)
{:error, error} ->
{:error, "Media download failed: #{inspect(error)}"}
end
end
@doc """
Uploads a media file to the Cloud API servers from a path
This returns the Media ID, which is required to send any type
of media files in a message.
"""
@spec upload_from_path(Path.t(), Auth.t()) ::
{:ok, Media.media_id()} | {:error, String.t()}
def upload_from_path(file_path, %Auth{} = auth) do
upload(file_path, file_path, auth)
end
@doc """
Uploads a media file to the Cloud API servers from binary data
This returns the Media ID, which is required to send any type
of media files in a message.
"""
@spec upload_binary(iodata(), String.t(), Auth.t()) ::
{:ok, Media.media_id()} | {:error, String.t()}
def upload_binary(binary_file_content, filename, %Auth{} = auth) do
upload(binary_file_content, filename, auth)
end
@spec upload(Path.t() | iodata(), Path.t(), Auth.t()) ::
{:ok, Media.media_id()} | {:error, String.t()}
defp upload(multipart_data, file_path, auth) do
with :ok <- validate_file(file_path),
{:ok, mime_type} <- detect_mime(file_path) do
filename = Path.basename(file_path)
do_upload(multipart_data, mime_type, filename, auth)
end
end
@spec do_upload(Path.t() | iodata(), String.t(), String.t(), Auth.t()) ::
{:ok, Media.media_id()} | {:error, String.t()}
defp do_upload(multipart_data, mime_type, filename, auth) do
headers = [Auth.build_header(auth)]
data = [
{"file", multipart_data, {"form-data", [name: "file", filename: filename]},
[{"Content-Type", mime_type}]},
{"type", mime_type},
{"messaging_product", "whatsapp"}
]
auth.whatsapp_number_id
|> CloudAPI.build_url("media")
|> HTTPoison.post({:multipart, data}, headers)
|> case do
{:ok, response} ->
ResponseParser.parse(response, :media_upload)
_ ->
{:error, "Media upload failed"}
end
end
@spec validate_file(Path.t()) :: :ok | {:error, String.t()}
defp validate_file(file_path) do
with :ok <- validate_extension(file_path) do
:ok
end
end
@spec validate_extension(Path.t()) :: :ok | {:error, String.t()}
defp validate_extension(file_path) do
case Path.extname(file_path) do
"" ->
error =
"File has no extension. Whatsapp requires a valid extension to process media files"
{:error, error}
_extension ->
:ok
end
end
@spec detect_mime(Path.t()) :: String.t()
defp detect_mime(file_path) do
case Path.extname(file_path) do
".m4a" -> {:ok, "audio/mp4"}
".ogg" -> {:ok, "audio/ogg"}
".mp3" -> {:ok, "audio/mpeg"}
".aac" -> {:ok, "audio/aac"}
".amr" -> {:ok, "audio/amr"}
".opus" -> {:ok, "audio/opus"}
".pdf" -> {:ok, "application/pdf"}
".doc" -> {:ok, "application/msword"}
".docx" -> {:ok, "application/vnd.openxmlformats-officedocument.wordprocessingml.document"}
".ppt" -> {:ok, "application/vnd.ms-powerpoint"}
".pptx" -> {:ok, "application/vnd.openxmlformats-officedocument.presentationml.presentation"}
".xls" -> {:ok, "application/vnd.ms-excel"}
".xlsx" -> {:ok, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"}
".txt" -> {:ok, "text/plain"}
".jpeg" -> {:ok, "image/jpeg"}
".jpg" -> {:ok, "image/jpeg"}
".png" -> {:ok, "image/png"}
".webp" -> {:ok, "image/webp"}
".mp4" -> {:ok, "video/mp4"}
".3gp" -> {:ok, "video/3gpp"}
extension -> {:error, "File #{extension} not supported"}
end
end
end