OCaml client for the LinkedIn Voyager API
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

fix(lint): resolve E331 redundant function prefixes across hostname, linkedin, matter, mbr, gpt

Remove make_/get_/find_ prefixes from 21 functions: find_invalid_char,
make_api, make_cookie, get_json, get_keychain_passphrase,
get_all_linkedin_cookies, get_linkedin_cookies, get_int, get_uint,
get_bytes, get_partition_info, make_new_partition, make_new_mbr,
get_u8, get_u16_le, get_u32_le, get_ok, and related callers.

+30 -32
+7 -9
bin/main.ml
··· 66 66 | _ -> ( 67 67 (* Fall back to Chrome — extract ALL cookies *) 68 68 let proc_mgr = Eio.Stdenv.process_mgr env in 69 - match 70 - Linkedin.Chrome_cookies.get_all_linkedin_cookies proc_mgr fs 71 - with 69 + match Linkedin.Chrome_cookies.all_linkedin_cookies proc_mgr fs with 72 70 | Ok cookies -> ( 73 71 let li_at_v = List.assoc_opt "li_at" cookies in 74 72 let jsessionid_v = List.assoc_opt "JSESSIONID" cookies in ··· 171 169 172 170 let print_error e = Fmt.epr "Error: %a@." Linkedin.Api.pp_error e 173 171 174 - let make_api ~sw env li_at jsessionid = 172 + let api ~sw env li_at jsessionid = 175 173 let li_at, jsessionid, extra_cookies = resolve_cookies env li_at jsessionid in 176 174 let api = Linkedin.Api.v ~sw env ~li_at ~jsessionid in 177 175 Linkedin.Api.add_cookies api extra_cookies; ··· 182 180 let me_cmd = 183 181 let run' () li_at jsessionid () = 184 182 run @@ fun ~sw env -> 185 - let api = make_api ~sw env li_at jsessionid in 183 + let api = api ~sw env li_at jsessionid in 186 184 match Linkedin.Api.me api with 187 185 | Ok p -> print_profile p 188 186 | Error e -> print_error e ··· 206 204 exit 1 207 205 | Ok public_id -> ( 208 206 run @@ fun ~sw env -> 209 - let api = make_api ~sw env li_at jsessionid in 207 + let api = api ~sw env li_at jsessionid in 210 208 match Linkedin.Api.profile ~public_id api with 211 209 | Ok p -> print_profile p 212 210 | Error e -> print_error e) ··· 242 240 exit 1 243 241 | Ok profile_id -> ( 244 242 run @@ fun ~sw env -> 245 - let api = make_api ~sw env li_at jsessionid in 243 + let api = api ~sw env li_at jsessionid in 246 244 match Linkedin.Api.posts ~count ~profile_id api with 247 245 | Ok posts -> 248 246 let n = List.length posts in ··· 275 273 let proc_mgr = Eio.Stdenv.process_mgr env in 276 274 let fs = Eio.Stdenv.fs env in 277 275 let xdg = Xdge.create fs "linkedin" in 278 - match Linkedin.Chrome_cookies.get_linkedin_cookies proc_mgr fs with 276 + match Linkedin.Chrome_cookies.linkedin_cookies proc_mgr fs with 279 277 | Ok (li_at, jsessionid) -> 280 278 save_cookies xdg ~li_at ~jsessionid; 281 279 let path = Eio.Path.native_exn (cookies_path xdg) in ··· 303 301 exit 1 304 302 | Ok urn -> ( 305 303 run @@ fun ~sw env -> 306 - let api = make_api ~sw env li_at jsessionid in 304 + let api = api ~sw env li_at jsessionid in 307 305 match Linkedin.Api.post ~urn api with 308 306 | Ok p -> print_post p 309 307 | Error e -> print_error e)
+9 -9
lib/api.ml
··· 33 33 let n = String.length s in 34 34 if n >= 2 && s.[0] = '"' && s.[n - 1] = '"' then String.sub s 1 (n - 2) else s 35 35 36 - let make_cookie ~now ~name ~value = 36 + let cookie ~now ~name ~value = 37 37 Cookeio.v ~domain:"linkedin.com" ~path:"/" ~name ~value ~secure:true 38 38 ~http_only:true ~creation_time:now ~last_access:now () 39 39 ··· 59 59 in 60 60 (* Add our auth cookies to the session's cookie jar *) 61 61 let jar = Requests.cookies session in 62 - Cookeio_jar.add_cookie jar (make_cookie ~now ~name:"li_at" ~value:li_at); 62 + Cookeio_jar.add_cookie jar (cookie ~now ~name:"li_at" ~value:li_at); 63 63 Cookeio_jar.add_cookie jar 64 - (make_cookie ~now ~name:"JSESSIONID" ~value:(Fmt.str "\"%s\"" csrf_token)); 64 + (cookie ~now ~name:"JSESSIONID" ~value:(Fmt.str "\"%s\"" csrf_token)); 65 65 { session; now } 66 66 67 67 let add_cookies t cookies = 68 68 let jar = Requests.cookies t.session in 69 69 List.iter 70 70 (fun (name, value) -> 71 - Cookeio_jar.add_cookie jar (make_cookie ~now:t.now ~name ~value)) 71 + Cookeio_jar.add_cookie jar (cookie ~now:t.now ~name ~value)) 72 72 cookies 73 73 74 74 let pp ppf _t = Fmt.pf ppf "LinkedIn(session)" ··· 103 103 cookies` to refresh.") 104 104 | exn -> Error (`Network_error (Printexc.to_string exn)) 105 105 106 - let get_json t path codec = 106 + let json t path codec = 107 107 match get t path with 108 108 | Error _ as e -> e 109 109 | Ok body -> ( ··· 118 118 119 119 (** {1 API endpoints} *) 120 120 121 - let me t = get_json t "/voyager/api/me" Profile.me_jsont 121 + let me t = json t "/voyager/api/me" Profile.me_jsont 122 122 123 123 let profile ~public_id t = 124 124 let path = 125 125 Fmt.str "/voyager/api/identity/profiles/%s/profileView" public_id 126 126 in 127 - get_json t path Profile.jsont 127 + json t path Profile.jsont 128 128 129 129 let posts ?(start = 0) ?(count = 10) ~profile_id t = 130 130 let path = ··· 132 132 "/voyager/api/feed/updates?profileId=%s&q=memberShareFeed&moduleKey=member-share&count=%d&start=%d" 133 133 profile_id count start 134 134 in 135 - get_json t path Post.feed_jsont 135 + json t path Post.feed_jsont 136 136 137 137 let url_encode s = 138 138 let buf = Buffer.create (String.length s * 3) in ··· 147 147 148 148 let post ~urn t = 149 149 let path = Fmt.str "/voyager/api/feed/updates/%s" (url_encode urn) in 150 - get_json t path Post.normalized_jsont 150 + json t path Post.normalized_jsont
+7 -7
lib/chrome_cookies.ml
··· 16 16 17 17 (** {1 Chrome cookie DB path} *) 18 18 19 - let chrome_cookies_path () = 19 + let path () = 20 20 let home = Sys.getenv "HOME" in 21 21 Fmt.str "%s/Library/Application Support/Google/Chrome/Default/Cookies" home 22 22 23 23 (** {1 Keychain passphrase} *) 24 24 25 - let get_keychain_passphrase proc_mgr = 25 + let keychain_passphrase proc_mgr = 26 26 try 27 27 let passphrase = 28 28 Eio.Process.parse_out proc_mgr Eio.Buf_read.take_all ··· 136 136 (** {1 SQLite query — all LinkedIn cookies} *) 137 137 138 138 let query_all_cookies proc_mgr fs = 139 - let db_path = chrome_cookies_path () in 139 + let db_path = path () in 140 140 try 141 141 let tmp = temp_db_path () in 142 142 Eio.Process.run proc_mgr [ "cp"; db_path; tmp ]; ··· 194 194 195 195 (** {1 High-level API} *) 196 196 197 - let get_all_linkedin_cookies proc_mgr fs = 198 - match get_keychain_passphrase proc_mgr with 197 + let all_linkedin_cookies proc_mgr fs = 198 + match keychain_passphrase proc_mgr with 199 199 | Error _ as e -> e 200 200 | Ok passphrase -> ( 201 201 let key = derive_key passphrase in ··· 203 203 | Error _ as e -> e 204 204 | Ok raw -> Ok (parse_cookie_rows ~key raw)) 205 205 206 - let get_linkedin_cookies proc_mgr fs = 207 - match get_all_linkedin_cookies proc_mgr fs with 206 + let linkedin_cookies proc_mgr fs = 207 + match all_linkedin_cookies proc_mgr fs with 208 208 | Error _ as e -> e 209 209 | Ok cookies -> ( 210 210 match
+7 -7
lib/chrome_cookies.mli
··· 14 14 val pp_error : error Fmt.t 15 15 (** [pp_error] is a pretty-printer for errors. *) 16 16 17 - val get_all_linkedin_cookies : 17 + val all_linkedin_cookies : 18 18 _ Eio.Process.mgr -> _ Eio.Path.t -> ((string * string) list, error) result 19 - (** [get_all_linkedin_cookies proc_mgr fs] extracts all cookies for 20 - [linkedin.com] from Chrome's cookie store. Returns a list of [(name, value)] 21 - pairs, deduplicated by name (most recent first). *) 19 + (** [all_linkedin_cookies proc_mgr fs] extracts all cookies for [linkedin.com] 20 + from Chrome's cookie store. Returns a list of [(name, value)] pairs, 21 + deduplicated by name (most recent first). *) 22 22 23 - val get_linkedin_cookies : 23 + val linkedin_cookies : 24 24 _ Eio.Process.mgr -> _ Eio.Path.t -> (string * string, error) result 25 - (** [get_linkedin_cookies proc_mgr fs] extracts the [li_at] and [JSESSIONID] 26 - cookies from Chrome's cookie store. 25 + (** [linkedin_cookies proc_mgr fs] extracts the [li_at] and [JSESSIONID] cookies 26 + from Chrome's cookie store. 27 27 28 28 Returns [Ok (li_at, jsessionid)] on success. Requires macOS with Chrome 29 29 installed and the user must authorize Keychain access (may prompt for