class Shrine::Plugins::DetermineMimeType::MimeTypeAnalyzer

Constants

MAGIC_NUMBER
SUPPORTED_TOOLS

Public Class Methods

new(tool) click to toggle source
# File lib/shrine/plugins/determine_mime_type.rb, line 79
def initialize(tool)
  raise Error, "unknown mime type analyzer #{tool.inspect}, supported analyzers are: #{SUPPORTED_TOOLS.join(",")}" unless SUPPORTED_TOOLS.include?(tool)

  @tool = tool
end

Public Instance Methods

call(io, options = {}) click to toggle source
# File lib/shrine/plugins/determine_mime_type.rb, line 85
def call(io, options = {})
  mime_type = send(:"extract_with_#{@tool}", io, options)
  io.rewind

  mime_type
end

Private Instance Methods

extract_filename(io) click to toggle source
# File lib/shrine/plugins/determine_mime_type.rb, line 182
def extract_filename(io)
  if io.respond_to?(:original_filename)
    io.original_filename
  elsif io.respond_to?(:path)
    File.basename(io.path)
  end
end
extract_with_content_type(io, options) click to toggle source
# File lib/shrine/plugins/determine_mime_type.rb, line 176
def extract_with_content_type(io, options)
  if io.respond_to?(:content_type) && io.content_type
    io.content_type.split(";").first
  end
end
extract_with_fastimage(io, options) click to toggle source
# File lib/shrine/plugins/determine_mime_type.rb, line 123
def extract_with_fastimage(io, options)
  require "fastimage"

  type = FastImage.type(io)
  return 'image/svg+xml' if type == :svg

  "image/#{type}" if type
end
extract_with_file(io, options) click to toggle source
# File lib/shrine/plugins/determine_mime_type.rb, line 94
def extract_with_file(io, options)
  require "open3"

  return nil if io.eof? # file command returns "application/x-empty" for empty files

  Open3.popen3(*%W[file --mime-type --brief -]) do |stdin, stdout, stderr, thread|
    begin
      IO.copy_stream(io, stdin.binmode)
    rescue Errno::EPIPE
    end
    stdin.close

    status = thread.value

    raise Error, "file command failed to spawn: #{stderr.read}" if status.nil?
    raise Error, "file command failed: #{stderr.read}" unless status.success?

    $stderr.print(stderr.read)

    output = stdout.read.strip

    raise Error, "file command failed: #{output}" if output.include?("cannot open")

    output
  end
rescue Errno::ENOENT
  raise Error, "file command-line tool is not installed"
end
extract_with_filemagic(io, options) click to toggle source
# File lib/shrine/plugins/determine_mime_type.rb, line 132
def extract_with_filemagic(io, options)
  require "filemagic"

  return nil if io.eof? # FileMagic returns "application/x-empty" for empty files

  FileMagic.open(FileMagic::MAGIC_MIME_TYPE) do |filemagic|
    filemagic.buffer(io.read(MAGIC_NUMBER))
  end
end
extract_with_marcel(io, options) click to toggle source
# File lib/shrine/plugins/determine_mime_type.rb, line 149
def extract_with_marcel(io, options)
  require "marcel"

  return nil if io.eof? # marcel returns "application/octet-stream" for empty files

  filename = (options[:filename_fallback] ? extract_filename(io) : nil)
  Marcel::MimeType.for(io, name: filename)
end
extract_with_mime_types(io, options) click to toggle source
# File lib/shrine/plugins/determine_mime_type.rb, line 158
def extract_with_mime_types(io, options)
  require "mime/types"

  if filename = extract_filename(io)
    mime_type = MIME::Types.of(filename).first
    mime_type&.content_type
  end
end
extract_with_mimemagic(io, options) click to toggle source
# File lib/shrine/plugins/determine_mime_type.rb, line 142
def extract_with_mimemagic(io, options)
  require "mimemagic"

  mime = MimeMagic.by_magic(io)
  mime&.type
end
extract_with_mini_mime(io, options) click to toggle source
# File lib/shrine/plugins/determine_mime_type.rb, line 167
def extract_with_mini_mime(io, options)
  require "mini_mime"

  if filename = extract_filename(io)
    info = MiniMime.lookup_by_filename(filename)
    info&.content_type
  end
end