Class: Aspera::Preview::FileTypes

Inherits:
Object
  • Object
show all
Includes:
Singleton
Defined in:
lib/aspera/preview/file_types.rb

Overview

function conversion_type returns one of the types: CONVERSION_TYPES

Constant Summary collapse

CONVERSION_TYPES =

values for conversion_type : input format

%i[image office pdf plaintext video].freeze

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeFileTypes

Returns a new instance of FileTypes.



63
64
65
# File 'lib/aspera/preview/file_types.rb', line 63

def initialize
  @use_mimemagic = false
end

Instance Attribute Details

#use_mimemagicObject



61
62
63
# File 'lib/aspera/preview/file_types.rb', line 61

def use_mimemagic
  @use_mimemagic
end

Class Method Details

.instanceFileTypes

Returns the singleton instance of FileTypes

Returns:



15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
# File 'lib/aspera/preview/file_types.rb', line 15

class FileTypes
  include Singleton

  # values for conversion_type : input format
  CONVERSION_TYPES = %i[image office pdf plaintext video].freeze

  # Special cases for MIME types
  # spellchecker:disable
  SUPPORTED_MIME_TYPES = {
    'application/json'                   => :plaintext,
    'text/plain'                         => :plaintext,
    'application/pdf'                    => :pdf,
    'audio/ogg'                          => :video,
    'application/mxf'                    => :video,
    'application/mac-binhex40'           => :office,
    'application/msword'                 => :office,
    'application/vnd.ms-excel'           => :office,
    'application/vnd.ms-powerpoint'      => :office,
    'application/rtf'                    => :office,
    'application/x-abiword'              => :office,
    'application/x-mspublisher'          => :office,
    'image/vnd.dxf'                      => :office,
    'image/x-cmx'                        => :office,
    'image/x-freehand'                   => :office,
    'image/x-pict'                       => :office,
    'text/csv'                           => :office,
    'text/html'                          => :office,
    'application/dicom'                  => :image,
    'application/postscript'             => :image,
    'application/vnd.3gpp.pic-bw-small'  => :image,
    'application/vnd.hp-hpgl'            => :image,
    'application/vnd.hp-pcl'             => :image,
    'application/vnd.mobius.msl'         => :image,
    'application/vnd.mophun.certificate' => :image,
    'application/x-director'             => :image,
    'application/x-font-type1'           => :image,
    'application/x-msmetafile'           => :image,
    'application/x-xfig'                 => :image,
    'font/ttf'                           => :image,
    'text/troff'                         => :image,
    'video/x-mng'                        => :image
  }.freeze

  private_constant :SUPPORTED_MIME_TYPES

  # @attr use_mimemagic [Boolean] `true` to use mimemagic to determine real mime type based on file content
  attr_accessor :use_mimemagic

  def initialize
    @use_mimemagic = false
  end

  # @param mimetype [String] mime type
  # @return [NilClass,Symbol] file type, one of enum CONVERSION_TYPES, or nil if not found
  def mime_to_type(mimetype)
    Aspera.assert_type(mimetype, String)
    return SUPPORTED_MIME_TYPES[mimetype] if SUPPORTED_MIME_TYPES.key?(mimetype)
    return :office if mimetype.start_with?('application/vnd.ms-')
    return :office if mimetype.start_with?('application/vnd.openxmlformats-officedocument')
    return :video if mimetype.start_with?('video/')
    return :image if mimetype.start_with?('image/')
    return
  end

  # @param filepath [String] Full path to file
  # @param mimetype [String] MIME typre provided by node API
  # @return file type, one of enum CONVERSION_TYPES
  # @raise [RuntimeError] if no conversion type found
  def conversion_type(filepath, mimetype)
    Log.log.debug{"conversion_type(#{filepath},mime=#{mimetype},magic=#{@use_mimemagic})"}
    # Default type or empty means no type
    mimetype = TYPE_NOT_FOUND if mimetype.nil? || (mimetype.is_a?(String) && mimetype.empty?)
    mimetype = Marcel::MimeType.for(Pathname.new(filepath), name: File.basename(filepath), declared_type: mimetype)
    mimetype = 'text/plain' if mimetype.eql?(TYPE_NOT_FOUND) && ascii_text_file?(filepath)
    raise "no MIME type found for #{File.basename(filepath)}" if mimetype.eql?(TYPE_NOT_FOUND)
    conversion_type = mime_to_type(mimetype)
    raise "no conversion type found for #{File.basename(filepath)}" if conversion_type.nil?
    Log.log.trace1{"conversion_type(#{File.basename(filepath)}): #{conversion_type.class.name} [#{conversion_type}]"}
    return conversion_type
  end

  private

  TYPE_NOT_FOUND = 'application/octet-stream'
  ACCEPT_CTRL_CHARS = [9, 10, 13]

  # Returns true if the file looks like ASCII text (printable ASCII + \t, \r, \n, space).
  # It reads only a small prefix (default: 64KB) and fails fast on the first bad byte.
  def ascii_text_file?(path, sample_size: 64 * 1024)
    File.open(path, 'rb') do |f|
      sample = f.read(sample_size) || ''.b
      sample.each_byte do |b|
        next if b.between?(32, 126) || ACCEPT_CTRL_CHARS.include?(b)
        # Any other control character => not ASCII text
        return false
      end
      true
    end
  end
end

Instance Method Details

#conversion_type(filepath, mimetype) ⇒ Object

Returns file type, one of enum CONVERSION_TYPES.

Parameters:

  • filepath (String)

    Full path to file

  • mimetype (String)

    MIME typre provided by node API

Returns:

  • file type, one of enum CONVERSION_TYPES

Raises:

  • (RuntimeError)

    if no conversion type found



83
84
85
86
87
88
89
90
91
92
93
94
# File 'lib/aspera/preview/file_types.rb', line 83

def conversion_type(filepath, mimetype)
  Log.log.debug{"conversion_type(#{filepath},mime=#{mimetype},magic=#{@use_mimemagic})"}
  # Default type or empty means no type
  mimetype = TYPE_NOT_FOUND if mimetype.nil? || (mimetype.is_a?(String) && mimetype.empty?)
  mimetype = Marcel::MimeType.for(Pathname.new(filepath), name: File.basename(filepath), declared_type: mimetype)
  mimetype = 'text/plain' if mimetype.eql?(TYPE_NOT_FOUND) && ascii_text_file?(filepath)
  raise "no MIME type found for #{File.basename(filepath)}" if mimetype.eql?(TYPE_NOT_FOUND)
  conversion_type = mime_to_type(mimetype)
  raise "no conversion type found for #{File.basename(filepath)}" if conversion_type.nil?
  Log.log.trace1{"conversion_type(#{File.basename(filepath)}): #{conversion_type.class.name} [#{conversion_type}]"}
  return conversion_type
end

#mime_to_type(mimetype) ⇒ NilClass, Symbol

Returns file type, one of enum CONVERSION_TYPES, or nil if not found.

Parameters:

  • mimetype (String)

    mime type

Returns:

  • (NilClass, Symbol)

    file type, one of enum CONVERSION_TYPES, or nil if not found



69
70
71
72
73
74
75
76
77
# File 'lib/aspera/preview/file_types.rb', line 69

def mime_to_type(mimetype)
  Aspera.assert_type(mimetype, String)
  return SUPPORTED_MIME_TYPES[mimetype] if SUPPORTED_MIME_TYPES.key?(mimetype)
  return :office if mimetype.start_with?('application/vnd.ms-')
  return :office if mimetype.start_with?('application/vnd.openxmlformats-officedocument')
  return :video if mimetype.start_with?('video/')
  return :image if mimetype.start_with?('image/')
  return
end