philomena/lib/philomena_media/mime.ex

67 lines
1.8 KiB
Elixir

defmodule PhilomenaMedia.Mime do
@moduledoc """
Utilities for determining the MIME type of a file via parsing.
Many MIME type libraries assume the MIME type of the file by reading file extensions.
This is inherently unreliable, as many websites disguise the content types of files with
specific names for cost or bandwidth saving reasons. As processing depends on correctly
identifying the type of a file, parsing the file contents is necessary.
"""
@type t :: String.t()
@doc """
Gets the MIME type of the given pathname.
## Examples
iex> PhilomenaMedia.Mime.file("image.png")
{:ok, "image/png"}
iex> PhilomenaMedia.Mime.file("file.txt")
{:unsupported_mime, "text/plain"}
iex> PhilomenaMedia.Mime.file("nonexistent.file")
:error
"""
@spec file(Path.t()) :: {:ok, t()} | {:unsupported_mime, t()} | :error
def file(path) do
System.cmd("file", ["-b", "--mime-type", path])
|> case do
{output, 0} ->
true_mime(String.trim(output))
_error ->
:error
end
end
@doc """
Provides the "true" MIME type of this file.
Some files are identified as a type they should not be based on how they are used by
this library. These MIME types (and their "corrected") versions are:
- `image/svg` -> `image/svg+xml`
- `audio/webm` -> `video/webm`
## Examples
iex> PhilomenaMedia.Mime.file("image.svg")
"image/svg+xml"
iex> PhilomenaMedia.Mime.file("audio.webm")
"video/webm"
"""
@spec true_mime(String.t()) :: {:ok, t()} | {:unsupported_mime, t()}
def true_mime("image/svg"), do: {:ok, "image/svg+xml"}
def true_mime("audio/webm"), do: {:ok, "video/webm"}
def true_mime(mime)
when mime in ~W(image/gif image/jpeg image/png image/svg+xml video/webm),
do: {:ok, mime}
def true_mime(mime), do: {:unsupported_mime, mime}
end