====== Custom MIME Type and associated Application ====== In this article we will explain how to define a **custom MIME Type** with an **associated application**; the purpose is to automatically launch the specified application from the **Firefox browser**, when the user **clicks over an URL** pointing to a specified **content type**. The reference system is a **GNU/Linux** workstation running **Debian 10**. ===== Executing a program from a browser link ===== We want to execute a **local program** when the user **click over an URL** pointing to a **playlist file**. The playlist is a simple text file, containing the filename of the images to be displayed along with geometry data. Geometry data allow to zoom and pan the image on the fly. The program is **[[https://github.com/RigacciOrg/photo-reframe-slideshow|photo-reframe Slideshow]]** and the playlists are saved as **.m3u files**. The ultimate goal of this project is to build a **GNU/Linux based kiosk**, with a **web based interface to select a folder** containing images and start a **slideshow** on it. ===== The Content Type ===== A **GNU/Linux** box with a modern **desktop environment** already knows **several content types**; info about most of them are provided by the **shared-mime-info** package. The **GNOME**, **KDE** and **Xfce** desktop environments use that database. You can use the **xdg-mime** command line tool (from the **xdg-utils** package) to query the database. Here it is an example against a JPEG image: xdg-mime query filetype myphoto.jpg image/jpeg The **xdg-mime** tool uses actually a very complex procedure to determine the content type of the file. The extension of the file (**glob** matching) is part of this procedure, but also the actual content of the file is generally inspected (**magic** detection). On our system it turned out also that **different binaries** are invoked if you are in a **console only** (textual) environment or in a **graphical desktop**. By defining the **XDG_UTILS_DEBUG_LEVEL** environment variable, you can see what binary program is actually used by xdg-mime: XDG_UTILS_DEBUG_LEVEL=10 xdg-mime query filetype myphoto.jpg Running gio info "/home/niccolo/myphoto.jpg" image/jpeg The above example is taken from a **graphic environment**: the program executed is actually **gio**. XDG_UTILS_DEBUG_LEVEL=10 xdg-mime query filetype myphoto.jpg Running mimetype --brief --dereference "/home/niccolo/myphoto.jpg" image/jpeg In the second example, executed into a **text-only console**, the program **mimetype** is executed instead. Fortunately the result is the same: the file is an **image/jpeg** content type. We will create a custom **%%MIME type/subtype%%** to suit our needs. For the **type** we could use //image// one, to mean that each line of the playlist will point to an image file, but we prefer the **application** type, because we want to mean that data will require a specific application to be interpreted. For the **subtype** we will use the **x-** prefix, because the extension is not considered a standard type, so our choice is **x-image-playlist**. ===== MIME Type application/x-image-playlist ===== We create a playlist to experiment with; this is a **playlist.m3u** example: IMG_6602.JPG|4000x2250+0+332 IMG_6605.JPG|2971x1671+796+628 IMG_6606.JPG|4000x2250+0+442 IMG_6610.JPG|3810x2143+90+387 IMG_6615.JPG|2828x1590+547+681 This is the first version of the MIME Type definition, in XML format: M3U Images Playlist We save the file as **photo-reframe.xml** into the **/usr/local/share/mime/packages/** directory, then we update the database of MIME Types with the command: update-mime-database /usr/local/share/mime Several files will be created/updated in that directory, most notably: **globs**, **globs2**, **magic** and **mime.cache**. Here we face **the first problem**: asking the system the type of the playlist.m3u we get **audio/x-mpegurl** instead of **application/x-image-playlist**: xdg-mime query filetype playlist.m3u audio/x-mpegurl This is because the extension **.m3u** is already used by the MIME definition contained into the system file **/usr/share/mime/packages/freedesktop.org.xml** (provided by the **shared-mime-info** package). We can solve the problem by choosing a different filename extension and add another **%%%%** line into the XML definition, but here we want to show how to override the default preference order. So we add the **%%weight="60"%%** attribute to the **glob** tag, knowing that the default weight is 50 (the value must be between 0 and 100). Executing the **update-mime-database** tool, the **globs** and **globs2** files are updated. They contain the mime type and the associated extension; if **globs2** exists, it is preferred because it contains the //weight// data, otherwise **globs** is used (where only the listing order matters). **WARNING**! Not all the MIME query tools behave in the same way: **gio** (from the **libglib2.0-bin** package) and **mimetype** (from the **libfile-mimeinfo-perl** package) are known to return different results for the same file; one reason is that the files in **/usr/local/share/mime/** and **/usr/share/mime/** are not treated in the same way by the two programs. Here we face **the second problem**, despite the .m3u extension is associated to our custom MIME Type with more //weigth// than the default audio/x-mpegurl type, **xdg-mime** returns the same result as above. To get some insight we run the underlying program, which is **gio** (see above about the **XDG_UTILS_DEBUG_LEVEL**): XDG_UTILS_DEBUG_LEVEL=10 xdg-mime query filetype playlist.m3u Running gio info "/home/niccolo/playlist.m3u" audio/x-mpegurl gio info "/home/niccolo/playlist.m3u" | grep content-type standard::content-type: audio/x-mpegurl standard::fast-content-type: application/x-image-playlist Here it is the clue: the **fast-content-type** is the one we want (**application/x-image-playlist**), but the **content-type** is the one which prevails. The //fast-content-type// is determined by just inspecting the filename extension (the **glob**), but the more important //content-type// is determined by inspecting the actual content of the file (the **magic**). There is no choiche: we need to add some info to let the **magic** work. Taking a cue from the **[[wp>M3U#Extended_M3U|Extended M3U]]**, we will use the pseudo comment **%%#EXTM3U-PHOTO-REFRAME%%** as the first line of the playlist. So this is the final version of th XML file to define the MIME type: M3U Images Playlist The **%%%%** tag uses the **match** method: the file will be inspected starting at offset zero, searching for that magic string. The priority value of 60, assures that this match will prevail over the defaults. To update the MIME database another run of **update-mime-database** is required. This is the new version of the playlist: #EXTM3U-PHOTO-REFRAME IMG_6602.JPG|4000x2250+0+332 IMG_6605.JPG|2971x1671+796+628 IMG_6606.JPG|4000x2250+0+442 IMG_6610.JPG|3810x2143+90+387 IMG_6615.JPG|2828x1590+547+681 Finally the MIME type detection works as expected: xdg-mime query filetype playlist.m3u application/x-image-playlist ==== Configuration system-wide or user-wide ==== The MIME related tools search for the MIME database in several directories. On a Debian system there is the directory where offical packages install their definitions, the directory where the system administrator can install local configuration valid for all the users, and the user's personal directory: * **/usr/share/mime/** * **/usr/local/share/mime/** * **$HOME/.local/share/mime/** ===== Application associated to a MIME Type ===== To view if there is an application associated with our custom MIME Type, we can run the following command. No result is returned, as we can expect: xdg-mime query default application/x-image-playlist We check also the behaviour of the **Firefox** browser, we prepare an HTML file containing this (notice the **anchor** tag uses the **type** attribute to declare the proper MIME type): Image Slideshow Once clicked the link, Firefox displays the //Open with...// dialog box suggesting to use **VLC** to open the **MPEG Audio URL**. If you click over the //Other...// option, Firefox says **No applications found for "M3U Images Playlist" files**. The MIME Type is recognized, but the application to handle it is unknown. Now we prepare a file and save it as **/usr/local/share/applications/photo-reframe.desktop**: [Desktop Entry] # The format of this file is specified at # http://standards.freedesktop.org/desktop-entry-spec/1.0/ # The entries are in the order they are listed in version 1.0 Type=Application # This is the version of the spec for this file, not the application version. Version=1.0 Name=Photo-Reframe GenericName=Image Viewer Comment=Slideshow with on-the-fly image cropping Icon=image TryExec=photo-reframe Exec=photo-reframe --fullscreen --play %f Terminal=false MimeType=application/x-image-playlist; # Category entry according to: # http://standards.freedesktop.org/menu-spec/1.0/ Categories=Graphics;2DGraphics;RasterGraphics;Qt; then we run the **update-desktop-database** over that directory (it will update the **mimeinfo.cache** file in the same directory): update-desktop-database /usr/local/share/applications/ Something good has happened; the system knows how to handle that MIME type: xdg-mime query default application/x-image-playlist photo-reframe.desktop After this step, Firefox suggests to use **Photo-Reframe (default)** to handle the link, you can check the box **Do this automatically for files like this from now on** and the associated application will be launched automatically whenever you will click over a link like this. Only after this association, you can open the Firefox **Preferences** => **Applications** and browse for the //M3U Images Playlist// and assign the preferred action. **NOTICE**: You may need to use **Shift-Click** to force the reloading of the link, otherwise Firefox may get the object from the cache, where the MIME type is cached too. ===== Useless recipes ===== There are many recipes to add a new MIME Type and an associated applications, many of them suggest to edit some system files. In our experience it is **absolutely useless to modify** the following files: * /etc/mailcap * /etc/mime.types * $HOME/.mozilla/firefox/.default/mimeTypes.rdf * $HOME/.mozilla/firefox/.default/handlers.json ===== Opening local files from an HTTP page ===== For security reasons a web browser does not allow to open a **%%file://%%** link from a page loaded via a network protocolo, like **%%http://%%**. This is obvious because you don't want to allow a remote sito to fiddle with objects stored on your local disk. But for our application we need this indeed: a page loaded from **%%http://localhost/gallery.php%%** must execute a local program passing a local file path to it, something like **/home/data/directory/playlist.m3u**. The link on the HTML page will look something like this: To bypass the Firefox restriction, you have to create an **user.js** file in your profile directory, something like **$HOME/.mozilla/firefox/3e4ghyw2.default/user.js** (tested with Firefox 68.4): user_pref("capability.policy.policynames", "localfilelinks"); user_pref("capability.policy.localfilelinks.sites", "http://localhost"); user_pref("capability.policy.localfilelinks.checkloaduri.enabled", "allAccess"); ===== Web References ===== * **[[https://wiki.archlinux.org/index.php/XDG_MIME_Applications|XDG MIME Applications]]** * **[[https://stackoverflow.com/questions/63681036/trying-to-create-a-handler-for-maff-files-in-linux|Trying to create a handler for .maff files in Linux]]** * **[[https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types|MIME types (IANA media types)]]** * **[[https://www.december.com/html/spec/mime.html|MIME Types]]** * **[[http://kb.mozillazine.org/Links_to_local_pages_do_not_work|Links to local pages do not work]]**