OCaml library for JSONfeed parsing and creation
1(** Feed items in a JSON Feed.
2
3 An item represents a single entry in a feed, such as a blog post, podcast episode,
4 or microblog entry. Each item must have a unique identifier and content.
5
6 @see <https://www.jsonfeed.org/version/1.1/> JSON Feed Specification *)
7
8
9(** The type representing a feed item. *)
10type t
11
12(** Content representation for an item.
13
14 The JSON Feed specification requires that each item has at least one
15 form of content. This type enforces that requirement at compile time.
16
17 - [`Html s]: Item has HTML content only
18 - [`Text s]: Item has plain text content only
19 - [`Both (html, text)]: Item has both HTML and plain text versions *)
20type content =
21 [ `Html of string
22 | `Text of string
23 | `Both of string * string
24 ]
25
26
27(** {1 Construction} *)
28
29(** [create ~id ~content ?url ?external_url ?title ?summary ?image ?banner_image
30 ?date_published ?date_modified ?authors ?tags ?language ?attachments ()]
31 creates a feed item.
32
33 @param id Unique identifier for the item (required). Should be a full URL if possible.
34 @param content The item's content in HTML and/or plain text (required)
35 @param url Permalink to the item
36 @param external_url URL of an external resource (useful for linkblogs)
37 @param title Plain text title of the item
38 @param summary Plain text summary/excerpt of the item
39 @param image URL of the main featured image for the item
40 @param banner_image URL of a banner image for the item
41 @param date_published Publication date/time (RFC 3339 format)
42 @param date_modified Last modification date/time (RFC 3339 format)
43 @param authors Item-specific authors (overrides feed-level authors)
44 @param tags Plain text tags/categories for the item
45 @param language Primary language of the item (RFC 5646 format, e.g. ["en-US"])
46 @param attachments Related resources like audio files or downloads
47
48 {b Examples:}
49 {[
50 (* Simple blog post *)
51 let item = Item.create
52 ~id:"https://example.com/posts/42"
53 ~content:(`Html "<p>Hello, world!</p>")
54 ~title:"My First Post"
55 ~url:"https://example.com/posts/42" ()
56
57 (* Microblog entry with plain text *)
58 let item = Item.create
59 ~id:"https://example.com/micro/123"
60 ~content:(`Text "Just posted a new photo!")
61 ~date_published:(Ptime.of_float_s (Unix.time ()) |> Option.get) ()
62
63 (* Article with both HTML and plain text *)
64 let item = Item.create
65 ~id:"https://example.com/article/99"
66 ~content:(`Both ("<p>Rich content</p>", "Plain version"))
67 ~title:"Article Title"
68 ~tags:["ocaml"; "programming"] ()
69
70 (* Podcast episode with attachment *)
71 let attachment = Attachment.create
72 ~url:"https://example.com/ep1.mp3"
73 ~mime_type:"audio/mpeg"
74 ~duration_in_seconds:1800 () in
75 let item = Item.create
76 ~id:"https://example.com/podcast/1"
77 ~content:(`Html "<p>Episode description</p>")
78 ~title:"Episode 1"
79 ~attachments:[attachment] ()
80 ]} *)
81val create :
82 id:string ->
83 content:content ->
84 ?url:string ->
85 ?external_url:string ->
86 ?title:string ->
87 ?summary:string ->
88 ?image:string ->
89 ?banner_image:string ->
90 ?date_published:Ptime.t ->
91 ?date_modified:Ptime.t ->
92 ?authors:Author.t list ->
93 ?tags:string list ->
94 ?language:string ->
95 ?attachments:Attachment.t list ->
96 unit ->
97 t
98
99
100(** {1 Accessors} *)
101
102(** [id t] returns the item's unique identifier. *)
103val id : t -> string
104
105(** [content t] returns the item's content. *)
106val content : t -> content
107
108(** [url t] returns the item's permalink URL, if set. *)
109val url : t -> string option
110
111(** [external_url t] returns the external resource URL, if set. *)
112val external_url : t -> string option
113
114(** [title t] returns the item's title, if set. *)
115val title : t -> string option
116
117(** [summary t] returns the item's summary, if set. *)
118val summary : t -> string option
119
120(** [image t] returns the item's featured image URL, if set. *)
121val image : t -> string option
122
123(** [banner_image t] returns the item's banner image URL, if set. *)
124val banner_image : t -> string option
125
126(** [date_published t] returns the item's publication date, if set. *)
127val date_published : t -> Ptime.t option
128
129(** [date_modified t] returns the item's last modification date, if set. *)
130val date_modified : t -> Ptime.t option
131
132(** [authors t] returns the item's authors, if set. *)
133val authors : t -> Author.t list option
134
135(** [tags t] returns the item's tags, if set. *)
136val tags : t -> string list option
137
138(** [language t] returns the item's language code, if set. *)
139val language : t -> string option
140
141(** [attachments t] returns the item's attachments, if set. *)
142val attachments : t -> Attachment.t list option
143
144
145(** {1 Content Helpers} *)
146
147(** [content_html t] extracts HTML content from the item.
148
149 Returns [Some html] if the item has HTML content (either [Html] or [Both]),
150 [None] otherwise. *)
151val content_html : t -> string option
152
153(** [content_text t] extracts plain text content from the item.
154
155 Returns [Some text] if the item has plain text content (either [Text] or [Both]),
156 [None] otherwise. *)
157val content_text : t -> string option
158
159
160(** {1 Comparison} *)
161
162(** [equal a b] tests equality between two items.
163
164 Items are considered equal if they have the same ID. *)
165val equal : t -> t -> bool
166
167(** [compare a b] compares two items by their publication dates.
168
169 Items without publication dates are considered older than items with dates.
170 Useful for sorting items chronologically. *)
171val compare : t -> t -> int
172
173
174(** {1 Pretty Printing} *)
175
176(** [pp ppf t] pretty prints an item to the formatter.
177
178 The output is human-readable and suitable for debugging.
179
180 {b Example output:}
181 {v [2024-11-03] My First Post (https://example.com/posts/42) v} *)
182val pp : Format.formatter -> t -> unit
183
184(** [pp_content ppf content] pretty prints content to the formatter.
185
186 {b Example output:}
187 {v HTML (123 chars) v}
188 {v Text (56 chars) v}
189 {v Both (HTML: 123 chars, Text: 56 chars) v} *)
190val pp_content : Format.formatter -> content -> unit