OCaml library for JSONfeed parsing and creation
1(*---------------------------------------------------------------------------
2 Copyright (c) 2024 Anil Madhavapeddy. All rights reserved.
3 SPDX-License-Identifier: ISC
4 ---------------------------------------------------------------------------*)
5
6module Unknown = struct
7 type t = (string * Jsont.json) list
8
9 let empty = []
10 let is_empty = function [] -> true | _ -> false
11end
12
13type t = {
14 url : string;
15 mime_type : string;
16 title : string option;
17 size_in_bytes : int64 option;
18 duration_in_seconds : int option;
19 unknown : Unknown.t;
20}
21
22let make ~url ~mime_type ?title ?size_in_bytes ?duration_in_seconds ?(unknown = Unknown.empty) () =
23 { url; mime_type; title; size_in_bytes; duration_in_seconds; unknown }
24
25let create ~url ~mime_type ?title ?size_in_bytes ?duration_in_seconds () =
26 make ~url ~mime_type ?title ?size_in_bytes ?duration_in_seconds ()
27
28let url t = t.url
29let mime_type t = t.mime_type
30let title t = t.title
31let size_in_bytes t = t.size_in_bytes
32let duration_in_seconds t = t.duration_in_seconds
33let unknown t = t.unknown
34
35let equal a b =
36 a.url = b.url &&
37 a.mime_type = b.mime_type &&
38 a.title = b.title &&
39 a.size_in_bytes = b.size_in_bytes &&
40 a.duration_in_seconds = b.duration_in_seconds
41
42let pp ppf t =
43 (* Extract filename from URL *)
44 let filename =
45 try
46 let parts = String.split_on_char '/' t.url in
47 List.nth parts (List.length parts - 1)
48 with _ -> t.url
49 in
50
51 Format.fprintf ppf "%s (%s" filename t.mime_type;
52
53 (match t.size_in_bytes with
54 | Some size ->
55 let mb = Int64.to_float size /. (1024. *. 1024.) in
56 Format.fprintf ppf ", %.1f MB" mb
57 | None -> ());
58
59 (match t.duration_in_seconds with
60 | Some duration ->
61 let mins = duration / 60 in
62 let secs = duration mod 60 in
63 Format.fprintf ppf ", %dm%ds" mins secs
64 | None -> ());
65
66 Format.fprintf ppf ")"
67
68let jsont =
69 let kind = "Attachment" in
70 let doc = "An attachment object" in
71 let unknown_mems : (Unknown.t, Jsont.json, Jsont.mem list) Jsont.Object.Mems.map =
72 let open Jsont.Object.Mems in
73 let dec_empty () = [] in
74 let dec_add _meta (name : string) value acc =
75 ((name, Jsont.Meta.none), value) :: acc
76 in
77 let dec_finish _meta mems =
78 List.rev_map (fun ((name, _meta), value) -> (name, value)) mems in
79 let enc = {
80 enc = fun (type acc) (f : Jsont.Meta.t -> string -> Jsont.json -> acc -> acc) unknown (acc : acc) ->
81 List.fold_left (fun acc (name, value) ->
82
83 f Jsont.Meta.none name value acc
84 ) acc unknown
85 } in
86 map ~kind:"Unknown members" Jsont.json ~dec_empty ~dec_add ~dec_finish ~enc
87 in
88 let make_obj url mime_type title size_in_bytes duration_in_seconds unknown =
89 make ~url ~mime_type ?title ?size_in_bytes ?duration_in_seconds ~unknown ()
90 in
91 Jsont.Object.map ~kind ~doc make_obj
92 |> Jsont.Object.mem "url" Jsont.string ~enc:url
93 |> Jsont.Object.mem "mime_type" Jsont.string ~enc:mime_type
94 |> Jsont.Object.opt_mem "title" Jsont.string ~enc:title
95 |> Jsont.Object.opt_mem "size_in_bytes" Jsont.int64 ~enc:size_in_bytes
96 |> Jsont.Object.opt_mem "duration_in_seconds" Jsont.int ~enc:duration_in_seconds
97 |> Jsont.Object.keep_unknown unknown_mems ~enc:unknown
98 |> Jsont.Object.finish