discourse / mini_mime

minimal mime type library
MIT License
95 stars 34 forks source link

webm and wmv miscategorized as video instead of audio #26

Open martinvonwittich opened 5 years ago

martinvonwittich commented 5 years ago

Redmine uses mini_mime to determine whether an uploaded media file is an audio or a video file to decide whether to use a <audio> or <video> tag in the HTML.

Unfortunately, both .webm and .wmv files are "miscategorized" as audio by mini_mime:

https://github.com/discourse/mini_mime/blob/master/lib/db/ext_mime.db#L1048

webm        audio/webm                                                                base64          

https://github.com/discourse/mini_mime/blob/master/lib/db/ext_mime.db#L1064

wmv         audio/x-ms-wmv                                                            base64          

Though this isn't strictly wrong (webm is a container format for both audio and video; wmv is intended for video, but of course also can contain audio), it is IMO not what one would expect. In this case it's causing Redmine to attempt to play these kinds of video files with an <audio> tag, which forces users to download the files to actually see the video: https://www.redmine.org/issues/31553

For webm, this has been overridden in Redmine, but today I've stumbled over the same issue with wmv. I thought that MIME::Types solved this pretty elegantly by returning an array of matching MIME types, but apparently that library suffers from memory usage issues which led to Redmine replacing it with mini_mime.

I'm not sure what the best solution would be here. I'm pretty new to Ruby and all of these libraries, but from what I can gather, mini_mime uses MIME::Types internally to generate a list of extension -> MIME types mappings, and lets priority_compare decide which MIME type will win when there are multiple. But there is not real concept of "priority" in MIME::Types in the sense of that e.g. video/webm can have a higher priority than audio/webm. priority_compare essentially just simplifies the MIME types, and then compares them alphabetically. This means that audio will always win over video:

irb(main):005:0> MIME::Types.type_for('test.wmv').each { |m| pp m.simplified }; nil
"audio/x-ms-wmv"
"video/x-ms-wmv"
=> nil

IMO this is a fundamental problem which cannot be easily solved, and the proper fix would be to return multiple MIME types for a given extension (#25).

SamSaffron commented 5 years ago

Fundamentally you are going to end up picking "one thing" so the interface of "please give me a mime type for X" is still correct imo.

I do support adding a clear interface for adding overrides provided it has zero cost when unused.

halostatue commented 2 years ago

I am exploring improving extension priority to fix this sort of issue. See mime-types/ruby-mime-types#161. This is not going to be quick, and it may be a bit longer to get it in mini_mime, but since I implemented mime-types/mime-types-data#47, I might be able to get something that is testable sooner once I figure it out.

halostatue commented 2 years ago

The tools for this are in process. I’m going to need to find some Ruby community volunteers to review the changes here, but the main changes are https://github.com/mime-types/mime-types-data/tree/priority-extensions and are supported https://github.com/mime-types/ruby-mime-types/tree/priority-extensions. The description of how this affects mini_mime is found in #44.

If you want wmv and webm to represent video, I will need an issue or PR on mime-types-data that recommends these changes. Since there’s almost no authority on this, it would not take much convincing, but I do want to see why we should skew things one way or another. In my experience, when I was using Windows, wmv were mostly audio files. I have no experience with webm files. IIRC, wmv aren’t backed by registered types, but webm are and the registrations for the types include webm as valid for both types.