OCaml HTML5 parser/serialiser based on Python's JustHTML

fixes

+93 -82
+17 -34
ocaml-peertube/bin/opeertube.ml
··· 193 handle_api_error @@ fun () -> 194 Eio_main.run @@ fun env -> 195 Eio.Switch.run @@ fun sw -> 196 - let session = Requests.create ~sw env in 197 - let client = Peertube.Client.create ~session ~base_url in 198 if all then begin 199 let videos = 200 Peertube.Client.fetch_all_channel_videos client ?max_pages ··· 226 handle_api_error @@ fun () -> 227 Eio_main.run @@ fun env -> 228 Eio.Switch.run @@ fun sw -> 229 - let session = Requests.create ~sw env in 230 - let client = Peertube.Client.create ~session ~base_url in 231 let response = Peertube.Client.list_videos client ~count ~start () in 232 Fmt.pr "Showing %d of %d videos (offset %d)@.@." 233 (List.length (Peertube.Paginated.data response)) ··· 247 handle_api_error @@ fun () -> 248 Eio_main.run @@ fun env -> 249 Eio.Switch.run @@ fun sw -> 250 - let session = Requests.create ~sw env in 251 - let client = Peertube.Client.create ~session ~base_url in 252 let response = Peertube.Client.search_videos client ~query ~count ~start () in 253 Fmt.pr "Found %d results for '%s' (showing %d, offset %d)@.@." 254 (Peertube.Paginated.total response) ··· 269 handle_api_error @@ fun () -> 270 Eio_main.run @@ fun env -> 271 Eio.Switch.run @@ fun sw -> 272 - let session = Requests.create ~sw env in 273 - let client = Peertube.Client.create ~session ~base_url in 274 let video = Peertube.Client.fetch_video_details client ~uuid () in 275 print_video ~json video 276 ··· 285 handle_api_error @@ fun () -> 286 Eio_main.run @@ fun env -> 287 Eio.Switch.run @@ fun sw -> 288 - let session = Requests.create ~sw env in 289 - let client = Peertube.Client.create ~session ~base_url in 290 let video = Peertube.Client.fetch_video_details client ~uuid () in 291 match 292 Peertube.Client.download_thumbnail client ~video ~output_path:output () ··· 310 handle_api_error @@ fun () -> 311 Eio_main.run @@ fun env -> 312 Eio.Switch.run @@ fun sw -> 313 - let session = Requests.create ~sw env in 314 - let client = Peertube.Client.create ~session ~base_url in 315 let response = Peertube.Client.list_channels client ~count ~start () in 316 Fmt.pr "Showing %d of %d channels (offset %d)@.@." 317 (List.length (Peertube.Paginated.data response)) ··· 331 handle_api_error @@ fun () -> 332 Eio_main.run @@ fun env -> 333 Eio.Switch.run @@ fun sw -> 334 - let session = Requests.create ~sw env in 335 - let client = Peertube.Client.create ~session ~base_url in 336 let response = 337 Peertube.Client.search_channels client ~query ~count ~start () 338 in ··· 355 handle_api_error @@ fun () -> 356 Eio_main.run @@ fun env -> 357 Eio.Switch.run @@ fun sw -> 358 - let session = Requests.create ~sw env in 359 - let client = Peertube.Client.create ~session ~base_url in 360 let channel = Peertube.Client.get_channel client ~handle () in 361 print_channel ~json channel 362 ··· 378 handle_api_error @@ fun () -> 379 Eio_main.run @@ fun env -> 380 Eio.Switch.run @@ fun sw -> 381 - let session = Requests.create ~sw env in 382 - let client = Peertube.Client.create ~session ~base_url in 383 let response = Peertube.Client.list_accounts client ~count ~start () in 384 Fmt.pr "Showing %d of %d accounts (offset %d)@.@." 385 (List.length (Peertube.Paginated.data response)) ··· 399 handle_api_error @@ fun () -> 400 Eio_main.run @@ fun env -> 401 Eio.Switch.run @@ fun sw -> 402 - let session = Requests.create ~sw env in 403 - let client = Peertube.Client.create ~session ~base_url in 404 let account = Peertube.Client.get_account client ~handle () in 405 print_account ~json account 406 ··· 415 handle_api_error @@ fun () -> 416 Eio_main.run @@ fun env -> 417 Eio.Switch.run @@ fun sw -> 418 - let session = Requests.create ~sw env in 419 - let client = Peertube.Client.create ~session ~base_url in 420 let response = 421 Peertube.Client.get_account_videos client ~count ~start ~handle () 422 in ··· 445 handle_api_error @@ fun () -> 446 Eio_main.run @@ fun env -> 447 Eio.Switch.run @@ fun sw -> 448 - let session = Requests.create ~sw env in 449 - let client = Peertube.Client.create ~session ~base_url in 450 let response = Peertube.Client.list_playlists client ~count ~start () in 451 Fmt.pr "Showing %d of %d playlists (offset %d)@.@." 452 (List.length (Peertube.Paginated.data response)) ··· 466 handle_api_error @@ fun () -> 467 Eio_main.run @@ fun env -> 468 Eio.Switch.run @@ fun sw -> 469 - let session = Requests.create ~sw env in 470 - let client = Peertube.Client.create ~session ~base_url in 471 let response = 472 Peertube.Client.search_playlists client ~query ~count ~start () 473 in ··· 490 handle_api_error @@ fun () -> 491 Eio_main.run @@ fun env -> 492 Eio.Switch.run @@ fun sw -> 493 - let session = Requests.create ~sw env in 494 - let client = Peertube.Client.create ~session ~base_url in 495 let playlist = Peertube.Client.get_playlist client ~id () in 496 print_playlist ~json playlist 497 ··· 506 handle_api_error @@ fun () -> 507 Eio_main.run @@ fun env -> 508 Eio.Switch.run @@ fun sw -> 509 - let session = Requests.create ~sw env in 510 - let client = Peertube.Client.create ~session ~base_url in 511 let response = 512 Peertube.Client.get_playlist_videos client ~count ~start ~id () 513 in ··· 549 handle_api_error @@ fun () -> 550 Eio_main.run @@ fun env -> 551 Eio.Switch.run @@ fun sw -> 552 - let session = Requests.create ~sw env in 553 - let client = Peertube.Client.create ~session ~base_url in 554 let config = Peertube.Client.get_config client () in 555 if json then print_json Peertube.Server_config.jsont config 556 else begin ··· 578 handle_api_error @@ fun () -> 579 Eio_main.run @@ fun env -> 580 Eio.Switch.run @@ fun sw -> 581 - let session = Requests.create ~sw env in 582 - let client = Peertube.Client.create ~session ~base_url in 583 let stats = Peertube.Client.get_stats client () in 584 if json then print_json Peertube.Server_stats.jsont stats 585 else begin
··· 193 handle_api_error @@ fun () -> 194 Eio_main.run @@ fun env -> 195 Eio.Switch.run @@ fun sw -> 196 + let client = Peertube.Client.create ~sw env ~base_url in 197 if all then begin 198 let videos = 199 Peertube.Client.fetch_all_channel_videos client ?max_pages ··· 225 handle_api_error @@ fun () -> 226 Eio_main.run @@ fun env -> 227 Eio.Switch.run @@ fun sw -> 228 + let client = Peertube.Client.create ~sw env ~base_url in 229 let response = Peertube.Client.list_videos client ~count ~start () in 230 Fmt.pr "Showing %d of %d videos (offset %d)@.@." 231 (List.length (Peertube.Paginated.data response)) ··· 245 handle_api_error @@ fun () -> 246 Eio_main.run @@ fun env -> 247 Eio.Switch.run @@ fun sw -> 248 + let client = Peertube.Client.create ~sw env ~base_url in 249 let response = Peertube.Client.search_videos client ~query ~count ~start () in 250 Fmt.pr "Found %d results for '%s' (showing %d, offset %d)@.@." 251 (Peertube.Paginated.total response) ··· 266 handle_api_error @@ fun () -> 267 Eio_main.run @@ fun env -> 268 Eio.Switch.run @@ fun sw -> 269 + let client = Peertube.Client.create ~sw env ~base_url in 270 let video = Peertube.Client.fetch_video_details client ~uuid () in 271 print_video ~json video 272 ··· 281 handle_api_error @@ fun () -> 282 Eio_main.run @@ fun env -> 283 Eio.Switch.run @@ fun sw -> 284 + let client = Peertube.Client.create ~sw env ~base_url in 285 let video = Peertube.Client.fetch_video_details client ~uuid () in 286 match 287 Peertube.Client.download_thumbnail client ~video ~output_path:output () ··· 305 handle_api_error @@ fun () -> 306 Eio_main.run @@ fun env -> 307 Eio.Switch.run @@ fun sw -> 308 + let client = Peertube.Client.create ~sw env ~base_url in 309 let response = Peertube.Client.list_channels client ~count ~start () in 310 Fmt.pr "Showing %d of %d channels (offset %d)@.@." 311 (List.length (Peertube.Paginated.data response)) ··· 325 handle_api_error @@ fun () -> 326 Eio_main.run @@ fun env -> 327 Eio.Switch.run @@ fun sw -> 328 + let client = Peertube.Client.create ~sw env ~base_url in 329 let response = 330 Peertube.Client.search_channels client ~query ~count ~start () 331 in ··· 348 handle_api_error @@ fun () -> 349 Eio_main.run @@ fun env -> 350 Eio.Switch.run @@ fun sw -> 351 + let client = Peertube.Client.create ~sw env ~base_url in 352 let channel = Peertube.Client.get_channel client ~handle () in 353 print_channel ~json channel 354 ··· 370 handle_api_error @@ fun () -> 371 Eio_main.run @@ fun env -> 372 Eio.Switch.run @@ fun sw -> 373 + let client = Peertube.Client.create ~sw env ~base_url in 374 let response = Peertube.Client.list_accounts client ~count ~start () in 375 Fmt.pr "Showing %d of %d accounts (offset %d)@.@." 376 (List.length (Peertube.Paginated.data response)) ··· 390 handle_api_error @@ fun () -> 391 Eio_main.run @@ fun env -> 392 Eio.Switch.run @@ fun sw -> 393 + let client = Peertube.Client.create ~sw env ~base_url in 394 let account = Peertube.Client.get_account client ~handle () in 395 print_account ~json account 396 ··· 405 handle_api_error @@ fun () -> 406 Eio_main.run @@ fun env -> 407 Eio.Switch.run @@ fun sw -> 408 + let client = Peertube.Client.create ~sw env ~base_url in 409 let response = 410 Peertube.Client.get_account_videos client ~count ~start ~handle () 411 in ··· 434 handle_api_error @@ fun () -> 435 Eio_main.run @@ fun env -> 436 Eio.Switch.run @@ fun sw -> 437 + let client = Peertube.Client.create ~sw env ~base_url in 438 let response = Peertube.Client.list_playlists client ~count ~start () in 439 Fmt.pr "Showing %d of %d playlists (offset %d)@.@." 440 (List.length (Peertube.Paginated.data response)) ··· 454 handle_api_error @@ fun () -> 455 Eio_main.run @@ fun env -> 456 Eio.Switch.run @@ fun sw -> 457 + let client = Peertube.Client.create ~sw env ~base_url in 458 let response = 459 Peertube.Client.search_playlists client ~query ~count ~start () 460 in ··· 477 handle_api_error @@ fun () -> 478 Eio_main.run @@ fun env -> 479 Eio.Switch.run @@ fun sw -> 480 + let client = Peertube.Client.create ~sw env ~base_url in 481 let playlist = Peertube.Client.get_playlist client ~id () in 482 print_playlist ~json playlist 483 ··· 492 handle_api_error @@ fun () -> 493 Eio_main.run @@ fun env -> 494 Eio.Switch.run @@ fun sw -> 495 + let client = Peertube.Client.create ~sw env ~base_url in 496 let response = 497 Peertube.Client.get_playlist_videos client ~count ~start ~id () 498 in ··· 534 handle_api_error @@ fun () -> 535 Eio_main.run @@ fun env -> 536 Eio.Switch.run @@ fun sw -> 537 + let client = Peertube.Client.create ~sw env ~base_url in 538 let config = Peertube.Client.get_config client () in 539 if json then print_json Peertube.Server_config.jsont config 540 else begin ··· 562 handle_api_error @@ fun () -> 563 Eio_main.run @@ fun env -> 564 Eio.Switch.run @@ fun sw -> 565 + let client = Peertube.Client.create ~sw env ~base_url in 566 let stats = Peertube.Client.get_stats client () in 567 if json then print_json Peertube.Server_stats.jsont stats 568 else begin
+18 -6
ocaml-peertube/lib/peertube.mli
··· 14 let () = 15 Eio_main.run @@ fun env -> 16 Eio.Switch.run @@ fun sw -> 17 - let session = Requests.create ~sw env in 18 - let client = Client.create ~session ~base_url:"https://framatube.org" in 19 20 (* List recent videos *) 21 let videos = Client.list_videos client () in ··· 815 Functions raise {!Client.Api_error} on HTTP errors. 816 817 {[ 818 - let client = Client.create ~session ~base_url:"https://framatube.org" in 819 let videos = Client.list_videos client () in 820 ... 821 ]} *) ··· 828 Encapsulates the HTTP client and base URL for making API requests. In 829 future, this may also contain authentication credentials. *) 830 831 - val create : session:Requests.t -> base_url:string -> t 832 - (** [create ~session ~base_url] creates a new PeerTube API session. 833 834 - @param session HTTP client session from the Requests library 835 @param base_url 836 Base URL of the PeerTube instance (e.g., "https://framatube.org") *) 837
··· 14 let () = 15 Eio_main.run @@ fun env -> 16 Eio.Switch.run @@ fun sw -> 17 + let client = Client.create ~sw env ~base_url:"https://framatube.org" in 18 19 (* List recent videos *) 20 let videos = Client.list_videos client () in ··· 814 Functions raise {!Client.Api_error} on HTTP errors. 815 816 {[ 817 + let client = Client.create ~sw env ~base_url:"https://framatube.org" in 818 let videos = Client.list_videos client () in 819 ... 820 ]} *) ··· 827 Encapsulates the HTTP client and base URL for making API requests. In 828 future, this may also contain authentication credentials. *) 829 830 + val create : 831 + ?session:Requests.t -> 832 + sw:Eio.Switch.t -> 833 + < clock : _ Eio.Time.clock 834 + ; net : _ Eio.Net.t 835 + ; fs : Eio.Fs.dir_ty Eio.Path.t 836 + ; .. > -> 837 + base_url:string -> 838 + t 839 + (** [create ?session ~sw env ~base_url] creates a new PeerTube API session. 840 841 + If [session] is not provided, a new HTTP session is created using the 842 + given switch and environment. If [session] is provided, it is reused. 843 + 844 + @param session Optional existing HTTP client session to reuse 845 + @param sw Eio switch for resource management 846 + @param env Eio environment with clock, net, and fs capabilities 847 @param base_url 848 Base URL of the PeerTube instance (e.g., "https://framatube.org") *) 849
+6 -1
ocaml-peertube/lib/peertube_client.ml
··· 3 type t = { session : Requests.t; base_url : string } 4 (** Session type encapsulating HTTP client and base URL. *) 5 6 - let create ~session ~base_url = { session; base_url } 7 let base_url t = t.base_url 8 let http_session t = t.session 9 let log_src = Logs.Src.create "peertube" ~doc:"PeerTube API client"
··· 3 type t = { session : Requests.t; base_url : string } 4 (** Session type encapsulating HTTP client and base URL. *) 5 6 + let create ?session ~sw env ~base_url = 7 + let session = match session with 8 + | Some s -> s 9 + | None -> Requests.create ~sw env 10 + in 11 + { session; base_url } 12 let base_url t = t.base_url 13 let http_session t = t.session 14 let log_src = Logs.Src.create "peertube" ~doc:"PeerTube API client"
+16 -3
ocaml-peertube/lib/peertube_client.mli
··· 11 Encapsulates the HTTP client and base URL for making API requests. In 12 future, this may also contain authentication credentials. *) 13 14 - val create : session:Requests.t -> base_url:string -> t 15 - (** [create ~session ~base_url] creates a new PeerTube API session. 16 17 - @param session HTTP client session from the Requests library 18 @param base_url 19 Base URL of the PeerTube instance (e.g., "https://framatube.org") *) 20
··· 11 Encapsulates the HTTP client and base URL for making API requests. In 12 future, this may also contain authentication credentials. *) 13 14 + val create : 15 + ?session:Requests.t -> 16 + sw:Eio.Switch.t -> 17 + < clock : _ Eio.Time.clock 18 + ; net : _ Eio.Net.t 19 + ; fs : Eio.Fs.dir_ty Eio.Path.t 20 + ; .. > -> 21 + base_url:string -> 22 + t 23 + (** [create ?session ~sw env ~base_url] creates a new PeerTube API session. 24 + 25 + If [session] is not provided, a new HTTP session is created using the 26 + given switch and environment. If [session] is provided, it is reused. 27 28 + @param session Optional existing HTTP client session to reuse 29 + @param sw Eio switch for resource management 30 + @param env Eio environment with clock, net, and fs capabilities 31 @param base_url 32 Base URL of the PeerTube instance (e.g., "https://framatube.org") *) 33
+17 -20
ocaml-requests/lib/signature.ml
··· 409 (* Context *) 410 (* ========================================================================= *) 411 412 - module Context = struct 413 - (** Request context for signature computation. *) 414 - type request_ctx = { 415 - method_ : Method.t; (** The HTTP method *) 416 - uri : Uri.t; (** The request URI *) 417 - headers : Headers.t; (** The request headers *) 418 - } 419 420 - (** Response context for signature computation. *) 421 - type response_ctx = { 422 - status : int; (** The HTTP status code *) 423 - headers : Headers.t; (** The response headers *) 424 - request : request_ctx option; (** The original request, if available *) 425 - } 426 427 - (** Message context (request or response). *) 428 type t = [ 429 - | `Request of request_ctx (** A request context *) 430 - | `Response of response_ctx (** A response context *) 431 ] 432 433 let request ~method_ ~uri ~headers : t = ··· 517 518 let resolve_component (ctx : Context.t) (component : Component.t) = 519 let get_headers : Context.t -> Headers.t = function 520 - | `Request r -> r.Context.headers 521 - | `Response r -> r.Context.headers 522 in 523 let get_request_headers : Context.t -> Headers.t option = function 524 - | `Request r -> Some r.Context.headers 525 - | `Response (r : Context.response_ctx) -> Option.map (fun (req : Context.request_ctx) -> req.headers) r.request 526 in 527 match component with 528 | `Derived (d, params) ->
··· 409 (* Context *) 410 (* ========================================================================= *) 411 412 + type request_ctx = { 413 + method_ : Method.t; 414 + uri : Uri.t; 415 + headers : Headers.t; 416 + } 417 418 + type response_ctx = { 419 + status : int; 420 + headers : Headers.t; 421 + request : request_ctx option; 422 + } 423 424 + module Context = struct 425 type t = [ 426 + | `Request of request_ctx 427 + | `Response of response_ctx 428 ] 429 430 let request ~method_ ~uri ~headers : t = ··· 514 515 let resolve_component (ctx : Context.t) (component : Component.t) = 516 let get_headers : Context.t -> Headers.t = function 517 + | `Request r -> r.headers 518 + | `Response r -> r.headers 519 in 520 let get_request_headers : Context.t -> Headers.t option = function 521 + | `Request r -> Some r.headers 522 + | `Response (r : response_ctx) -> Option.map (fun (req : request_ctx) -> req.headers) r.request 523 in 524 match component with 525 | `Derived (d, params) ->
+16 -15
ocaml-requests/lib/signature.mli
··· 273 274 (** {1 Signing Context} *) 275 276 - module Context : sig 277 - (** Context for resolving message components. *) 278 279 - type request_ctx = { 280 - method_ : Method.t; (** The HTTP method *) 281 - uri : Uri.t; (** The request URI *) 282 - headers : Headers.t; (** The request headers *) 283 - } 284 - (** Request context for signature computation. *) 285 286 - type response_ctx = { 287 - status : int; (** The HTTP status code *) 288 - headers : Headers.t; (** The response headers *) 289 - request : request_ctx option; (** The original request, if available *) 290 - } 291 - (** Response context for signature computation. *) 292 - 293 type t = [ 294 | `Request of request_ctx 295 | `Response of response_ctx
··· 273 274 (** {1 Signing Context} *) 275 276 + type request_ctx = { 277 + method_ : Method.t; 278 + uri : Uri.t; 279 + headers : Headers.t; 280 + } 281 + (** Request context for signature computation. 282 + Contains the HTTP method, request URI, and request headers. *) 283 284 + type response_ctx = { 285 + status : int; 286 + headers : Headers.t; 287 + request : request_ctx option; 288 + } 289 + (** Response context for signature computation. 290 + Contains the HTTP status code, response headers, and optionally the original request. *) 291 292 + (** Context for resolving message components. *) 293 + module Context : sig 294 type t = [ 295 | `Request of request_ctx 296 | `Response of response_ctx
+1 -1
ocaml-zulip/lib/zulip/channel.mli
··· 121 (** Email notification setting. *) 122 123 val wildcard_mentions_notify : t -> bool option 124 - (** Whether to notify on @all/@everyone mentions. *) 125 126 val jsont : t Jsont.t 127 (** Jsont codec for subscription. *)
··· 121 (** Email notification setting. *) 122 123 val wildcard_mentions_notify : t -> bool option 124 + (** Whether to notify on \@all/\@everyone mentions. *) 125 126 val jsont : t Jsont.t 127 (** Jsont codec for subscription. *)
+2 -2
ocaml-zulip/lib/zulip/message_flag.mli
··· 18 19 type t = 20 [ modifiable 21 - | `Mentioned (** User was @-mentioned in the message *) 22 - | `Wildcard_mentioned (** User was mentioned via @all/@everyone *) 23 | `Has_alert_word (** Message contains one of user's alert words *) 24 | `Historical (** Message predates user joining the stream *) ] 25 (** All possible message flags. *)
··· 18 19 type t = 20 [ modifiable 21 + | `Mentioned (** User was \@-mentioned in the message *) 22 + | `Wildcard_mentioned (** User was mentioned via \@all/\@everyone *) 23 | `Has_alert_word (** Message contains one of user's alert words *) 24 | `Historical (** Message predates user joining the stream *) ] 25 (** All possible message flags. *)