From ea29bd47cfad93212e0d45aedf6d2d612f34d95f Mon Sep 17 00:00:00 2001 From: Harold Kim Date: Wed, 23 Jun 2021 14:01:19 +0900 Subject: [PATCH] Update version with more implementations --- .gitignore | 1 + cli.py | 7 +-- clubhouse/clubhouse.py | 108 ++++++++++++++++++++++------------------- setup.py | 4 +- 4 files changed, 64 insertions(+), 56 deletions(-) diff --git a/.gitignore b/.gitignore index a77a0ea..6f0c31f 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ *.pyc *.ini *.spec +*.dmp __pycache__/ .DS_Store Thumbs.db diff --git a/cli.py b/cli.py index c941fd9..3b96399 100644 --- a/cli.py +++ b/cli.py @@ -135,16 +135,17 @@ def print_channel_list(client, max_limit=20): Print list of channels """ - # Get channels and print out + # Get channels and print console = Console() table = Table(show_header=True, header_style="bold magenta") table.add_column("") table.add_column("channel_name", style="cyan", justify="right") table.add_column("topic") table.add_column("speaker_count") - channels = client.get_channels()['channels'] + channels = client.get_feed()['items'] # ['channel'] i = 0 for channel in channels: + channel = channel['channel'] i += 1 if i > max_limit: break @@ -240,8 +241,8 @@ def _wait_speaker_permission(client, channel_name, user_id): break table.add_row( str(user['user_id']), + "@" + str(user['username']), str(user['name']), - str(user['username']), str(user['is_speaker']), str(user['is_moderator']), ) diff --git a/clubhouse/clubhouse.py b/clubhouse/clubhouse.py index 4a39928..aac854e 100644 --- a/clubhouse/clubhouse.py +++ b/clubhouse/clubhouse.py @@ -32,14 +32,15 @@ class Clubhouse: # App/API Information API_URL = "https://www.clubhouseapi.com/api" - API_BUILD_ID = "304" - API_BUILD_VERSION = "0.1.28" + API_BUILD_ID = "434" + API_BUILD_VERSION = "0.1.40" API_UA = f"clubhouse/{API_BUILD_ID} (iPhone; iOS 14.4; Scale/2.00)" API_UA_STATIC = f"Clubhouse/{API_BUILD_ID} CFNetwork/1220.1 Darwin/20.3.0" # Some useful information for commmunication PUBNUB_PUB_KEY = "pub-c-6878d382-5ae6-4494-9099-f930f938868b" PUBNUB_SUB_KEY = "sub-c-a4abea84-9ca3-11ea-8e71-f2b83ac9263d" + PUBNUB_API_URL = "https://clubhouse.pubnubapi.com/v2" TWITTER_ID = "NyJhARWVYU1X3qJZtC2154xSI" TWITTER_SECRET = "ylFImLBFaOE362uwr4jut8S8gXGWh93S1TUKbkfh7jDIPse02o" @@ -340,13 +341,16 @@ def update_follow_notifications(self, user_id, notification_type=2): return req.json() @require_authentication - def get_suggested_follows_similar(self, user_id): - """ (Clubhouse, int) -> dict + def get_suggested_follows_similar(self, user_id='', username=''): + """ (Clubhouse, str, str) -> dict Get similar users based on the given user. """ data = { - "user_id": int(user_id), + "user_id": int(user_id) if user_id else None, + "username": username if username else None, + "query_id": None, + "query_result_position": None, } req = requests.post(f"{self.API_URL}/get_suggested_follows_similar", headers=self.HEADERS, json=data) return req.json() @@ -491,7 +495,10 @@ def get_club(self, club_id, source_topic_id=None): """ data = { "club_id": int(club_id), - "source_topic_id": source_topic_id + "source_topic_id": source_topic_id, + "query_id": None, + "query_result_position": None, + "slug": None, } req = requests.post(f"{self.API_URL}/get_club", headers=self.HEADERS, json=data) return req.json() @@ -554,6 +561,7 @@ def join_channel(self, channel, attribution_source="feed", attribution_details=" "channel": channel, "attribution_source": attribution_source, "attribution_details": attribution_details, # base64_json + # logging_context (json of some details) } req = requests.post(f"{self.API_URL}/join_channel", headers=self.HEADERS, json=data) return req.json() @@ -565,8 +573,7 @@ def leave_channel(self, channel): Leave the given channel """ data = { - "channel": channel, - "channel_id": None + "channel": channel } req = requests.post(f"{self.API_URL}/leave_channel", headers=self.HEADERS, json=data) return req.json() @@ -639,13 +646,16 @@ def block_from_channel(self, channel, user_id): return req.json() @require_authentication - def get_profile(self, user_id): - """ (Clubhouse, str) -> dict + def get_profile(self, user_id='', username=''): + """ (Clubhouse, str, str) -> dict Lookup someone else's profile. It is OK to one's own profile with this method. """ data = { - "user_id": int(user_id) + "query_id": None, + "query_result_position": 0, + "user_id": int(user_id) if user_id else None, + "username": username if username else None } req = requests.post(f"{self.API_URL}/get_profile", headers=self.HEADERS, json=data) return req.json() @@ -715,6 +725,15 @@ def get_all_topics(self): req = requests.get(f"{self.API_URL}/get_all_topics", headers=self.HEADERS) return req.json() + @require_authentication + def get_feed(self): + """ (Clubhouse) -> dict + + Get list of channels, current invite status, etc. + """ + req = requests.get(f"{self.API_URL}/get_feed?", headers=self.HEADERS) + return req.json() + @require_authentication def get_channels(self): """ (Clubhouse) -> dict @@ -1341,7 +1360,6 @@ def cancel_new_channel_invite(self, channel_invite_id): req = requests.post(f"{self.API_URL}/cancel_new_channel_invite", headers=self.HEADERS, json=data) return req.json() - @unstable_endpoint @require_authentication def add_club_admin(self, club_id, user_id): """ (Clubhouse, int, int) -> dict @@ -1355,7 +1373,6 @@ def add_club_admin(self, club_id, user_id): req = requests.post(f"{self.API_URL}/add_club_admin", headers=self.HEADERS, json=data) return req.json() - @unstable_endpoint @require_authentication def remove_club_admin(self, club_id, user_id): """ (Clubhouse, int, int) -> dict @@ -1369,7 +1386,6 @@ def remove_club_admin(self, club_id, user_id): req = requests.post(f"{self.API_URL}/remove_club_admin", headers=self.HEADERS, json=data) return req.json() - @unstable_endpoint @require_authentication def remove_club_member(self, club_id, user_id): """ (Clubhouse, int, int) -> dict @@ -1383,21 +1399,23 @@ def remove_club_member(self, club_id, user_id): req = requests.post(f"{self.API_URL}/remove_club_member", headers=self.HEADERS, json=data) return req.json() - @unstable_endpoint @require_authentication - def accept_club_member_invite(self, club_id, source_topic_id=None): - """ (Clubhouse, int, int) -> dict + def accept_club_member_invite(self, club_id, source_topic_id=None, invite_code=None): + """ (Clubhouse, int, int, str) -> dict Accept Club member invite. """ data = { "club_id": int(club_id) if club_id else None, + "invite_code": invite_code, + "query_id": None, + "query_result_position": None, + "slug": None, "source_topic_id": source_topic_id } req = requests.post(f"{self.API_URL}/accept_club_member_invite", headers=self.HEADERS, json=data) return req.json() - @unstable_endpoint @require_authentication def add_club_member(self, club_id, user_id, name, phone_number, message, reason): """ (Clubhouse, int, int, str, str, str, unknown) -> dict @@ -1415,7 +1433,6 @@ def add_club_member(self, club_id, user_id, name, phone_number, message, reason) req = requests.post(f"{self.API_URL}/add_club_member", headers=self.HEADERS, json=data) return req.json() - @unstable_endpoint @require_authentication def get_club_nominations(self, club_id, source_topic_id): """ (Club, int, int) -> dict @@ -1429,7 +1446,6 @@ def get_club_nominations(self, club_id, source_topic_id): req = requests.post(f"{self.API_URL}/get_club_nominations", headers=self.HEADERS, json=data) return req.json() - @unstable_endpoint @require_authentication def approve_club_nomination(self, club_id, source_topic_id, invite_nomination_id): """ (Club, int, int) -> dict @@ -1444,7 +1460,6 @@ def approve_club_nomination(self, club_id, source_topic_id, invite_nomination_id req = requests.post(f"{self.API_URL}/approve_club_nomination", headers=self.HEADERS, json=data) return req.json() - @unstable_endpoint @require_authentication def reject_club_nomination(self, club_id, source_topic_id, invite_nomination_id): """ (Club, int, int) -> dict @@ -1459,7 +1474,6 @@ def reject_club_nomination(self, club_id, source_topic_id, invite_nomination_id) req = requests.post(f"{self.API_URL}/approve_club_nomination", headers=self.HEADERS, json=data) return req.json() - @unstable_endpoint @require_authentication def add_club_topic(self, club_id, topic_id): """ (Club, int, int) -> dict @@ -1473,7 +1487,6 @@ def add_club_topic(self, club_id, topic_id): req = requests.post(f"{self.API_URL}/add_club_topic", headers=self.HEADERS, json=data) return req.json() - @unstable_endpoint @require_authentication def remove_club_topic(self, club_id, topic_id): """ (Club, int, int) -> dict @@ -1487,7 +1500,6 @@ def remove_club_topic(self, club_id, topic_id): req = requests.post(f"{self.API_URL}/remove_club_topic", headers=self.HEADERS, json=data) return req.json() - @unstable_endpoint @require_authentication def get_events_to_start(self): """ (Clubhouse) -> dict @@ -1497,7 +1509,6 @@ def get_events_to_start(self): req = requests.get(f"{self.API_URL}/get_events_to_start", headers=self.HEADERS) return req.json() - @unstable_endpoint @require_authentication def update_is_follow_allowed(self, club_id, is_follow_allowed=True): """ (Clubhouse, int, bool) -> dict @@ -1511,12 +1522,12 @@ def update_is_follow_allowed(self, club_id, is_follow_allowed=True): req = requests.post(f"{self.API_URL}/update_is_follow_allowed", headers=self.HEADERS, json=data) return req.json() - @unstable_endpoint @require_authentication - def update_is_membership_private(self, club_id, is_membership_private): + def update_is_membership_private(self, club_id, is_membership_private=False): """ (Clubhouse, int, bool) -> dict - Update membership status of the given Club + Update club membership status of the given Club + If True, member list will not be shown to public. """ data = { "club_id": int(club_id), @@ -1525,12 +1536,11 @@ def update_is_membership_private(self, club_id, is_membership_private): req = requests.post(f"{self.API_URL}/update_is_membership_private", headers=self.HEADERS, json=data) return req.json() - @unstable_endpoint @require_authentication - def update_is_community(self, club_id, is_community): + def update_is_community(self, club_id, is_community=False): """ (Clubhouse, int, bool) -> dict - Update community stat of the given Club + Change room start permission. If set False, Admins can only start club rooms. """ data = { "club_id": int(club_id), @@ -1539,7 +1549,6 @@ def update_is_community(self, club_id, is_community): req = requests.post(f"{self.API_URL}/update_is_community", headers=self.HEADERS, json=data) return req.json() - @unstable_endpoint @require_authentication def update_club_description(self, club_id, description): """ (Clubhouse, int, str) -> dict @@ -1553,29 +1562,26 @@ def update_club_description(self, club_id, description): req = requests.post(f"{self.API_URL}/update_club_description", headers=self.HEADERS, json=data) return req.json() - @unstable_endpoint - @require_authentication - def update_club_rules(self): - """ (Clubhouse) -> dict - - Not implemented method - """ - raise NotImplementedError("Not Implemented!") - - @unstable_endpoint @require_authentication - def update_club_topics(self): - """ (Clubhouse) -> dict + def update_club_rules(self, club_id='', rules=None): + """ (Clubhouse, str, list) -> dict - Not implemented method + Update Club's rules (Maximum upto 3 rules) + rules: [{'desc': "text", "title": "text"}, ...] """ - raise NotImplementedError("Not Implemented!") + data = { + "club_id": int(club_id), + "rules": rules if rules else [], + } + req = requests.post(f"{self.API_URL}/update_club_rules", headers=self.HEADERS, json=data) + return req.json() - @unstable_endpoint @require_authentication - def get_events_for_user(self): - """ (Clubhouse) -> dict + def get_events_for_user(self, user_id='', page_size=25, page=1): + """ (Clubhouse, str, int, int) -> dict - Not implemented method + Get events for the specific user. """ - raise NotImplementedError("Not Implemented!") + query = f"user_id={user_id}&page_size={page_size}&page={page}" + req = requests.get(f"{self.API_URL}/get_events_for_user?{query}", headers=self.HEADERS) + return req.json() diff --git a/setup.py b/setup.py index 351a138..1219948 100644 --- a/setup.py +++ b/setup.py @@ -16,7 +16,7 @@ def _requires_from_file(filename): setup( name="clubhouse-py", packages=["clubhouse"], - version="304.0.1", + version="434", license="MIT", description=("Clubhouse API written in Python. Standalone client included." + "For reference and education purposes only."), @@ -25,7 +25,7 @@ def _requires_from_file(filename): long_description=long_description, long_description_content_type="text/markdown", url="https://github.com/stypr/clubhouse-py", - download_url="https://github.com/stypr/clubhouse-py/archive/304.0.1.tar.gz", + download_url="https://github.com/stypr/clubhouse-py/archive/434.tar.gz", keywords=[ "clubhouse", "voice-chat",