Immich bindings and CLI in OCaml
at main 80 lines 3.1 kB view raw
1(*--------------------------------------------------------------------------- 2 Copyright (c) 2025 Anil Madhavapeddy. All rights reserved. 3 SPDX-License-Identifier: ISC 4 ---------------------------------------------------------------------------*) 5 6open Cmdliner 7 8(* Styled output helpers *) 9let header_style = Fmt.(styled `Bold string) 10let id_style = Fmt.(styled `Faint string) 11let name_style = Fmt.(styled (`Fg `Cyan) string) 12let count_style = Fmt.(styled (`Fg `Green) int) 13let shared_style = Fmt.(styled (`Fg `Yellow) string) 14 15(* List albums - using low-level API since get_all_albums returns array but typed as single *) 16 17let list_action ~requests_config ~profile ~shared env = 18 Immich_auth.Error.wrap (fun () -> 19 Immich_auth.Cmd.with_client ~requests_config ?profile (fun _fs client -> 20 let api = Immich_auth.Client.client client in 21 let session = Immich.session api in 22 let base_url = Immich.base_url api in 23 let query = match shared with 24 | None -> "" 25 | Some true -> "?shared=true" 26 | Some false -> "?shared=false" 27 in 28 let url = base_url ^ "/albums" ^ query in 29 let response = Requests.get session url in 30 if Requests.Response.ok response then begin 31 let json = Requests.Response.json response in 32 let albums = Openapi.Runtime.Json.decode_json_exn 33 (Jsont.list Immich.Album.ResponseDto.jsont) json in 34 if albums = [] then 35 Fmt.pr "%a@." Fmt.(styled `Faint string) "No albums found." 36 else begin 37 Fmt.pr "%a@." header_style "Albums:"; 38 List.iter (fun album -> 39 let is_shared = Immich.Album.ResponseDto.shared album in 40 Fmt.pr " %a %a (%a assets)%a@." 41 id_style (Immich.Album.ResponseDto.id album) 42 name_style (Immich.Album.ResponseDto.album_name album) 43 count_style (Immich.Album.ResponseDto.asset_count album) 44 shared_style (if is_shared then " (shared)" else "") 45 ) albums 46 end 47 end else begin 48 raise (Openapi.Runtime.Api_error { 49 operation = "get_all_albums"; 50 method_ = "GET"; 51 url; 52 status = Requests.Response.status_code response; 53 body = Requests.Response.text response; 54 parsed_body = None; 55 }) 56 end 57 ) env 58 ) 59 60let shared_arg = 61 let doc = "Filter by shared status. Use --shared for shared albums, --no-shared for owned only." in 62 Arg.(value & opt (some bool) None & info ["shared"] ~doc) 63 64let list_cmd env fs = 65 let doc = "List all albums." in 66 let info = Cmd.info "list" ~doc in 67 let list' (style_renderer, level) requests_config profile shared = 68 Immich_auth.Cmd.setup_logging_with_config style_renderer level requests_config; 69 list_action ~requests_config ~profile ~shared env 70 in 71 Cmd.v info Term.(const list' $ Immich_auth.Cmd.setup_logging $ Immich_auth.Cmd.requests_config_term fs $ Immich_auth.Cmd.profile_arg $ shared_arg) 72 73(* Albums command group *) 74 75let albums_cmd env fs = 76 let doc = "Album commands." in 77 let info = Cmd.info "albums" ~doc in 78 Cmd.group info 79 [ list_cmd env fs 80 ]