diff --git a/instagrapi/mixins/direct.py b/instagrapi/mixins/direct.py index efe93c4f..52d12849 100644 --- a/instagrapi/mixins/direct.py +++ b/instagrapi/mixins/direct.py @@ -151,12 +151,12 @@ def direct_threads_chunk( def direct_pending_inbox(self, amount: int = 20) -> List[DirectThread]: """ - Get direct message pending threads + Get direct threads of Pending inbox Parameters ---------- amount: int, optional - Maximum number of media to return, default is 20 + Maximum number of threads to return, default is 20 Returns ------- @@ -166,7 +166,6 @@ def direct_pending_inbox(self, amount: int = 20) -> List[DirectThread]: cursor = None threads = [] - # self.private_request("direct_v2/get_presence/") while True: new_threads, cursor = self.direct_pending_chunk(cursor) for thread in new_threads: @@ -182,7 +181,7 @@ def direct_pending_chunk( self, cursor: str = None ) -> Tuple[List[DirectThread], str]: """ - Get direct message pending threads + Get direct threads of Pending inbox. Chunk Parameters ---------- @@ -212,6 +211,89 @@ def direct_pending_chunk( cursor = inbox.get("oldest_cursor") return threads, cursor + def direct_pending_approve(self, thread_id: int) -> bool: + """ + Approve pending direct thread + + Parameters + ---------- + thread_id: int + ID of thread to approve + + Returns + ------- + bool + A boolean value + """ + assert self.user_id, "Login required" + + result = self.private_request( + f"direct_v2/threads/{thread_id}/approve/", + data={"filter": "DEFAULT", "_uuid": self.uuid}, + with_signature=False, + ) + return result.get("status", "") == "ok" + + def direct_spam_inbox(self, amount: int = 20) -> List[DirectThread]: + """ + Get direct threads of Spam inbox (hidden requests) + + Parameters + ---------- + amount: int, optional + Maximum number of threads to return, default is 20 + + Returns + ------- + List[DirectThread] + A list of objects of DirectThread + """ + cursor = None + threads = [] + while True: + new_threads, cursor = self.direct_spam_chunk(cursor) + for thread in new_threads: + threads.append(thread) + + if not cursor or (amount and len(threads) >= amount): + break + if amount: + threads = threads[:amount] + return threads + + def direct_spam_chunk( + self, cursor: str = None + ) -> Tuple[List[DirectThread], str]: + """ + Get direct threads of Spam inbox (hidden requests). Chunk + + Parameters + ---------- + cursor: str, optional + Cursor from the previous chunk request + + Returns + ------- + Tuple[List[DirectThread], str] + A tuple of list of objects of DirectThread and str (cursor) + """ + assert self.user_id, "Login required" + params = { + "visual_message_return_type": "unseen", + "persistentBadging": "true", + "is_prefetching": "false", + } + if cursor: + params.update({"cursor": cursor}) + + threads = [] + result = self.private_request("direct_v2/spam_inbox/", params=params) + inbox = result.get("inbox", {}) + for thread in inbox.get("threads", []): + threads.append(extract_direct_thread(thread)) + cursor = inbox.get("oldest_cursor") + return threads, cursor + def direct_thread(self, thread_id: int, amount: int = 20) -> DirectThread: """ Get all the information about a Direct Message thread @@ -541,28 +623,53 @@ def direct_active_presence(self) -> Dict: return result.get("user_presence", {}) - def direct_send_seen(self, thread_id: int) -> DirectResponse: + def direct_message_seen(self, thread_id: int, message_id: int) -> bool: """ - Send seen to thread + Mark direct message as seen Parameters ---------- thread_id: int - Id of thread which messages will be read - + ID of the thread with message + message_id: int + ID of the message to mark as seen + Returns ------- - An object of DirectResponse + bool + A boolean value """ - data = {} - - thread = self.direct_thread(thread_id=thread_id) + token = self.generate_mutation_token() + data = { + "thread_id": str(thread_id), + "action": "mark_seen", + "client_context": token, + "_uuid": self.uuid, + "offline_threading_id": token + } result = self.private_request( - f"direct_v2/threads/{thread_id}/items/{thread.messages[0].id}/seen/", - data=self.with_default_data(data), + f"direct_v2/threads/{thread_id}/items/{message_id}/seen/", + data=data, with_signature=False, ) - return extract_direct_response(result) + return result.get("status", "") == "ok" + + def direct_send_seen(self, thread_id: int) -> bool: + """ + Mark direct thread as seen + + Parameters + ---------- + thread_id: int + ID of thread to mark as read + + Returns + ------- + bool + A boolean value + """ + thread = self.direct_thread(thread_id=thread_id) + return self.direct_message_seen(thread_id, thread.messages[0].id) def direct_search( self, query: str, mode: SEARCH_MODE = "universal" @@ -680,7 +787,7 @@ def direct_thread_by_participants(self, user_ids: List[int]) -> Dict: result["users"] = users return result - def direct_thread_hide(self, thread_id: int) -> bool: + def direct_thread_hide(self, thread_id: int, move_to_spam: bool = False) -> bool: """ Hide (delete) a thread When you click delete, Instagram hides a thread @@ -688,18 +795,23 @@ def direct_thread_hide(self, thread_id: int) -> bool: Parameters ---------- thread_id: int - Id of thread which messages will be read + ID of thread to hide + move_to_spam: bool, optional + True - move to the hidden requests (spam) folder, False - just hide (default - False) Returns ------- bool A boolean value """ - data = self.with_default_data({}) - data.pop("_uid", None) - data.pop("device_id", None) - result = self.private_request(f"direct_v2/threads/{thread_id}/hide/", data=data) - return result["status"] == "ok" + assert self.user_id, "Login required" + + result = self.private_request( + f"direct_v2/threads/{thread_id}/hide/", + data={"should_move_future_requests_to_spam": move_to_spam, "_uuid": self.uuid}, + with_signature=False, + ) + return result.get("status", "") == "ok" def direct_media_share(self, media_id: str, user_ids: List[int]) -> DirectMessage: """