internal static (FB_User author, long at) _parse_fetch(Session session, JToken data) { var author = new FB_User(session: session, uid: data?.get("message_sender")?.get("id")?.Value <string>()); var at = long.Parse(data?.get("timestamp_precise")?.Value <string>()); return(author, at); }
internal static FB_FriendRequest _parse(Session session, JToken data) { var author = new FB_User(session: session, uid: data?.get("from")?.Value <string>()); return(new FB_FriendRequest() { author = author }); }
internal static (FB_User author, FB_Thread thread, long at) _parse_metadata(Session session, JToken data) { var metadata = data?.get("messageMetadata"); var author = new FB_User(session: session, uid: metadata?.get("actorFbId")?.Value <string>()); var thread = FB_ThreadEvent._get_thread(session, metadata); var at = long.Parse(metadata?.get("timestamp")?.Value <string>()); return(author, thread, at); }
public static FB_User _from_thread_fetch(JToken data) { var c_info = FB_User._parse_customization_info(data); var participants = data.get("all_participants")?.get("nodes")?.Select(node => node.get("messaging_actor")); var user = participants.Where((p) => p.get("id")?.Value <string>() == data.get("thread_key")?.get("other_user_id")?.Value <string>())?.FirstOrDefault(); var last_message_timestamp = data.get("last_message")?.get("nodes")?.FirstOrDefault()?.get("timestamp_precise")?.Value <string>(); var name = user.get("name")?.Value <string>(); var first_name = user.get("first_name")?.Value <string>() ?? user.get("short_name")?.Value <string>(); var last_name = first_name != null?name?.Replace(first_name, "")?.Trim() : null; var gender = GENDER.graphql_GENDERS["UNKNOWN"]; if (data.get("gender")?.Type == JTokenType.Integer) { gender = GENDER.standard_GENDERS[data.get("gender")?.Value <int>() ?? 0]; } else { int gender_int = 0; if (int.TryParse(data.get("gender")?.Value <string>(), out gender_int)) { gender = GENDER.standard_GENDERS[gender_int]; } else { gender = GENDER.graphql_GENDERS[data.get("gender")?.Value <string>() ?? "UNKNOWN"]; } }; if (user.get("big_image_src") == null) { user["big_image_src"] = new JObject(new JProperty("uri", "")); } var plan = data.get("event_reminders")?.get("nodes")?.FirstOrDefault() != null?FB_Plan._from_graphql(data.get("event_reminders")?.get("nodes")?.FirstOrDefault()) : null; return(new FB_User( uid: user.get("id")?.Value <string>(), url: user.get("url")?.Value <string>(), name: name, first_name: first_name, last_name: last_name, is_friend: user.get("is_viewer_friend")?.Value <bool>() ?? false, gender: gender, affinity: user.get("viewer_affinity")?.Value <float>() ?? 0, nickname: (string)c_info.GetValueOrDefault("nickname"), color: (string)c_info.GetValueOrDefault("color"), emoji: (JToken)c_info.GetValueOrDefault("emoji"), own_nickname: (string)c_info.GetValueOrDefault("own_nickname"), photo: user.get("big_image_src")?.get("uri")?.Value <string>(), message_count: data.get("messages_count")?.Value <int>() ?? 0, last_message_timestamp: last_message_timestamp, plan: plan)); }
/// <summary> /// Get thread list of your facebook account /// </summary> /// <param name="limit">Max.number of threads to retrieve. Capped at 20</param> /// <param name="thread_location">models.ThreadLocation: INBOX, PENDING, ARCHIVED or OTHER</param> /// <param name="before">A unix timestamp, indicating from which point to retrieve messages</param> public async Task <List <FB_Thread> > fetchThreadList(int limit = 20, string thread_location = ThreadLocation.INBOX, string before = null) { /* * Get thread list of your facebook account * :param limit: Max.number of threads to retrieve.Capped at 20 * :param thread_location: models.ThreadLocation: INBOX, PENDING, ARCHIVED or OTHER * :param before: A timestamp (in milliseconds), indicating from which point to retrieve threads * :type limit: int * :return: `models.Thread` objects * :rtype: list * :raises: Exception if request failed */ if (limit > 20 || limit < 1) { throw new FBchatUserError("`limit` should be between 1 and 20"); } var dict = new Dictionary <string, object>() { { "limit", limit }, { "tags", new string[] { thread_location } }, { "before", before }, { "includeDeliveryReceipts", true }, { "includeSeqID", false } }; var j = await this._session.graphql_request(GraphQL.from_doc_id(doc_id: "1349387578499440", param: dict)); var rtn = new List <FB_Thread>(); foreach (var node in j.get("viewer")?.get("message_threads")?.get("nodes")) { var _type = node.get("thread_type")?.Value <string>(); if (_type == "GROUP") { rtn.Add(FB_Group._from_graphql(_session, node)); } else if (_type == "ONE_TO_ONE") { rtn.Add(FB_User._from_thread_fetch(_session, node)); } else if (_type == "MARKETPLACE") { rtn.Add(FB_Marketplace._from_graphql(_session, node)); } else { throw new FBchatException(string.Format("Unknown thread type: {0}", _type)); } } return(rtn); }
internal static FB_TypingStatus _from_orca(Session session, JToken data) { var author = new FB_User(session: session, uid: data?.get("sender_fbid")?.Value <string>()); var status = data?.get("state")?.Value <int>() == 1; return(new FB_TypingStatus() { author = author, thread = author, status = status }); }
internal static FB_ParticipantRemoved _from_fetch(FB_Thread thread, JToken data) { (FB_User author, long at) = FB_ParticipantRemoved._parse_fetch(thread.session, data); var removed = new FB_User(data?.get("participants_removed")?.FirstOrDefault()?.get("id")?.Value <string>(), thread.session); return(new FB_ParticipantRemoved() { author = author, thread = thread as FB_Group, removed = removed, at = at }); }
/// TODO: This! internal static FB_LiveLocationEvent _parse(Session session, JToken data) { var thread = FB_LiveLocationEvent._get_thread(session, data); foreach (var location_data in data?.get("messageLiveLocations") ?? Enumerable.Empty <JToken>()) { var message = new FB_Message(session: session, thread_id: thread.uid, uid: data?.get("messageId")?.Value <string>()); var author = new FB_User(session: session, uid: location_data?.get("senderId")?.Value <string>()); var location = FB_LiveLocationAttachment._from_pull(location_data); } return(null); }
internal static FB_ParticipantRemoved _parse(Session session, JToken data) { (FB_User author, FB_Thread thread, long at) = FB_ParticipantRemoved._parse_metadata(session, data); var removed = new FB_User(data?.get("leftParticipantFbId")?.Value <string>(), session); return(new FB_ParticipantRemoved() { author = author, thread = thread as FB_Group, removed = removed, at = at }); }
public static FB_User _from_graphql(JToken data) { if (data.get("profile_picture") == null) { data["profile_picture"] = new JObject(new JProperty("uri", "")); } var c_info = FB_User._parse_customization_info(data); var plan = data.get("event_reminders")?.get("nodes")?.FirstOrDefault() != null?FB_Plan._from_graphql(data.get("event_reminders")?.get("nodes")?.FirstOrDefault()) : null; var name = data.get("name")?.Value <string>(); var first_name = data.get("first_name")?.Value <string>() ?? data.get("short_name")?.Value <string>(); var last_name = first_name != null?name?.Replace(first_name, "")?.Trim() : null; var gender = GENDER.graphql_GENDERS["UNKNOWN"]; if (data.get("gender")?.Type == JTokenType.Integer) { gender = GENDER.standard_GENDERS[data.get("gender")?.Value <int>() ?? 0]; } else { int gender_int = 0; if (int.TryParse(data.get("gender")?.Value <string>(), out gender_int)) { gender = GENDER.standard_GENDERS[gender_int]; } else { gender = GENDER.graphql_GENDERS[data.get("gender")?.Value <string>() ?? "UNKNOWN"]; } }; return(new FB_User( uid: data.get("id")?.Value <string>(), url: data.get("url")?.Value <string>(), name: name, first_name: first_name, last_name: last_name, is_friend: data.get("is_viewer_friend")?.Value <bool>() ?? false, gender: gender, affinity: data.get("viewer_affinity")?.Value <float>() ?? 0, nickname: (string)c_info.GetValueOrDefault("nickname"), color: (string)c_info.GetValueOrDefault("color"), emoji: (JToken)c_info.GetValueOrDefault("emoji"), own_nickname: (string)c_info.GetValueOrDefault("own_nickname"), photo: data.get("profile_picture")?.get("uri")?.Value <string>(), message_count: data.get("messages_count")?.Value <int>() ?? 0, plan: plan)); }
internal static FB_NicknameSet _parse(Session session, JToken data) { (FB_User author, FB_Thread thread, long at) = FB_NicknameSet._parse_metadata(session, data); var subject = new FB_User(data?.get("untypedData")?.get("participant_id")?.Value <string>(), session); var nickname = data?.get("untypedData")?.get("nickname")?.Value <string>(); return(new FB_NicknameSet() { author = author, thread = thread, subject = subject, nickname = nickname, at = at }); }
internal static FB_ThreadsRead _parse_read_receipt(Session session, JToken data) { var author = new FB_User(session: session, uid: data?.get("actorFbId")?.Value <string>()); var thread = FB_ThreadEvent._get_thread(session, data); var at = long.Parse(data.get("actionTimestampMs")?.Value <string>()); return(new FB_ThreadsRead() { author = author, threads = new List <FB_Thread>() { thread }, at = at }); }
internal static FB_ThreadsRead _parse(Session session, JToken data) { var author = new FB_User(session.user.uid, session); var threads = data?.get("threadKeys")?.Select(x => FB_ThreadEvent._get_thread(session, new JObject() { { "threadKey", x } })); var at = long.Parse(data?.get("actionTimestamp")?.Value <string>()); return(new FB_ThreadsRead() { author = author, threads = threads.ToList(), at = at }); }
internal static FB_AdminsRemoved _parse(Session session, JToken data) { (FB_User author, FB_Thread thread, long at) = FB_AdminsRemoved._parse_metadata(session, data); var target = new FB_User(data?.get("untypedData")?.get("TARGET_ID")?.Value <string>(), session); return(new FB_AdminsRemoved() { author = author, thread = thread, removed = new List <FB_User>() { target }, at = at }); }
internal static FB_NicknameSet _from_fetch(FB_Thread thread, JToken data) { (FB_User author, long at) = FB_NicknameSet._parse_fetch(thread.session, data); var extra = data?.get("extensible_message_admin_text"); var subject = new FB_User(extra?.get("participant_id")?.Value <string>(), thread.session); var nickname = extra?.get("nickname")?.Value <string>(); return(new FB_NicknameSet() { author = author, thread = thread, subject = subject, nickname = nickname, at = at }); }
/// <summary> /// Find and get a thread by its name /// </summary> /// <param name="name">Name of the thread</param> /// <param name="limit">The max. amount of threads to fetch</param> /// <returns>`FB_User`, `FB_Group` and `FB_Page` objects, ordered by relevance</returns> public async Task <List <FB_Thread> > searchThreads(string name, int limit = 1) { /* * Find and get a thread by its name * :param name: Name of the thread * :param limit: The max. amount of groups to fetch * : return: `User`, `Group` and `Page` objects, ordered by relevance * :rtype: list * :raises: FBchatException if request failed * */ var param = new Dictionary <string, object>() { { "search", name }, { "limit", limit.ToString() } }; var j = await this._session.graphql_request(GraphQL.from_query(GraphQL.SEARCH_THREAD, param)); List <FB_Thread> rtn = new List <FB_Thread>(); foreach (var node in j[name]?.get("threads")?.get("nodes")) { if (node.get("__typename").Value <string>().Equals("User")) { rtn.Add(FB_User._from_graphql(_session, node)); } else if (node.get("__typename").Value <string>().Equals("MessageThread")) { // MessageThread => Group thread rtn.Add(FB_Group._from_graphql(_session, node)); } else if (node.get("__typename").Value <string>().Equals("Page")) { rtn.Add(FB_Page._from_graphql(_session, node)); } else if (node.get("__typename").Value <string>().Equals("Group")) { // We don"t handle Facebook "Groups" continue; } else { Debug.WriteLine(string.Format("Unknown __typename: {0} in {1}", node.get("__typename").Value <string>(), node)); } } return(rtn); }
/// <summary> /// Find and get user by his/her name /// </summary> /// <param name="name">Name of the user</param> /// <param name="limit">The max. amount of users to fetch</param> /// <returns>`FB_User` objects, ordered by relevance</returns> public async Task <List <FB_User> > searchUsers(string name, int limit = 10) { /* * Find and get user by his/ her name * : param name: Name of the user * :param limit: The max. amount of users to fetch * : return: `User` objects, ordered by relevance * :rtype: list * :raises: FBchatException if request failed * */ var param = new Dictionary <string, object>() { { "search", name }, { "limit", limit.ToString() } }; var j = await this._session.graphql_request(GraphQL.from_query(GraphQL.SEARCH_USER, param)); return(j[name]?.get("users")?.get("nodes").Select(node => FB_User._from_graphql(_session, node)).ToList()); }
internal static FB_MessagesDelivered _parse(Session session, JToken data) { var thread = FB_MessagesDelivered._get_thread(session, data); var author = thread; if (data?.get("actorFbId")?.Value <string>() != null) { author = new FB_User(data?.get("actorFbId")?.Value <string>(), session); } var messages = data?.get("messageIds")?.Select(x => new FB_Message(session, thread_id: thread.uid, uid: x?.Value <string>())); var at = long.Parse(data?.get("deliveredWatermarkTimestampMs")?.Value <string>()); return(new FB_MessagesDelivered() { author = author as FB_User, thread = thread, messages = messages.ToList(), at = at }); }
/// <summary> /// Fetch users the client is currently chatting with /// </summary> /// <returns>`FB_User` objects</returns> public async Task <List <FB_User> > fetchUsers() { /* * Fetch users the client is currently chatting with * This is very close to your friend list, with the follow differences: * It differs by including users that you're not friends with, but have chatted * with before, and by including accounts that are "Messenger Only". * But does not include deactivated, deleted or memorialized users (logically, * since you can't chat with those). * : return: `User` objects * :rtype: list * :raises: FBchatException if request failed * */ var data = new Dictionary <string, object>() { { "viewer", this._session.user.uid }, }; var j = await this._session._payload_post("/chat/user_info_all", data : data); var users = new List <FB_User>(); foreach (var u in j.Value <JObject>().Properties()) { var k = u.Value; if (!new[] { "user", "friend" }.Contains(k?.get("type")?.Value <string>()) || new[] { "0", "\0" }.Contains(k.get("id").Value <string>())) { // Skip invalid users continue; } users.Add(FB_User._from_all_fetch(_session, k)); } return(users); }
/// <summary> /// Get threads' info from IDs, unordered /// </summary> /// <param name="thread_ids">One or more thread ID(s) to query</param> /// <returns>A dictionary of FB_Thread objects, labeled by their ID</returns> public async Task <Dictionary <string, FB_Thread> > fetchThreadInfo(List <string> thread_ids) { /* * Get threads" info from IDs, unordered * ..warning:: * Sends two requests if users or pages are present, to fetch all available info! * :param thread_ids: One or more thread ID(s) to query * :return: `models.Thread` objects, labeled by their ID * :rtype: dict * :raises: Exception if request failed */ var queries = new List <GraphQL>(); foreach (var thread_id in thread_ids) { queries.Add(GraphQL.from_doc_id(doc_id: "2147762685294928", param: new Dictionary <string, object>() { { "id", thread_id }, { "message_limit", 0.ToString() }, { "load_messages", false.ToString() }, { "load_read_receipts", false.ToString() }, { "before", null } })); } var j = await this._session.graphql_requests(queries); foreach (var obj in j.Select((x, index) => new { entry = x, i = index })) { if (obj.entry.get("message_thread") == null) { // If you don't have an existing thread with this person, attempt to retrieve user data anyways j[obj.i]["message_thread"] = new JObject( new JProperty("thread_key", new JObject( new JProperty("other_user_id", thread_ids[obj.i]))), new JProperty("thread_type", "ONE_TO_ONE")); } } var pages_and_user_ids = j.Where(k => k.get("message_thread")?.get("thread_type")?.Value <string>()?.Equals("ONE_TO_ONE") ?? false) .Select(k => k.get("message_thread")?.get("thread_key")?.get("other_user_id")?.Value <string>()); JObject pages_and_users = null; if (pages_and_user_ids.Count() != 0) { pages_and_users = await this._fetchInfo(pages_and_user_ids.ToList()); } var rtn = new Dictionary <string, FB_Thread>(); foreach (var obj in j.Select((x, index) => new { entry = x, i = index })) { var entry = obj.entry.get("message_thread"); if (entry.get("thread_type")?.Value <string>()?.Equals("GROUP") ?? false) { var _id = entry.get("thread_key")?.get("thread_fbid").Value <string>(); rtn[_id] = FB_Group._from_graphql(_session, entry); } if (entry.get("thread_type")?.Value <string>()?.Equals("MARKETPLACE") ?? false) { var _id = entry.get("thread_key")?.get("thread_fbid").Value <string>(); rtn[_id] = FB_Marketplace._from_graphql(_session, entry); } else if (entry.get("thread_type")?.Value <string>()?.Equals("ONE_TO_ONE") ?? false) { var _id = entry.get("thread_key")?.get("other_user_id")?.Value <string>(); if (pages_and_users[_id] == null) { throw new FBchatException(string.Format("Could not fetch thread {0}", _id)); } foreach (var elem in pages_and_users[_id]) { entry[((JProperty)elem).Name] = ((JProperty)elem).Value; } if (entry.get("first_name") != null) { rtn[_id] = FB_User._from_graphql(_session, entry); } else { rtn[_id] = FB_Page._from_graphql(_session, entry); } } else { throw new FBchatException(string.Format("{0} had an unknown thread type: {1}", thread_ids[obj.i], entry)); } } return(rtn); }