(** Immiche - Immich API client library *) open Printf (** {1 Types} *) type t = { base_url: string; api_key: string; requests_session: Requests.t; } type person = { id: string; name: string; birth_date: string option; thumbnail_path: string; is_hidden: bool; unknown: Jsont.json; } (** {1 Client Creation} *) let create ~requests_session ~base_url ~api_key : t = (* Set API key header on the session *) let requests_session = Requests.set_default_header requests_session "x-api-key" api_key in { base_url; api_key; requests_session } (** {1 JSON Codecs} *) (* Jsont codec for person *) let person_jsont = let make id name birth_date thumbnail_path is_hidden unknown = { id; name; birth_date; thumbnail_path; is_hidden; unknown } in let id p = p.id in let name p = p.name in let birth_date p = p.birth_date in let thumbnail_path p = p.thumbnail_path in let is_hidden p = p.is_hidden in let unknown p = p.unknown in Jsont.Object.map ~kind:"Person" make |> Jsont.Object.mem "id" Jsont.string ~enc:id |> Jsont.Object.mem "name" Jsont.string ~enc:name |> Jsont.Object.opt_mem "birthDate" Jsont.string ~enc:birth_date |> Jsont.Object.mem "thumbnailPath" Jsont.string ~enc:thumbnail_path |> Jsont.Object.mem "isHidden" Jsont.bool ~enc:is_hidden |> Jsont.Object.keep_unknown Jsont.json_mems ~enc:unknown |> Jsont.Object.finish type people_response = { total: int; visible: int; people: person list; unknown: Jsont.json; } (* Jsont codec for people_response *) let people_response_jsont = let make total visible people unknown = { total; visible; people; unknown } in let total r = r.total in let visible r = r.visible in let people r = r.people in let unknown r = r.unknown in Jsont.Object.map ~kind:"PeopleResponse" make |> Jsont.Object.mem "total" Jsont.int ~enc:total |> Jsont.Object.mem "visible" Jsont.int ~enc:visible |> Jsont.Object.mem "people" (Jsont.list person_jsont) ~enc:people |> Jsont.Object.keep_unknown Jsont.json_mems ~enc:unknown |> Jsont.Object.finish (** {1 API Functions} *) let fetch_people { base_url; requests_session; _ } = let open Requests_json_api in let url = base_url / "api/people" in get_json_exn requests_session url people_response_jsont let fetch_person { base_url; requests_session; _ } ~person_id = let open Requests_json_api in let url = base_url / "api/people" / person_id in get_json_exn requests_session url person_jsont let download_thumbnail { base_url; requests_session; _ } ~fs ~person_id ~output_path = try let open Requests_json_api in let url = base_url / "api/people" / person_id / "thumbnail" in match get_result requests_session url with | Error (status, _body) -> Error (`Msg (sprintf "HTTP error: %d" status)) | Ok img_data -> (* Ensure output directory exists *) let dir = Filename.dirname output_path in if not (Sys.file_exists dir) then Unix.mkdir dir 0o755; (* Write the image data to file *) let path = Eio.Path.(fs / output_path) in Eio.Path.save ~create:(`Or_truncate 0o644) path img_data; Ok () with | Failure msg -> Error (`Msg msg) | exn -> Error (`Msg (Printexc.to_string exn)) let search_person { base_url; requests_session; _ } ~name = let open Requests_json_api in let encoded_name = Uri.pct_encode name in let url = sprintf "%s/api/search/person?name=%s" base_url encoded_name in get_json_exn requests_session url (Jsont.list person_jsont)