From 1aecc21b065c6eb24a928ea4537fea44f3f45627 Mon Sep 17 00:00:00 2001 From: DrunkLeen Date: Sun, 16 Jul 2023 10:05:58 +0200 Subject: [PATCH 01/12] like/unlike fixed --- threadspy/threads_api.py | 51 ++++++++++++++++++++++++++++------------ 1 file changed, 36 insertions(+), 15 deletions(-) diff --git a/threadspy/threads_api.py b/threadspy/threads_api.py index bf56f95..b21310a 100644 --- a/threadspy/threads_api.py +++ b/threadspy/threads_api.py @@ -53,7 +53,7 @@ class ThreadsAPI: def __init__( self, - verbose: str | None = None, + verbose: True | False = None, noUpdateLSD: str | None = None, fbLSDToken: str | None = None, username: str | None = None, @@ -67,7 +67,7 @@ def __init__( self.device_id = device_id if noUpdateLSD is not None and isinstance(noUpdateLSD, str): self.noUpdateLSD = noUpdateLSD - if verbose is not None and isinstance(verbose, str): + if verbose is not None and isinstance(verbose, bool): self.verbose = verbose if ( @@ -87,6 +87,7 @@ def __init__( self.token = token else: self.token = self.get_token() + self.user_id = self.get_user_id_from_username(username) def __is_valid_url(self, url: str) -> bool: url_pattern = re.compile(r"https?://(?:[-\w.]|(?:%[\da-fA-F]{2}))+") @@ -487,23 +488,43 @@ def __toggle_auth__post_request(self, url: str): token = self.token if token is None: raise "Token not found" - headers = self.__get_default_headers() - res = self.http_client.post(url, headers=headers) - return res + headers = self.__get_app_headers() + response = self.http_client.post(url, headers=headers) + return response def like(self, post_id: str) -> bool: - user_id = self.get_current_user_id() - res = self.__toggle_auth__post_request( - f"{BASE_API_URL}/api/v1/media/{post_id}_${user_id}/like/" - ) - return res.json()["status"] == "ok" + """ + like a post. + + Args: + post_id (str): post identifier + + Returns: + boolean and if verbose mode is enabled, prints response dict + """ + user_id = self.user_id or self.get_current_user_id() + response = self.__toggle_auth__post_request( + url=f'{BASE_API_URL}/media/{post_id}_{user_id}/like/',) + if self.verbose: + print("[LIKE]", response.json()) + return response.json()["status"] == "ok" def unlike(self, post_id: str) -> bool: - user_id = self.get_current_user_id() - res = self.__toggle_auth__post_request( - f"{BASE_API_URL}/api/v1/media/{post_id}_${user_id}/unlike/" - ) - return res.json()["status"] == "ok" + """ + takes your like back from a post. + + Args: + post_id (str): post identifier + + Returns: + boolean and if verbose mode is enabled, prints response dict + """ + user_id = self.user_id or self.get_current_user_id() + response = self.__toggle_auth__post_request( + f"{BASE_API_URL}/media/{post_id}_{user_id}/unlike/",) + if self.verbose: + print("[UNLIKE]", response.json()) + return response.json()["status"] == "ok" def follow(self, user_id: str) -> bool: res = self.__toggle_auth__post_request( From 693c849ab4f323071605d015b0f75aab35a1992a Mon Sep 17 00:00:00 2001 From: DrunkLeen Date: Sun, 16 Jul 2023 10:06:47 +0200 Subject: [PATCH 02/12] follow/unfollow updated --- threadspy/threads_api.py | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/threadspy/threads_api.py b/threadspy/threads_api.py index b21310a..4b3bf7f 100644 --- a/threadspy/threads_api.py +++ b/threadspy/threads_api.py @@ -527,20 +527,16 @@ def unlike(self, post_id: str) -> bool: return response.json()["status"] == "ok" def follow(self, user_id: str) -> bool: - res = self.__toggle_auth__post_request( - f"{BASE_API_URL}/api/v1/friendships/create/{user_id}/" - ) + res = self.__toggle_auth__post_request(f"{BASE_API_URL}/friendships/create/{user_id}/") if self.verbose: print("[FOLLOW]", res.json()) - return res.json() + return res.json()["status"] == "ok" def unfollow(self, user_id: str) -> bool: - res = self.__toggle_auth__post_request( - f"{BASE_API_URL}/api/v1/friendships/destroy/{user_id}/" - ) + res = self.__toggle_auth__post_request(f"{BASE_API_URL}/friendships/destroy/{user_id}/") if self.verbose: print("[UNFOLLOW]", res.json()) - return res.json() + return res.json()["status"] == "ok" def get_token(self) -> str: """ From d94a3893d32224e6dcefec3b62301691a520974e Mon Sep 17 00:00:00 2001 From: DrunkLeen Date: Sun, 16 Jul 2023 10:07:58 +0200 Subject: [PATCH 03/12] Block/Unblock methods added --- threadspy/threads_api.py | 61 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/threadspy/threads_api.py b/threadspy/threads_api.py index 4b3bf7f..7e6b485 100644 --- a/threadspy/threads_api.py +++ b/threadspy/threads_api.py @@ -538,6 +538,67 @@ def unfollow(self, user_id: str) -> bool: print("[UNFOLLOW]", res.json()) return res.json()["status"] == "ok" + def block(self, user_id: str) -> bool: + """ + Blocks a user. + + Args: + user_id (str): user identifier + + Returns: + boolean and if verbose mode is enabled, prints response dict + """ + params = quote( + string=json.dumps( + obj={ + "user_id": user_id, + "surface": "ig_text_feed_timeline", + "is_auto_block_enabled": "true", + }, + ), + safe="!~*'()" + ) + + response = self.http_client.post( + url=f'{BASE_API_URL}/friendships/block/{user_id}/', + headers=self.__get_app_headers(), + data=f'signed_body=SIGNATURE.{params}', + ) + + if self.verbose: + print("[BLOCK]", response.json()) + return response.json()["status"] == "ok" + + def unblock(self, user_id: str) -> bool: + """ + Unblocks a user. + + Args: + user_id (str): user identifier + + Returns: + boolean and if verbose mode is enabled, prints response dict + """ + params = quote( + string=json.dumps( + obj={ + "user_id": user_id, + "surface": "ig_text_feed_timeline", + }, + ), + safe="!~*'()" + ) + + response = self.http_client.post( + url=f'{BASE_API_URL}/friendships/unblock/{user_id}/', + headers=self.__get_app_headers(), + data=f'signed_body=SIGNATURE.{params}', + ) + + if self.verbose: + print("[UNBLOCK]", response.json()) + return response.json()["status"] == "ok" + def get_token(self) -> str: """ set fb login token From 42b2c0f183de24cf8b28eb3a866857b376340ab2 Mon Sep 17 00:00:00 2001 From: DrunkLeen Date: Sun, 16 Jul 2023 10:08:33 +0200 Subject: [PATCH 04/12] Mute/Unmute methods added --- threadspy/threads_api.py | 60 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/threadspy/threads_api.py b/threadspy/threads_api.py index 7e6b485..86ce721 100644 --- a/threadspy/threads_api.py +++ b/threadspy/threads_api.py @@ -599,6 +599,66 @@ def unblock(self, user_id: str) -> bool: print("[UNBLOCK]", response.json()) return response.json()["status"] == "ok" + def mute(self, user_id: str) -> bool: + """ + Mutes a user. + + Args: + user_id (str): user identifier + + Returns: + boolean and if verbose mode is enabled, prints response dict + """ + params = quote( + string=json.dumps( + obj={ + "target_posts_author_id": user_id, + "container_module": "ig_text_feed_timeline", + }, + ), + safe="!~*'()" + ) + + response = self.http_client.post( + url=f'{BASE_API_URL}/friendships/mute_posts_or_story_from_follow/', + headers=self.__get_app_headers(), + data=f'signed_body=SIGNATURE.{params}', + ) + + if self.verbose: + print("[MUTE]", response.json()) + return response.json()["status"] == "ok" + + def unmute(self, user_id: str) -> bool: + """ + Unmutes a user. + + Args: + user_id (str): user identifier + + Returns: + boolean and if verbose mode is enabled, prints response dict + """ + params = quote( + string=json.dumps( + obj={ + "target_posts_author_id": user_id, + "container_module": "ig_text_feed_timeline", + }, + ), + safe="!~*'()" + ) + + response = self.http_client.post( + url=f'{BASE_API_URL}/friendships/unmute_posts_or_story_from_follow/', + headers=self.__get_app_headers(), + data=f'signed_body=SIGNATURE.{params}', + ) + + if self.verbose: + print("[UNMUTE]", response.json()) + return response.json()["status"] == "ok" + def get_token(self) -> str: """ set fb login token From 347cc7aae74759894f3f316a353a71d62de52108 Mon Sep 17 00:00:00 2001 From: DrunkLeen Date: Sun, 16 Jul 2023 10:09:26 +0200 Subject: [PATCH 05/12] Restriction methods added --- threadspy/threads_api.py | 60 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/threadspy/threads_api.py b/threadspy/threads_api.py index 86ce721..2c2b92a 100644 --- a/threadspy/threads_api.py +++ b/threadspy/threads_api.py @@ -599,6 +599,66 @@ def unblock(self, user_id: str) -> bool: print("[UNBLOCK]", response.json()) return response.json()["status"] == "ok" + def restrict(self, user_id: str) -> bool: + """ + Restrict a user. + + Args: + user_id (str): user identifier + + Returns: + boolean and if verbose mode is enabled, prints response dict + """ + params = quote( + string=json.dumps( + obj={ + "user_ids": user_id, + "container_module": "ig_text_feed_timeline", + }, + ), + safe="!~*'()" + ) + + response = self.http_client.post( + url=f'{BASE_API_URL}/restrict_action/restrict_many/', + headers=self.__get_app_headers(), + data=f'signed_body=SIGNATURE.{params}', + ) + + if self.verbose: + print("[RESTRICT]", response.json()) + return response.json()["status"] == "ok" + + def unrestrict(self, user_id: str) -> bool: + """ + Unrestrict a user. + + Args: + user_id (str): user identifier + + Returns: + boolean and if verbose mode is enabled, prints response dict + """ + params = quote( + string=json.dumps( + obj={ + "target_user_id": user_id, + "container_module": "ig_text_feed_timeline", + }, + ), + safe="!~*'()" + ) + + response = self.http_client.post( + url=f'{BASE_API_URL}/restrict_action/unrestrict/', + headers=self.__get_app_headers(), + data=f'signed_body=SIGNATURE.{params}', + ) + + if self.verbose: + print("[UNRESTRICT]", response.json()) + return response.json()["status"] == "ok" + def mute(self, user_id: str) -> bool: """ Mutes a user. From 2c9cbfdb275f8762e79dca0d1af3a1a6a1684778 Mon Sep 17 00:00:00 2001 From: DrunkLeen Date: Sun, 16 Jul 2023 10:10:17 +0200 Subject: [PATCH 06/12] User-Search method added --- threadspy/threads_api.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/threadspy/threads_api.py b/threadspy/threads_api.py index 2c2b92a..e362e9d 100644 --- a/threadspy/threads_api.py +++ b/threadspy/threads_api.py @@ -526,6 +526,22 @@ def unlike(self, post_id: str) -> bool: print("[UNLIKE]", response.json()) return response.json()["status"] == "ok" + def search(self, search_parameter: str) -> dict: + """ + Search for user. + + Args: + search_parameter (str): parameter to search + + Returns: + dict:{A list of users}. + """ + response = self.http_client.get( + url=f'{BASE_API_URL}/users/search/?q={search_parameter}', + headers=self.__get_app_headers(), + ) + return response if response.status_code is not 200 else response.json() + def follow(self, user_id: str) -> bool: res = self.__toggle_auth__post_request(f"{BASE_API_URL}/friendships/create/{user_id}/") if self.verbose: From 71b3387510cfe0e2211acaf265e7cb19db24399f Mon Sep 17 00:00:00 2001 From: DrunkLeen Date: Sun, 16 Jul 2023 10:19:07 +0200 Subject: [PATCH 07/12] README.md updated with latest changes --- README.md | 46 ++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 42 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 3e2b009..823439c 100644 --- a/README.md +++ b/README.md @@ -97,6 +97,14 @@ api.publish({ }) ``` +#### 🔎 Search Users + +```python +search_parameter = "DrunkLeen" +# 💡 Uses current credentials +api.search(search_parameter) +``` + #### ✨ Like/Unlike a Thread (from v0.0.7) ```python @@ -108,14 +116,44 @@ api.like(postIDToLike) api.unlike(postIDToLike) ``` -#### ✨ Follow/Unfollow a User (from v0.0.7) +#### ✨ Follow/Unfollow a User + +```python +user_id = api.get_user_id_from_username('junhoyeo') + +# 💡 Uses current credentials +api.follow(user_id) +api.unfollow(user_id) +``` + +#### ⛔ Block/Unblock a User + +```python +user_id = api.get_user_id_from_username('junhoyeo') + +# 💡 Uses current credentials +api.block(user_id) +api.unblock(user_id) +``` + +#### 🔇 Mute/Unmute a User + +```python +user_id = api.get_user_id_from_username('junhoyeo') + +# 💡 Uses current credentials +api.mute(user_id) +api.unmute(user_id) +``` + +#### ⏚ī¸ Restrict/Unrestrict a User ```python -user_id_to_follow = api.get_user_id_from_username('junhoyeo') +user_id = api.get_user_id_from_username('junhoyeo') # 💡 Uses current credentials -api.follow(user_id_to_follow) -api.unfollow(user_id_to_follow) +api.restrict(user_id) +api.unrestrict(user_id) ``` ## [](https://github.com/junhoyeo) Roadmap From 17fa1f638e6a7b62ea880c44712aeec0ccbfa387 Mon Sep 17 00:00:00 2001 From: DrunkLeen Date: Sun, 16 Jul 2023 11:36:01 +0200 Subject: [PATCH 08/12] API URLs patched --- threadspy/threads_api.py | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/threadspy/threads_api.py b/threadspy/threads_api.py index e362e9d..0721f3c 100644 --- a/threadspy/threads_api.py +++ b/threadspy/threads_api.py @@ -504,7 +504,7 @@ def like(self, post_id: str) -> bool: """ user_id = self.user_id or self.get_current_user_id() response = self.__toggle_auth__post_request( - url=f'{BASE_API_URL}/media/{post_id}_{user_id}/like/',) + url=f'{BASE_API_URL}/api/v1/media/{post_id}_{user_id}/like/',) if self.verbose: print("[LIKE]", response.json()) return response.json()["status"] == "ok" @@ -521,7 +521,7 @@ def unlike(self, post_id: str) -> bool: """ user_id = self.user_id or self.get_current_user_id() response = self.__toggle_auth__post_request( - f"{BASE_API_URL}/media/{post_id}_{user_id}/unlike/",) + f"{BASE_API_URL}/api/v1/media/{post_id}_{user_id}/unlike/",) if self.verbose: print("[UNLIKE]", response.json()) return response.json()["status"] == "ok" @@ -537,19 +537,20 @@ def search(self, search_parameter: str) -> dict: dict:{A list of users}. """ response = self.http_client.get( - url=f'{BASE_API_URL}/users/search/?q={search_parameter}', + url=f'{BASE_API_URL}/api/v1/users/search/?q={search_parameter}', headers=self.__get_app_headers(), ) - return response if response.status_code is not 200 else response.json() + print("URL:", f'{BASE_API_URL}/api/v1/users/search/?q={search_parameter}') + return response if response.status_code != 200 else response.json() def follow(self, user_id: str) -> bool: - res = self.__toggle_auth__post_request(f"{BASE_API_URL}/friendships/create/{user_id}/") + res = self.__toggle_auth__post_request(f"{BASE_API_URL}/api/v1/friendships/create/{user_id}/") if self.verbose: print("[FOLLOW]", res.json()) return res.json()["status"] == "ok" def unfollow(self, user_id: str) -> bool: - res = self.__toggle_auth__post_request(f"{BASE_API_URL}/friendships/destroy/{user_id}/") + res = self.__toggle_auth__post_request(f"{BASE_API_URL}/api/v1/friendships/destroy/{user_id}/") if self.verbose: print("[UNFOLLOW]", res.json()) return res.json()["status"] == "ok" @@ -576,7 +577,7 @@ def block(self, user_id: str) -> bool: ) response = self.http_client.post( - url=f'{BASE_API_URL}/friendships/block/{user_id}/', + url=f'{BASE_API_URL}/api/v1/friendships/block/{user_id}/', headers=self.__get_app_headers(), data=f'signed_body=SIGNATURE.{params}', ) @@ -606,7 +607,7 @@ def unblock(self, user_id: str) -> bool: ) response = self.http_client.post( - url=f'{BASE_API_URL}/friendships/unblock/{user_id}/', + url=f'{BASE_API_URL}/api/v1/friendships/unblock/{user_id}/', headers=self.__get_app_headers(), data=f'signed_body=SIGNATURE.{params}', ) @@ -636,7 +637,7 @@ def restrict(self, user_id: str) -> bool: ) response = self.http_client.post( - url=f'{BASE_API_URL}/restrict_action/restrict_many/', + url=f'{BASE_API_URL}/api/v1/restrict_action/restrict_many/', headers=self.__get_app_headers(), data=f'signed_body=SIGNATURE.{params}', ) @@ -666,7 +667,7 @@ def unrestrict(self, user_id: str) -> bool: ) response = self.http_client.post( - url=f'{BASE_API_URL}/restrict_action/unrestrict/', + url=f'{BASE_API_URL}/api/v1/restrict_action/unrestrict/', headers=self.__get_app_headers(), data=f'signed_body=SIGNATURE.{params}', ) @@ -696,7 +697,7 @@ def mute(self, user_id: str) -> bool: ) response = self.http_client.post( - url=f'{BASE_API_URL}/friendships/mute_posts_or_story_from_follow/', + url=f'{BASE_API_URL}/api/v1/friendships/mute_posts_or_story_from_follow/', headers=self.__get_app_headers(), data=f'signed_body=SIGNATURE.{params}', ) @@ -726,7 +727,7 @@ def unmute(self, user_id: str) -> bool: ) response = self.http_client.post( - url=f'{BASE_API_URL}/friendships/unmute_posts_or_story_from_follow/', + url=f'{BASE_API_URL}/api/v1/friendships/unmute_posts_or_story_from_follow/', headers=self.__get_app_headers(), data=f'signed_body=SIGNATURE.{params}', ) From 862384cce31b77e1fcdae8bf3fa725cd43906be9 Mon Sep 17 00:00:00 2001 From: DrunkLeen Date: Sun, 16 Jul 2023 11:55:51 +0200 Subject: [PATCH 09/12] Bug Fix --- threadspy/threads_api.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/threadspy/threads_api.py b/threadspy/threads_api.py index 0721f3c..c5718b8 100644 --- a/threadspy/threads_api.py +++ b/threadspy/threads_api.py @@ -82,12 +82,12 @@ def __init__( self.encrypted_password, self.timestamp_string = self._password_encryption( password ) + self.user_id = self.get_user_id_from_username(username) if token is not None and isinstance(token, str): self.token = token else: self.token = self.get_token() - self.user_id = self.get_user_id_from_username(username) def __is_valid_url(self, url: str) -> bool: url_pattern = re.compile(r"https?://(?:[-\w.]|(?:%[\da-fA-F]{2}))+") From d23f570ad7e036109335ea9bb5586304359526e0 Mon Sep 17 00:00:00 2001 From: DrunkLeen Date: Sun, 16 Jul 2023 14:29:33 +0200 Subject: [PATCH 10/12] Check Friendship Status Added --- threadspy/threads_api.py | 125 +++++++++++++++++++++++---------------- 1 file changed, 75 insertions(+), 50 deletions(-) diff --git a/threadspy/threads_api.py b/threadspy/threads_api.py index c5718b8..a2280ad 100644 --- a/threadspy/threads_api.py +++ b/threadspy/threads_api.py @@ -504,7 +504,8 @@ def like(self, post_id: str) -> bool: """ user_id = self.user_id or self.get_current_user_id() response = self.__toggle_auth__post_request( - url=f'{BASE_API_URL}/api/v1/media/{post_id}_{user_id}/like/',) + url=f"{BASE_API_URL}/api/v1/media/{post_id}_{user_id}/like/", + ) if self.verbose: print("[LIKE]", response.json()) return response.json()["status"] == "ok" @@ -521,7 +522,8 @@ def unlike(self, post_id: str) -> bool: """ user_id = self.user_id or self.get_current_user_id() response = self.__toggle_auth__post_request( - f"{BASE_API_URL}/api/v1/media/{post_id}_{user_id}/unlike/",) + f"{BASE_API_URL}/api/v1/media/{post_id}_{user_id}/unlike/", + ) if self.verbose: print("[UNLIKE]", response.json()) return response.json()["status"] == "ok" @@ -537,20 +539,24 @@ def search(self, search_parameter: str) -> dict: dict:{A list of users}. """ response = self.http_client.get( - url=f'{BASE_API_URL}/api/v1/users/search/?q={search_parameter}', + url=f"{BASE_API_URL}/api/v1/users/search/?q={search_parameter}", headers=self.__get_app_headers(), - ) - print("URL:", f'{BASE_API_URL}/api/v1/users/search/?q={search_parameter}') + ) + print("URL:", f"{BASE_API_URL}/api/v1/users/search/?q={search_parameter}") return response if response.status_code != 200 else response.json() def follow(self, user_id: str) -> bool: - res = self.__toggle_auth__post_request(f"{BASE_API_URL}/api/v1/friendships/create/{user_id}/") + res = self.__toggle_auth__post_request( + f"{BASE_API_URL}/api/v1/friendships/create/{user_id}/" + ) if self.verbose: print("[FOLLOW]", res.json()) return res.json()["status"] == "ok" def unfollow(self, user_id: str) -> bool: - res = self.__toggle_auth__post_request(f"{BASE_API_URL}/api/v1/friendships/destroy/{user_id}/") + res = self.__toggle_auth__post_request( + f"{BASE_API_URL}/api/v1/friendships/destroy/{user_id}/" + ) if self.verbose: print("[UNFOLLOW]", res.json()) return res.json()["status"] == "ok" @@ -568,18 +574,18 @@ def block(self, user_id: str) -> bool: params = quote( string=json.dumps( obj={ - "user_id": user_id, - "surface": "ig_text_feed_timeline", - "is_auto_block_enabled": "true", + "user_id": user_id, + "surface": "ig_text_feed_timeline", + "is_auto_block_enabled": "true", }, - ), - safe="!~*'()" - ) + ), + safe="!~*'()", + ) response = self.http_client.post( - url=f'{BASE_API_URL}/api/v1/friendships/block/{user_id}/', + url=f"{BASE_API_URL}/api/v1/friendships/block/{user_id}/", headers=self.__get_app_headers(), - data=f'signed_body=SIGNATURE.{params}', + data=f"signed_body=SIGNATURE.{params}", ) if self.verbose: @@ -599,17 +605,17 @@ def unblock(self, user_id: str) -> bool: params = quote( string=json.dumps( obj={ - "user_id": user_id, - "surface": "ig_text_feed_timeline", + "user_id": user_id, + "surface": "ig_text_feed_timeline", }, - ), - safe="!~*'()" - ) + ), + safe="!~*'()", + ) response = self.http_client.post( - url=f'{BASE_API_URL}/api/v1/friendships/unblock/{user_id}/', + url=f"{BASE_API_URL}/api/v1/friendships/unblock/{user_id}/", headers=self.__get_app_headers(), - data=f'signed_body=SIGNATURE.{params}', + data=f"signed_body=SIGNATURE.{params}", ) if self.verbose: @@ -629,17 +635,17 @@ def restrict(self, user_id: str) -> bool: params = quote( string=json.dumps( obj={ - "user_ids": user_id, - "container_module": "ig_text_feed_timeline", + "user_ids": user_id, + "container_module": "ig_text_feed_timeline", }, - ), - safe="!~*'()" - ) + ), + safe="!~*'()", + ) response = self.http_client.post( - url=f'{BASE_API_URL}/api/v1/restrict_action/restrict_many/', + url=f"{BASE_API_URL}/api/v1/restrict_action/restrict_many/", headers=self.__get_app_headers(), - data=f'signed_body=SIGNATURE.{params}', + data=f"signed_body=SIGNATURE.{params}", ) if self.verbose: @@ -659,17 +665,17 @@ def unrestrict(self, user_id: str) -> bool: params = quote( string=json.dumps( obj={ - "target_user_id": user_id, - "container_module": "ig_text_feed_timeline", + "target_user_id": user_id, + "container_module": "ig_text_feed_timeline", }, - ), - safe="!~*'()" - ) + ), + safe="!~*'()", + ) response = self.http_client.post( - url=f'{BASE_API_URL}/api/v1/restrict_action/unrestrict/', + url=f"{BASE_API_URL}/api/v1/restrict_action/unrestrict/", headers=self.__get_app_headers(), - data=f'signed_body=SIGNATURE.{params}', + data=f"signed_body=SIGNATURE.{params}", ) if self.verbose: @@ -689,17 +695,17 @@ def mute(self, user_id: str) -> bool: params = quote( string=json.dumps( obj={ - "target_posts_author_id": user_id, - "container_module": "ig_text_feed_timeline", + "target_posts_author_id": user_id, + "container_module": "ig_text_feed_timeline", }, - ), - safe="!~*'()" - ) + ), + safe="!~*'()", + ) response = self.http_client.post( - url=f'{BASE_API_URL}/api/v1/friendships/mute_posts_or_story_from_follow/', + url=f"{BASE_API_URL}/api/v1/friendships/mute_posts_or_story_from_follow/", headers=self.__get_app_headers(), - data=f'signed_body=SIGNATURE.{params}', + data=f"signed_body=SIGNATURE.{params}", ) if self.verbose: @@ -719,23 +725,42 @@ def unmute(self, user_id: str) -> bool: params = quote( string=json.dumps( obj={ - "target_posts_author_id": user_id, - "container_module": "ig_text_feed_timeline", + "target_posts_author_id": user_id, + "container_module": "ig_text_feed_timeline", }, - ), - safe="!~*'()" - ) + ), + safe="!~*'()", + ) response = self.http_client.post( - url=f'{BASE_API_URL}/api/v1/friendships/unmute_posts_or_story_from_follow/', + url=f"{BASE_API_URL}/api/v1/friendships/unmute_posts_or_story_from_follow/", headers=self.__get_app_headers(), - data=f'signed_body=SIGNATURE.{params}', + data=f"signed_body=SIGNATURE.{params}", ) if self.verbose: print("[UNMUTE]", response.json()) return response.json()["status"] == "ok" + def friendship_status(self, user_id: str) -> dict | int: + """ + Checks Friendship_status with other users. + + Arguments: + user_id (str): target user identifier + + Returns: + dict(friendship_status) or int(response.status_code) + """ + response = self.http_client.get( + url=f"{BASE_API_URL}/api/v1/friendships/show/{user_id}/", + headers=self.__get_app_headers(), + ) + if response.status_code == 200: + return response.json() + else: + return response.status_code + def get_token(self) -> str: """ set fb login token From 17aa8d3673624054cdc252f9e44e2462e5dd22fd Mon Sep 17 00:00:00 2001 From: DrunkLeen Date: Sun, 16 Jul 2023 14:47:03 +0200 Subject: [PATCH 11/12] README.md updated --- README.md | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 823439c..5279460 100644 --- a/README.md +++ b/README.md @@ -105,7 +105,7 @@ search_parameter = "DrunkLeen" api.search(search_parameter) ``` -#### ✨ Like/Unlike a Thread (from v0.0.7) +#### 👍 Like/Unlike a Thread (from v0.0.7) ```python post_url = 'https://www.threads.net/t/CugF-EjhQ3r' @@ -116,7 +116,7 @@ api.like(postIDToLike) api.unlike(postIDToLike) ``` -#### ✨ Follow/Unfollow a User +#### 👉 Follow/Unfollow a User ```python user_id = api.get_user_id_from_username('junhoyeo') @@ -156,6 +156,16 @@ api.restrict(user_id) api.unrestrict(user_id) ``` +#### 🧑‍đŸĻŗ Check FriendshipStatus with a User + +```python +user_id = api.get_user_id_from_username('junhoyeo') + +# 💡 Uses current credentials +api.friendship_status(user_id) +``` + + ## [](https://github.com/junhoyeo) Roadmap - [x] ✅ Read public data @@ -175,17 +185,24 @@ api.unrestrict(user_id) - [ ] 🚧 Threads Tool for LangChain - [ ] 📌 Link Threads & LLaMa ([@Mineru98](https://github.com/Mineru98)) - [ ] 📌 Provide statistical analysis of posts in Threads ([@Mineru98](https://github.com/Mineru98)) -- [x] ✅ Write data (i.e. write automated Threads) - - [x] ✅ Create new Thread with text - - [x] ✅ Make link previews to get shown - - [x] ✅ Create new Thread with media +- [ ] 🚧 Write data (i.e. write automated Threads) + - [ ] 🚧 Create new Thread with text + - [ ] 🚧 Make link previews to get shown + - [ ] 🚧 Create new Thread with media - [ ] 🚧 Create new Thread with multiple images - - [x] ✅ Reply to existing Thread + - [ ] 🚧 Reply to existing Thread - [ ] 🚧 Quote Thread - [ ] 🚧 Delete Thread - [x] ✅ Friendships - [x] ✅ Follow User - [x] ✅ Unfollow User + - [x] ✅ Block User + - [x] ✅ Unblock User + - [x] ✅ Mute User + - [x] ✅ Unmute User + - [x] ✅ Restrict User + - [x] ✅ Unrestrict User + - [x] ✅ Check FriendshipStatus with a User - [x] ✅ Interactions - [x] ✅ Like Thread - [x] ✅ Unlike Thread From d523a1173d59de9b55c22c788caa1b109679672e Mon Sep 17 00:00:00 2001 From: DrunkLeen Date: Sun, 16 Jul 2023 15:58:42 +0200 Subject: [PATCH 12/12] Update threadspy/threads_api.py Co-authored-by: Junho Yeo --- threadspy/threads_api.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/threadspy/threads_api.py b/threadspy/threads_api.py index a2280ad..930da2e 100644 --- a/threadspy/threads_api.py +++ b/threadspy/threads_api.py @@ -506,9 +506,10 @@ def like(self, post_id: str) -> bool: response = self.__toggle_auth__post_request( url=f"{BASE_API_URL}/api/v1/media/{post_id}_{user_id}/like/", ) + data = response.json() if self.verbose: - print("[LIKE]", response.json()) - return response.json()["status"] == "ok" + print("[LIKE]", data) + return data["status"] == "ok" def unlike(self, post_id: str) -> bool: """