Skip to content

Commit

Permalink
Merge pull request #4 from savonet/mime
Browse files Browse the repository at this point in the history
Guess MIME types
  • Loading branch information
smimram authored Jan 29, 2024
2 parents 21d8ce9 + d52c05e commit 3c26ede
Show file tree
Hide file tree
Showing 7 changed files with 91 additions and 0 deletions.
4 changes: 4 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
0.3.0 (unreleased)
=====

- Add basic example.
- Add optional custom parser argument to override the default parsing mechanism.
- Add `MIME` module to guess MIME type of files (#4).

0.2.0 (2023-07-01)
=====

- Add support for FLAC.
- id3v2: use "bpm" instead of "tempo".
- id3v2: convert "tlen" to "duration".
Expand All @@ -14,4 +17,5 @@

0.1.0 (2023-02-08)
=====

- Initial release.
5 changes: 5 additions & 0 deletions examples/dune
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@
(modules dump)
(libraries metadata))

(executable
(name mimetype)
(modules mimetype)
(libraries metadata))

(executable
(name test)
(modules test)
Expand Down
2 changes: 2 additions & 0 deletions examples/mimetype
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
#!/bin/sh
dune exec --no-print-directory ./mimetype.exe -- $@
4 changes: 4 additions & 0 deletions examples/mimetype.ml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
let () =
let fname = Sys.argv.(1) in
let mime = try Metadata.MIME.of_file fname with Not_found -> "unknown" in
print_endline mime
2 changes: 2 additions & 0 deletions src/metadata.ml
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
module CharEncoding = MetadataCharEncoding

module MIME = MetadataMIME

module Make (E : CharEncoding.T) = struct
include MetadataBase
module ID3v1 = MetadataID3v1
Expand Down
10 changes: 10 additions & 0 deletions src/metadata.mli
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,16 @@
(** Functions for handling charset conversion. *)
module CharEncoding = MetadataCharEncoding

(** Guess the MIME type of a file. *)
module MIME : sig
(** Guess the MIME type from file contents. Raises [Not_found] if none was
found. *)
val of_string : string -> string

(** Same as [of_string] but takes a file name as argument. *)
val of_file : string -> string
end

(** Generate metadata parsers given functions for converting charsets. *)
module Make : functor (_ : CharEncoding.T) -> sig
(** Raised when the metadata is not valid. *)
Expand Down
64 changes: 64 additions & 0 deletions src/metadataMIME.ml
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
(** Guess the mime-type of a file. *)

module String = struct
include String

let contains_at offset ~substring s =
let n = String.length substring in
if String.length s < offset + n then false
else String.sub s offset n = substring
end

let prefixes =
[
"ID3", "audio/mpeg";
"OggS", "audio/ogg";
"%PDF-", "application/pdf";
"\137PNG\013\010\026\010", "image/png";
]

let advanced =
let wav s =
String.starts_with ~prefix:"RIFF" s &&
String.contains_at 8 ~substring:"WAVEfmt " s
in
let avi s =
String.starts_with ~prefix:"RIFF" s &&
String.contains_at 8 ~substring:"AVI " s
in
[
wav, "audio/wav";
avi, "video/x-msvideo"
]

let of_string s =
let ans = ref "" in
try
List.iter
(fun (f, mime) ->
if f s then
(
ans := mime;
raise Exit
)
) advanced;
List.iter
(fun (prefix, mime) ->
if String.starts_with ~prefix s then
(
ans := mime;
raise Exit
)
) prefixes;
raise Not_found
with
| Exit -> !ans

let of_file fname =
let len = 16 in
let buf = Bytes.create len in
let ic = open_in fname in
let n = input ic buf 0 len in
let buf = if n = len then buf else Bytes.sub buf 0 n in
let s = Bytes.unsafe_to_string buf in
of_string s

0 comments on commit 3c26ede

Please sign in to comment.