diff --git a/bin/dune b/bin/dune index 6943e4e..86e5ff9 100644 --- a/bin/dune +++ b/bin/dune @@ -2,4 +2,4 @@ (public_name pusk) (name main) (modules main twitter) - (libraries pusk twostep)) + (libraries pusk twostep core)) diff --git a/bin/main.ml b/bin/main.ml index 75c9fd0..4950772 100644 --- a/bin/main.ml +++ b/bin/main.ml @@ -26,9 +26,10 @@ let rec check ctx = (* Time to wait until next check *) let timeout = match find_latest_tweet ctx with - | Some _tweet -> + | Some tweet_date -> (* TODO: Get date of tweet and return time to wait before tweeting * (0 if we need to tweet) *) + print_endline (fmt "latest tweet date: %d" tweet_date); 30000000000000000 | None -> 0 in diff --git a/bin/twitter.ml b/bin/twitter.ml index 0b3ea19..255b363 100644 --- a/bin/twitter.ml +++ b/bin/twitter.ml @@ -98,7 +98,9 @@ let go_to_profile ctx = ignore (navigate ctx.session_id - (fmt "https://twitter.com%s/with_replies" (get_url ctx.session_id profile_button))); + (fmt + "https://twitter.com%s/with_replies" + (get_attribute ctx.session_id profile_button "href"))); Unix.sleep 4 ;; @@ -106,7 +108,27 @@ let find_latest_tweet ctx = match find ctx.session_id (XPath "//article[@data-testid='tweet']") with | [] -> None | _ as tweets -> - (* TODO: Find latest tweet *) - List.iter print_endline tweets; - Some "" (* tmp *) + (* Get dates attached to each tweets *) + let dates = + (* When a tweet is a RT, two dates are attached *) + List.flatten + (List.map + (fun tweet -> + match find_in_element ctx.session_id (CSS "time[datetime]") tweet with + | [] -> raise (Any (fmt "No dates found for tweet '%s'" tweet)) + | _ as l -> l) + tweets) + in + (* Turn datetime from ISO 8601 format to epoch int *) + let datetimes = + List.map + (fun date -> + let date = + Core.Time.of_string_with_utc_offset + (get_attribute ctx.session_id date "datetime") + in + Core.Time.to_span_since_epoch date |> Core.Time.Span.to_sec |> Float.to_int) + dates + in + Some (List.fold_left max min_int datetimes) ;; diff --git a/lib/net.ml b/lib/net.ml index 4d381c8..87183ba 100644 --- a/lib/net.ml +++ b/lib/net.ml @@ -86,13 +86,7 @@ let navigate ?(wait = true) session_id url = let screenshot session_id = execute_get_request (fmt "%s/screenshot" (driver session_id)) -let find session_id strategy = - let engine, search = get_strategy strategy in - let response = - execute_post_request - (fmt "%s/elements" (driver session_id)) - (Json.find_payload engine search) - in +let parser response = match Yojson.Safe.from_string response with | `Assoc fields -> (match List.assoc "value" fields with @@ -112,7 +106,27 @@ let find session_id strategy = [] l | _ -> []) - | _ -> raise (Any "wait_for_load | Invalid JSON") + | _ -> raise (Any "finder parser | Invalid JSON") +;; + +let find session_id strategy = + let engine, search = get_strategy strategy in + let response = + execute_post_request + (fmt "%s/elements" (driver session_id)) + (Json.find_payload engine search) + in + parser response +;; + +let find_in_element session_id strategy element = + let engine, search = get_strategy strategy in + let response = + execute_post_request + (fmt "%s/element/%s/elements" (driver session_id) element) + (Json.find_payload engine search) + in + parser response ;; let send_keys session_id element_id data = @@ -129,9 +143,10 @@ let click session_id element_id = Json.empty) ;; -let get_url session_id button_id = +let get_attribute session_id element_id attribute = let response = - execute_get_request (fmt "%s/element/%s/attribute/href" (driver session_id) button_id) + execute_get_request + (fmt "%s/element/%s/attribute/%s" (driver session_id) element_id attribute) in match Yojson.Safe.from_string response with | `Assoc fields -> @@ -139,7 +154,7 @@ let get_url session_id button_id = | `String href -> href | _ as e -> raise (Any (fmt "Unexpected response from driver: %s" (Yojson.Safe.to_string e)))) - | _ -> raise (Any "get_url | Invalid JSON") + | _ -> raise (Any "get_attribute | Invalid JSON") ;; let refresh_page ?(wait = true) session_id =